LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Problem with PCI bus rescan on 460EX
From: Felix Radensky @ 2010-03-17  7:38 UTC (permalink / raw)
  To: Kenji Kaneshige; +Cc: linux-pci, yinghai, Alex Chiang, linuxppc-dev@ozlabs.org
In-Reply-To: <4BA02A49.9050101@jp.fujitsu.com>

Hello Kenj-san

Kenji Kaneshige wrote:
>
>
> By the way, I think Yinghai's bridge resource reallocation patch series
> might help you. It is in Jesse's PCI tree. Please take a look.
>
>
I've tried Jesse's tree on my custom board and on 460EX evaluation board
(Canyonlands). In both cases the kernel doesn't boot unless PCI support is
disabled.  Debugging is difficult as the board just resets before 
anything is
is printed on console.

Felix.

^ permalink raw reply

* Re: [PATCH 2/4] 8xx: Avoid testing for kernel space in ITLB Miss.
From: Joakim Tjernlund @ 2010-03-17  7:35 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1268774376.2335.130.camel@pasglop>

Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote on 2010/03/16 22:19:36:
>
> On Fri, 2010-02-26 at 09:29 +0100, Joakim Tjernlund wrote:
> > +#ifdef CONFIG_MODULES
> > +       /* Only modules will cause ITLB Misses as we always
> > +        * pin the first 8MB of kernel memory */
> >         andi.   r11, r10, 0x0800        /* Address >= 0x80000000 */
> >         beq     3f
> >         lis     r11, swapper_pg_dir@h
> >         ori     r11, r11, swapper_pg_dir@l
> >         rlwimi  r10, r11, 0, 2, 19
> >  3:
> > +#endif
>
> You can optimize that further I think...
>
> You can probably just remove the code above, and add something to
> do_page_fault() that lazily copies the kernel PGD entries from
> swapper_pg_dir to the app pgdir. (You can even pre-fill that when
> creating a new mm).

I did look at this at some point and could not figure out how
to do this.

^ permalink raw reply

* Re: [PATCH] powerpc: fix swiotlb to respect the boot option
From: Albert Herranz @ 2010-03-17  6:03 UTC (permalink / raw)
  To: FUJITA Tomonori; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20100317081540C.fujita.tomonori@lab.ntt.co.jp>

FUJITA Tomonori wrote:
> powerpc initializes swiotlb before parsing the kernel boot options so
> swiotlb options (e.g. specifying the swiotlb buffer size) are ignored.
> 
> Any time before freeing bootmem works for swiotlb so this patch moves
> powerpc's swiotlb initialization after parsing the kernel boot
> options, mem_init (as x86 does).
> 
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> Tested-by: Becky Bruce <beckyb@kernel.crashing.org>

Thanks!

Tested-by: Albert Herranz <albert_herranz@yahoo.es>

> ---
>  arch/powerpc/kernel/setup_32.c |    6 ------
>  arch/powerpc/kernel/setup_64.c |    6 ------
>  arch/powerpc/mm/mem.c          |    6 ++++++
>  3 files changed, 6 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
> index b152de3..8f58986 100644
> --- a/arch/powerpc/kernel/setup_32.c
> +++ b/arch/powerpc/kernel/setup_32.c
> @@ -39,7 +39,6 @@
>  #include <asm/serial.h>
>  #include <asm/udbg.h>
>  #include <asm/mmu_context.h>
> -#include <asm/swiotlb.h>
>  
>  #include "setup.h"
>  
> @@ -343,11 +342,6 @@ void __init setup_arch(char **cmdline_p)
>  		ppc_md.setup_arch();
>  	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
>  
> -#ifdef CONFIG_SWIOTLB
> -	if (ppc_swiotlb_enable)
> -		swiotlb_init(1);
> -#endif
> -
>  	paging_init();
>  
>  	/* Initialize the MMU context management stuff */
> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
> index 6354739..9143891 100644
> --- a/arch/powerpc/kernel/setup_64.c
> +++ b/arch/powerpc/kernel/setup_64.c
> @@ -61,7 +61,6 @@
>  #include <asm/xmon.h>
>  #include <asm/udbg.h>
>  #include <asm/kexec.h>
> -#include <asm/swiotlb.h>
>  #include <asm/mmu_context.h>
>  
>  #include "setup.h"
> @@ -541,11 +540,6 @@ void __init setup_arch(char **cmdline_p)
>  	if (ppc_md.setup_arch)
>  		ppc_md.setup_arch();
>  
> -#ifdef CONFIG_SWIOTLB
> -	if (ppc_swiotlb_enable)
> -		swiotlb_init(1);
> -#endif
> -
>  	paging_init();
>  
>  	/* Initialize the MMU context management stuff */
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 311224c..448f972 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -48,6 +48,7 @@
>  #include <asm/sparsemem.h>
>  #include <asm/vdso.h>
>  #include <asm/fixmap.h>
> +#include <asm/swiotlb.h>
>  
>  #include "mmu_decl.h"
>  
> @@ -320,6 +321,11 @@ void __init mem_init(void)
>  	struct page *page;
>  	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
>  
> +#ifdef CONFIG_SWIOTLB
> +	if (ppc_swiotlb_enable)
> +		swiotlb_init(1);
> +#endif
> +
>  	num_physpages = lmb.memory.size >> PAGE_SHIFT;
>  	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
>  

^ permalink raw reply

* RE: [PATCH] 460EX on-chip SATA driver<kernel 2.6.33> < resubmission : 01>
From: Rupjyoti Sarmah @ 2010-03-17  5:55 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: Rupjyoti Sarmah, linux-ide, Jeff Garzik, linux-kernel,
	linuxppc-dev
In-Reply-To: <20100317155959.208eea21.sfr@canb.auug.org.au>

Hi Stephen,

Thanks for your suggestions.=20
I used git-send-email earlier and emails never appeared in the archive.
This time I sent through outlook & the message appeared in the archive.
Looks like outlook did that word wrap.

I am not sure why the emails from the git-send-email did not get
delivered. At the time of sending I got message delivered  logs.

Regards,
Rupjyoti Sarmah




-----Original Message-----
From: Stephen Rothwell [mailto:sfr@canb.auug.org.au]=20
Sent: Wednesday, March 17, 2010 10:30 AM
To: Rupjyoti Sarmah
Cc: linux-ide@vger.kernel.org; Jeff Garzik; Rupjyoti Sarmah;
linuxppc-dev@ozlabs.org; Rupjyoti Sarmah; linux-kernel@vger.kernel.org
Subject: Re: [PATCH] 460EX on-chip SATA driver<kernel 2.6.33> <
resubmission : 01>

Hi,

Just a couple of quick points ...

On Tue, 16 Mar 2010 21:23:16 -0700 "Rupjyoti Sarmah" <rsarmah@amcc.com>
wrote:
>
> This patch enables the on-chip DWC SATA controller of the AppliedMicro

> processor 460EX.
>=20
> Signed-off-by: Rupjyoti Sarmah <rsarmah@appliedmicro.com> ,Mark=20
> Miesfeld <mmiesfeld@appliedmicro.com>, Prodyut Hazarika=20
> <phazarika@appliedmicro.com>

Please put one Signed-off-by line per person.

> ---
>  arch/powerpc/boot/dts/canyonlands.dts |    8 +
>  drivers/ata/Kconfig                   |    9 +
>  drivers/ata/Makefile                  |    1 +
>  drivers/ata/sata_dwc.c                | 1965
> +++++++++++++++++++++++++++++++++
>  4 files changed, 1983 insertions(+), 0 deletions(-)  create mode=20
> 100644 drivers/ata/sata_dwc.c

This patch has been word wrapped by your mailer (or something along the
way).
--
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

^ permalink raw reply

* [git pull] Please pull powerpc.git merge branch (fwd)
From: Kumar Gala @ 2010-03-17  5:52 UTC (permalink / raw)
  To: linuxppc-dev

forgot to cc the list

---------- Forwarded message ----------
Date: Wed, 17 Mar 2010 00:13:00 -0500 (CDT)
From: Kumar Gala <galak@kernel.crashing.org>
To: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Subject: [git pull] Please pull powerpc.git merge branch

The following changes since commit 30124d11097e371e42052144d8a3f4a78d26e09f:
  Dave Kleikamp (1):
        powerpc/booke: Fix breakpoint/watchpoint one-shot behavior

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git merge

Kumar Gala (2):
      powerpc/85xx: Make sure lwarx hint isn't set on ppc32
      powerpc/fsl-booke: Get coherent bit from PTE

 arch/powerpc/include/asm/ppc-opcode.h |    6 +++---
 arch/powerpc/kernel/head_fsl_booke.S  |    3 ---
 2 files changed, 3 insertions(+), 6 deletions(-)

^ permalink raw reply

* Failing to get DMA working with MPC5200 (TQM5200) and CompactFlash
From: Josh Triplett @ 2010-03-17  5:17 UTC (permalink / raw)
  To: linuxppc-dev

Hello,

We've tried both 2.6.33 and DENX-v2.6.33.1, and we haven't managed to
successfully use any form of DMA with the TQM5200 and a CompactFlash
card.  We know the CF card supports DMA (or, at least, it says "UDMA"
right on the card, and various reports say Lexar Professional CF cards
do DMA), but the kernel always puts the card in PIO4 mode.  We tried
libata.force=mwdma2 and libata.force=udma2 , and many other modes, but
this always led to failures like this:

[   31.994311] ata1: lost interrupt (Status 0x58)
[   32.020435] ata1.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[   32.027712] ata1.00: failed command: READ DMA
[   32.032236] ata1.00: cmd c8/00:08:00:00:00/00:00:00:00:00/e0 tag 0 dma 4096 in
[   32.032249]          res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
[   32.047212] ata1.00: status: { DRDY }
[   32.051050] ata1: soft resetting link
[   32.218796] ata1.00: FORCE: xfer_mask set to udma2
[   32.230618] ata1.00: configured for UDMA/33
[   32.235000] ata1.00: device reported invalid CHS sector 0
[   32.240629] ata1: EH complete
[   62.994310] ata1: lost interrupt (Status 0x58)
[   63.020443] ata1.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[   63.027722] ata1.00: failed command: READ DMA
[   63.032246] ata1.00: cmd c8/00:08:00:00:00/00:00:00:00:00/e0 tag 0 dma 4096 in
[   63.032259]          res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
[   63.047221] ata1.00: status: { DRDY }
[   63.051060] ata1: soft resetting link
[   63.218778] ata1.00: FORCE: xfer_mask set to udma2
[   63.238603] ata1.00: configured for UDMA/33
[   63.242978] ata1.00: device reported invalid CHS sector 0
[   63.248609] ata1: EH complete

We have the MPC5200C revision of the silicon.

Does this sound like a known issue?  Can we do anything to troubleshoot
this further?

Thanks,
Josh Triplett and Jamey Sharp
Portland State Aerospace Society

^ permalink raw reply

* Re: [PATCH] 460EX on-chip SATA driver<kernel 2.6.33> < resubmission : 01>
From: Stephen Rothwell @ 2010-03-17  4:59 UTC (permalink / raw)
  To: Rupjyoti Sarmah
  Cc: Rupjyoti Sarmah, linuxppc-dev, linux-kernel, linux-ide,
	Rupjyoti Sarmah, Jeff Garzik
In-Reply-To: <AC311A8E81420D4EBC1F26E6479848FE065B7F30@SDCEXCHANGE01.ad.amcc.com>

[-- Attachment #1: Type: text/plain, Size: 971 bytes --]

Hi,

Just a couple of quick points ...

On Tue, 16 Mar 2010 21:23:16 -0700 "Rupjyoti Sarmah" <rsarmah@amcc.com> wrote:
>
> This patch enables the on-chip DWC SATA controller of the AppliedMicro
> processor 460EX.
> 
> Signed-off-by: Rupjyoti Sarmah <rsarmah@appliedmicro.com> ,Mark Miesfeld
> <mmiesfeld@appliedmicro.com>,
> Prodyut Hazarika <phazarika@appliedmicro.com>

Please put one Signed-off-by line per person.

> ---
>  arch/powerpc/boot/dts/canyonlands.dts |    8 +
>  drivers/ata/Kconfig                   |    9 +
>  drivers/ata/Makefile                  |    1 +
>  drivers/ata/sata_dwc.c                | 1965
> +++++++++++++++++++++++++++++++++
>  4 files changed, 1983 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/ata/sata_dwc.c

This patch has been word wrapped by your mailer (or something along the
way).
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* [PATCH] powerpc/fsl-booke: Get coherent bit from PTE
From: Kumar Gala @ 2010-03-17  4:41 UTC (permalink / raw)
  To: linuxppc-dev

We shouldn't be always setting 'M' in the TLB entry since its reasonable
for somethings to be mapped non-coherent.  The PTE should have 'M' set
properly.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/kernel/head_fsl_booke.S |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 25793bb..a7cf493 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -747,9 +747,6 @@ finish_tlb_load:
 #else
 	rlwimi	r12, r11, 26, 27, 31	/* extract WIMGE from pte */
 #endif
-#ifdef CONFIG_SMP
-	ori	r12, r12, MAS2_M
-#endif
 	mtspr	SPRN_MAS2, r12
 
 #ifdef CONFIG_PTE_64BIT
-- 
1.6.0.6

^ permalink raw reply related

* [PATCH] 460EX on-chip SATA driver<kernel 2.6.33> < resubmission : 01>
From: Rupjyoti Sarmah @ 2010-03-17  4:23 UTC (permalink / raw)
  To: linux-ide, Jeff Garzik
  Cc: Rupjyoti Sarmah, linuxppc-dev, Rupjyoti Sarmah, linux-kernel
In-Reply-To: <1268646854-27387-1-git-send-email-rsarmah@appliedmicro.com>

This patch enables the on-chip DWC SATA controller of the AppliedMicro
processor 460EX.

Signed-off-by: Rupjyoti Sarmah <rsarmah@appliedmicro.com> ,Mark Miesfeld
<mmiesfeld@appliedmicro.com>,
Prodyut Hazarika <phazarika@appliedmicro.com>
---
 arch/powerpc/boot/dts/canyonlands.dts |    8 +
 drivers/ata/Kconfig                   |    9 +
 drivers/ata/Makefile                  |    1 +
 drivers/ata/sata_dwc.c                | 1965
+++++++++++++++++++++++++++++++++
 4 files changed, 1983 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ata/sata_dwc.c

diff --git a/arch/powerpc/boot/dts/canyonlands.dts
b/arch/powerpc/boot/dts/canyonlands.dts
index cd56bb5..d3b2c99 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -163,6 +163,14 @@
 			interrupts =3D <0x1e 4>;
 		};
=20
+		SATA0: sata@bffd1000 {
+                        compatible =3D "amcc,sata-460ex";
+			reg =3D <4 0xbffd1000 0x800 4 0xbffd0800 0x400>;
+                        interrupt-parent =3D <&UIC3>;
+                        interrupts =3D <0x0 0x4       /* SATA */
+                                      0x5 0x4>;     /* AHBDMA */
+                };
+
 		POB0: opb {
 			compatible =3D "ibm,opb-460ex", "ibm,opb";
 			#address-cells =3D <1>;
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 56c6374..bba7b8a 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -82,6 +82,15 @@ config SATA_FSL
=20
 	  If unsure, say N.
=20
+config SATA_DWC
+	tristate "DesignWare Cores SATA support"
+	depends on 460EX
+	help
+	  This option enables support for the on-chip SATA controller of
the
+	  AppliedMicro processor 460EX.
+
+	  If unsure, say N.
+
 config ATA_SFF
 	bool "ATA SFF support"
 	default y
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index fc936d4..0de7a33 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SATA_INIC162X)	+=3D sata_inic162x.o
 obj-$(CONFIG_PDC_ADMA)		+=3D pdc_adma.o
 obj-$(CONFIG_SATA_FSL)		+=3D sata_fsl.o
 obj-$(CONFIG_PATA_MACIO)	+=3D pata_macio.o
+obj-$(CONFIG_SATA_DWC)		+=3D sata_dwc.o
=20
 obj-$(CONFIG_PATA_ALI)		+=3D pata_ali.o
 obj-$(CONFIG_PATA_AMD)		+=3D pata_amd.o
diff --git a/drivers/ata/sata_dwc.c b/drivers/ata/sata_dwc.c
new file mode 100644
index 0000000..28c227e
--- /dev/null
+++ b/drivers/ata/sata_dwc.c
@@ -0,0 +1,1965 @@
+/*
+ * drivers/ata/sata_dwc.c
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@appliedmicro.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ *          Copyright 2006 Applied Micro Circuits Corporation
+ *          COPYRIGHT (C) 2005  SYNOPSYS, INC.  ALL RIGHTS RESERVED
+ *
+ * This program is free software; you can redistribute  it and/or
modify it
+ * under  the terms of  the GNU General  Public License as published by
the
+ * Free Software Foundation;  either version 2 of the  License, or (at
your
+ * option) any later version.
+ *
+ */
+
+#ifdef CONFIG_SATA_DWC_DEBUG
+#define DEBUG
+#endif
+
+#ifdef CONFIG_SATA_DWC_VDEBUG
+#define VERBOSE_DEBUG
+#define DEBUG_NCQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/libata.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+
+#define DRV_NAME        "sata-dwc"
+#define DRV_VERSION     "1.0"
+
+/* SATA DMA driver Globals */
+#define DMA_NUM_CHANS			1
+#define DMA_NUM_CHAN_REGS		8
+
+/* SATA DMA Register definitions */
+#define AHB_DMA_BRST_DFLT		64 /* 16 data items burst length
*/
+
+struct dmareg {
+	u32 low;		/* Low bits 0-31 */
+	u32 high;		/* High bits 32-63 */
+};
+
+/* DMA Per Channel registers */
+
+struct dma_chan_regs {
+	struct dmareg sar;	/* Source Address */
+	struct dmareg dar;	/* Destination address */
+	struct dmareg llp;	/* Linked List Pointer */
+	struct dmareg ctl;	/* Control */
+	struct dmareg sstat;	/* Source Status not implemented in core
*/
+	struct dmareg dstat;	/* DestinationStatus not implemented in
core */
+	struct dmareg sstatar;	/* Source Status Address not impl in
core */
+	struct dmareg dstatar;	/* DestinationStatus Address not
implemented */
+	struct dmareg cfg;	/* Config */
+	struct dmareg sgr;	/* Source Gather */
+	struct dmareg dsr;	/* Destination Scatter */
+};
+
+/* Generic Interrupt Registers */
+struct dma_interrupt_regs {
+	struct dmareg tfr;	/* Transfer Interrupt */
+	struct dmareg block;	/* Block Interrupt */
+	struct dmareg srctran;	/* Source Transfer Interrupt */
+	struct dmareg dsttran;	/* Dest Transfer Interrupt */
+	struct dmareg error;	/* Error */
+};
+
+struct ahb_dma_regs {
+	struct dma_chan_regs	chan_regs[DMA_NUM_CHAN_REGS];/* channel
reg */
+	struct dma_interrupt_regs interrupt_raw;	/* Raw Interrupt
*/
+	struct dma_interrupt_regs interrupt_status;	/* Interrupt
Status */
+	struct dma_interrupt_regs interrupt_mask;	/* Interrupt
Mask */
+	struct dma_interrupt_regs interrupt_clear;	/* Interrupt
Clear */
+	struct dmareg		statusInt;		/* Interrupt
combined */
+	struct dmareg		rq_srcreg;		/* Src Trans Req
*/
+	struct dmareg		rq_dstreg;		/* Dst Trans Req
*/
+	struct dmareg		rq_sgl_srcreg;		/* Sngl Src
Trans Req */
+	struct dmareg		rq_sgl_dstreg;		/* Sngl Dst
Trans Req */
+	struct dmareg		rq_lst_srcreg;		/* Last Src
Trans Req */
+	struct dmareg		rq_lst_dstreg;		/* Last Dst
Trans Req */
+	struct dmareg		dma_cfg;		/* DMA Config */
+	struct dmareg		dma_chan_en;		/* DMA Channel
Enable */
+	struct dmareg		dma_id;			/* DMA ID */
+	struct dmareg		dma_test;		/* DMA Test */
+	struct dmareg		res1;			/* reserved */
+	struct dmareg		res2;			/* reserved */
+
+	/* DMA Comp Params
+	 * Param 6 =3D dma_param[0], Param 5 =3D dma_param[1],
+	 * Param 4 =3D dma_param[2] ...
+	 */
+	struct dmareg		dma_params[6];
+};
+
+/* Data structure for linked list item */
+struct lli {
+	u32		sar;		/* Source Address */
+	u32		dar;		/* Destination address */
+	u32		llp;		/* Linked List Pointer */
+	struct dmareg	ctl;		/* Control */
+	struct dmareg	dstat;		/* Destination Status */
+};
+
+enum {
+	SATA_DWC_DMAC_LLI_SZ =3D	(sizeof(struct lli)),
+	SATA_DWC_DMAC_LLI_NUM =3D	256,
+	SATA_DWC_DMAC_LLI_TBL_SZ =3D (SATA_DWC_DMAC_LLI_SZ * \
+					SATA_DWC_DMAC_LLI_NUM),
+	SATA_DWC_DMAC_TWIDTH_BYTES =3D 4,
+	SATA_DWC_DMAC_CTRL_TSIZE_MAX =3D (0x00000800 * \
+
SATA_DWC_DMAC_TWIDTH_BYTES),
+};
+
+/* DMA Register Operation Bits */
+
+enum {
+	DMA_EN	=3D		0x00000001, /* Enable AHB DMA */
+	/* Control Register */
+
+	DMA_CTL_LLP_SRCEN =3D	0x10000000, /* Blk chain enable Src */
+	DMA_CTL_LLP_DSTEN =3D	0x08000000, /* Blk chain enable Dst */
+};
+
+#define	DMA_CTL_BLK_TS(size)	((size) & 0x000000FFF)	/* Blk
Transfer size */
+#define DMA_CHANNEL(ch) 	(0x00000001 << (ch))	/* Select
channel */
+	/* Enable channel */
+#define	DMA_ENABLE_CHAN(ch)	((0x00000001 << (ch)) |
\
+				 ((0x000000001 << (ch)) << 8))
+	/* Disable channel */
+#define	DMA_DISABLE_CHAN(ch)	(0x00000000 | ((0x000000001 <<
(ch)) << 8))
+	/* Transfer Type & Flow Controller */
+#define	DMA_CTL_TTFC(type)	(((type) & 0x7) << 20)
+#define	DMA_CTL_SMS(num)	(((num) & 0x3) << 25) /* Src
Master Select */
+#define	DMA_CTL_DMS(num)	(((num) & 0x3) << 23)/* Dst
Master Select */
+	/* Src Burst Transaction Length */
+#define DMA_CTL_SRC_MSIZE(size) (((size) & 0x7) << 14)
+	/* Dst Burst Transaction Length */
+#define	DMA_CTL_DST_MSIZE(size) (((size) & 0x7) << 11)
+	/* Source Transfer Width */
+#define	DMA_CTL_SRC_TRWID(size) (((size) & 0x7) << 4)
+	/* Destination Transfer Width */
+#define	DMA_CTL_DST_TRWID(size) (((size) & 0x7) << 1)
+
+/* Assign HW handshaking interface (x) to destination / source
peripheral */
+#define	DMA_CFG_HW_HS_DEST(int_num) (((int_num) & 0xF) << 11)
+#define	DMA_CFG_HW_HS_SRC(int_num) (((int_num) & 0xF) << 7)
+#define	DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) |
(master))
+
+/*
+ * This define is used to set block chaining disabled in the control
low
+ * register.  It is already in little endian format so it can be &'d
dirctly.
+ * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN |
DMA_CTL_LLP_DSTEN))
+ */
+enum {
+	DMA_CTL_LLP_DISABLE_LE32 =3D 0xffffffe7,
+	DMA_CTL_TTFC_P2M_DMAC =3D	0x00000002, /* Per to mem, DMAC cntr */
+	DMA_CTL_TTFC_M2P_PER =3D	0x00000003, /* Mem to per, peripheral
cntr */
+	DMA_CTL_SINC_INC =3D	0x00000000, /* Source Address Increment
*/
+	DMA_CTL_SINC_DEC =3D	0x00000200,
+	DMA_CTL_SINC_NOCHANGE =3D	0x00000400,
+	DMA_CTL_DINC_INC =3D	0x00000000, /* Destination Address
Increment */
+	DMA_CTL_DINC_DEC =3D	0x00000080,
+	DMA_CTL_DINC_NOCHANGE =3D	0x00000100,
+	DMA_CTL_INT_EN =3D	0x00000001, /* Interrupt Enable */
+
+/* Channel Configuration Register high bits */
+	DMA_CFG_FCMOD_REQ =3D	0x00000001, /* Flow Control - request
based */
+	DMA_CFG_PROTCTL	=3D	(0x00000003 << 2),/* Protection Control
*/
+
+/* Channel Configuration Register low bits */
+	DMA_CFG_RELD_DST =3D	0x80000000, /* Reload Dest / Src Addr */
+	DMA_CFG_RELD_SRC =3D	0x40000000,
+	DMA_CFG_HS_SELSRC =3D	0x00000800, /* Software handshake Src/
Dest */
+	DMA_CFG_HS_SELDST =3D	0x00000400,
+	DMA_CFG_FIFOEMPTY =3D     (0x00000001 << 9), /* FIFO Empty bit */
+
+
+/* Channel Linked List Pointer Register */
+
+	DMA_LLP_AHBMASTER1 =3D	0,	/* List Master Select */
+	DMA_LLP_AHBMASTER2 =3D	1,
+
+	SATA_DWC_MAX_PORTS =3D 1,
+
+	SATA_DWC_SCR_OFFSET =3D 0x24,
+	SATA_DWC_REG_OFFSET =3D 0x64,
+
+};
+
+/* DWC SATA Registers */
+struct sata_dwc_regs {
+	u32 fptagr;		/* 1st party DMA tag */
+	u32 fpbor;		/* 1st party DMA buffer offset */
+	u32 fptcr;		/* 1st party DMA Xfr count */
+	u32 dmacr;		/* DMA Control */
+	u32 dbtsr;		/* DMA Burst Transac size */
+	u32 intpr;		/* Interrupt Pending */
+	u32 intmr;		/* Interrupt Mask */
+	u32 errmr;		/* Error Mask */
+	u32 llcr;		/* Link Layer Control */
+	u32 phycr;		/* PHY Control */
+	u32 physr;		/* PHY Status */
+	u32 rxbistpd;		/* Recvd BIST pattern def register */
+	u32 rxbistpd1;		/* Recvd BIST data dword1 */
+	u32 rxbistpd2;		/* Recvd BIST pattern data dword2 */
+	u32 txbistpd;		/* Trans BIST pattern def register */
+	u32 txbistpd1;		/* Trans BIST data dword1 */
+	u32 txbistpd2;		/* Trans BIST data dword2 */
+	u32 bistcr;		/* BIST Control Register */
+	u32 bistfctr;		/* BIST FIS Count Register */
+	u32 bistsr;		/* BIST Status Register */
+	u32 bistdecr;		/* BIST Dword Error count register */
+	u32 res[15];		/* Reserved locations */
+	u32 testr;		/* Test Register */
+	u32 versionr;		/* Version Register */
+	u32 idr;		/* ID Register */
+	u32 unimpl[192];	/* Unimplemented */
+	u32 dmadr[256];	/* FIFO Locations in DMA Mode */
+};
+
+enum {
+	SCR_SCONTROL_DET_ENABLE	=3D	0x00000001,
+	SCR_SSTATUS_DET_PRESENT	=3D	0x00000001,
+	SCR_SERROR_DIAG_X	=3D	0x04000000,
+
+/* DWC SATA Register Operations */
+	SATA_DWC_TXFIFO_DEPTH	=3D	0x01FF,
+	SATA_DWC_RXFIFO_DEPTH	=3D	0x01FF,
+
+	SATA_DWC_DMACR_TMOD_TXCHEN =3D	0x00000004,
+	SATA_DWC_DMACR_TXCHEN	=3D (0x00000001 |
SATA_DWC_DMACR_TMOD_TXCHEN),
+	SATA_DWC_DMACR_RXCHEN	=3D (0x00000002 |
SATA_DWC_DMACR_TMOD_TXCHEN),
+
+	SATA_DWC_DMACR_TXRXCH_CLEAR =3D	SATA_DWC_DMACR_TMOD_TXCHEN,
+
+
+	SATA_DWC_INTPR_DMAT	=3D	0x00000001,
+	SATA_DWC_INTPR_NEWFP	=3D	0x00000002,
+	SATA_DWC_INTPR_PMABRT	=3D	0x00000004,
+	SATA_DWC_INTPR_ERR	=3D	0x00000008,
+	SATA_DWC_INTPR_NEWBIST	=3D	0x00000010,
+	SATA_DWC_INTPR_IPF	=3D	0x10000000,
+	SATA_DWC_INTMR_DMATM	=3D	0x00000001,
+	SATA_DWC_INTMR_NEWFPM	=3D	0x00000002,
+	SATA_DWC_INTMR_PMABRTM	=3D	0x00000004,
+	SATA_DWC_INTMR_ERRM	=3D	0x00000008,
+	SATA_DWC_INTMR_NEWBISTM	=3D	0x00000010,
+	SATA_DWC_LLCR_SCRAMEN	=3D	0x00000001,
+	SATA_DWC_LLCR_DESCRAMEN	=3D	0x00000002,
+	SATA_DWC_LLCR_RPDEN	=3D	0x00000004,
+
+/* This is all error bits, zero's are reserved fields. */
+	SATA_DWC_SERROR_ERR_BITS =3D	0x0FFF0F03
+
+};
+
+#define SATA_DWC_SCR0_SPD_GET(v)	(((v) >> 4) & 0x0000000F)
+#define SATA_DWC_DMACR_TX_CLEAR(v)	(((v) & ~SATA_DWC_DMACR_TXCHEN)
|\
+
SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RX_CLEAR(v)	(((v) & ~SATA_DWC_DMACR_RXCHEN)
|\
+
SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DBTSR_MWR(size)	(((size)/4) &
SATA_DWC_TXFIFO_DEPTH)
+#define SATA_DWC_DBTSR_MRD(size)	((((size)/4) &
SATA_DWC_RXFIFO_DEPTH)\
+						 << 16)
+
+
+struct sata_dwc_device {
+	struct device		*dev;		/* generic device struct
*/
+	struct ata_probe_ent	*pe;		/* ptr to probe-ent */
+	struct ata_host		*host;
+	u8			*reg_base;
+	struct sata_dwc_regs	*sata_dwc_regs;	/* DW Synopsys SATA
specific */
+	int			irq_dma;
+};
+
+#define SATA_DWC_QCMD_MAX	32
+
+struct sata_dwc_device_port {
+	struct sata_dwc_device	*hsdev;
+	int			cmd_issued[SATA_DWC_QCMD_MAX];
+	struct lli		*llit[SATA_DWC_QCMD_MAX];
+	dma_addr_t		llit_dma[SATA_DWC_QCMD_MAX];
+	u32			dma_chan[SATA_DWC_QCMD_MAX];
+	int			dma_pending[SATA_DWC_QCMD_MAX];
+};
+
+/*
+ * Commonly used DWC SATA driver Macros
+ */
+#define HSDEV_FROM_HOST(host)  ((struct sata_dwc_device *)\
+					(host)->private_data)
+#define HSDEV_FROM_AP(ap)  ((struct sata_dwc_device *)\
+					(ap)->host->private_data)
+#define HSDEVP_FROM_AP(ap)   ((struct sata_dwc_device_port *)\
+					(ap)->private_data)
+#define HSDEV_FROM_QC(qc)	((struct sata_dwc_device *)\
+					(qc)->ap->host->private_data)
+#define HSDEV_FROM_HSDEVP(p)	((struct sata_dwc_device *)\
+						(hsdevp)->hsdev)
+
+enum {
+	SATA_DWC_CMD_ISSUED_NOT		=3D 0,
+	SATA_DWC_CMD_ISSUED_PEND	=3D 1,
+	SATA_DWC_CMD_ISSUED_EXEC	=3D 2,
+	SATA_DWC_CMD_ISSUED_NODATA	=3D 3,
+
+	SATA_DWC_DMA_PENDING_NONE	=3D 0,
+	SATA_DWC_DMA_PENDING_TX		=3D 1,
+	SATA_DWC_DMA_PENDING_RX		=3D 2,
+};
+
+
+struct sata_dwc_host_priv {
+
+	void __iomem *scr_addr_sstatus;
+	u32 sata_dwc_sactive_issued;
+	u32 sata_dwc_sactive_queued;
+	u32 dma_interrupt_count;
+	struct ahb_dma_regs *sata_dma_regs;
+	struct device *dwc_dev;
+
+};
+
+struct sata_dwc_host_priv host_pvt;
+
+/*
+ * Prototypes
+ */
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8
tag);
+static int sata_dwc_qc_complete(struct ata_port *ap, struct
ata_queued_cmd *qc,
+				u32 check_status);
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32
check_status);
+static void sata_dwc_port_stop(struct ata_port *ap);
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp,
u8 tag);
+
+static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq);
+static void dma_dwc_exit(struct sata_dwc_device *hsdev);
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+			      struct lli *lli, dma_addr_t dma_lli,
+			      void __iomem *addr, int dir);
+static void dma_dwc_xfer_start(int dma_ch);
+
+static const char *dir_2_txt(enum dma_data_direction dir)
+{
+	switch (dir) {
+	case DMA_BIDIRECTIONAL:
+		return "bi";
+	case DMA_FROM_DEVICE:
+		return "from";
+	case DMA_TO_DEVICE:
+		return "to";
+	case DMA_NONE:
+		return "none";
+	default:
+		return "err";
+	}
+}
+
+static const char *prot_2_txt(enum ata_tf_protocols protocol)
+{
+	switch (protocol) {
+	case ATA_PROT_UNKNOWN:
+		return "unknown";
+	case ATA_PROT_NODATA:
+		return "nodata";
+	case ATA_PROT_PIO:
+		return "pio";
+	case ATA_PROT_DMA:
+		return "dma";
+	case ATA_PROT_NCQ:
+		return "ncq";
+	case ATAPI_PROT_PIO:
+		return "atapi pio";
+	case ATAPI_PROT_NODATA:
+		return "atapi nodata";
+	case ATAPI_PROT_DMA:
+		return "atapi dma";
+	default:
+		return "err";
+	}
+}
+
+inline const char *ata_cmd_2_txt(const struct ata_taskfile *tf)
+{
+	switch (tf->command) {
+	case ATA_CMD_CHK_POWER:
+		return "ATA_CMD_CHK_POWER";
+	case ATA_CMD_EDD:
+		return "ATA_CMD_EDD";
+	case ATA_CMD_FLUSH:
+		return "ATA_CMD_FLUSH";
+	case ATA_CMD_FLUSH_EXT:
+		return "ATA_CMD_FLUSH_EXT";
+	case ATA_CMD_ID_ATA:
+		return "ATA_CMD_ID_ATA";
+	case ATA_CMD_ID_ATAPI:
+		return "ATA_CMD_ID_ATAPI";
+	case ATA_CMD_FPDMA_READ:
+		return "ATA_CMD_FPDMA_READ";
+	case ATA_CMD_FPDMA_WRITE:
+		return "ATA_CMD_FPDMA_WRITE";
+	case ATA_CMD_READ:
+		return "ATA_CMD_READ";
+	case ATA_CMD_READ_EXT:
+		return "ATA_CMD_READ_EXT";
+	case ATA_CMD_READ_NATIVE_MAX_EXT:
+		return "ATA_CMD_READ_NATIVE_MAX_EXT";
+	case ATA_CMD_VERIFY_EXT:
+		return "ATA_CMD_VERIFY_EXT";
+	case ATA_CMD_WRITE:
+		return "ATA_CMD_WRITE";
+	case ATA_CMD_WRITE_EXT:
+		return "ATA_CMD_WRITE_EXT";
+	case ATA_CMD_PIO_READ:
+		return "ATA_CMD_PIO_READ";
+	case ATA_CMD_PIO_READ_EXT:
+		return "ATA_CMD_PIO_READ_EXT";
+	case ATA_CMD_PIO_WRITE:
+		return "ATA_CMD_PIO_WRITE";
+	case ATA_CMD_PIO_WRITE_EXT:
+		return "ATA_CMD_PIO_WRITE_EXT";
+	case ATA_CMD_SET_FEATURES:
+		return "ATA_CMD_SET_FEATURES";
+	case ATA_CMD_PACKET:
+		return "ATA_CMD_PACKET";
+	default:
+		return "ATA_CMD_???";
+	}
+}
+
+static void sata_dwc_tf_dump(struct ata_taskfile *tf)
+{
+
+	dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s
flags: "
+		"0x%lx device: %x\n", tf->command,
prot_2_txt(tf->protocol),
+		tf->flags, tf->device);
+	dev_vdbg(host_pvt.dwc_dev, "feature: 0x%02x nsect: 0x%x lbal:
0x%x "
+		"lbam: 0x%x lbah: 0x%x\n", tf->feature, tf->nsect,
tf->lbal,
+		tf->lbam, tf->lbah);
+	dev_vdbg(host_pvt.dwc_dev, "hob_feature:0x%02x hob_nsect:0x%x
hob_lbal"
+		": 0x%x hob_lbam: 0x%x hob_lbah: 0x%x\n",
tf->hob_feature,
+		tf->hob_nsect, tf->hob_lbal, tf->hob_lbam,
tf->hob_lbah);
+}
+/*
+ * Function: get_burst_length_encode
+ * arguments: datalength: length in bytes of data
+ * returns value to be programmed in register corrresponding to data
length
+ * This value is effectively the log(base 2) of the length
+ */
+static inline int get_burst_length_encode(int datalength)
+{
+	int items =3D datalength >> 2;	/* div by 4 to get lword count
*/
+
+	if (items >=3D 64)
+		return 5;
+
+	if (items >=3D 32)
+		return 4;
+
+	if (items >=3D 16)
+		return 3;
+
+	if (items >=3D 8)
+		return 2;
+
+	if (items >=3D 4)
+		return 1;
+
+	return 0;
+}
+
+static inline void clear_chan_interrupts(int c)
+{
+	out_le32(&host_pvt.sata_dma_regs->interrupt_clear.tfr.low,
+		 DMA_CHANNEL(c));
+	out_le32(&host_pvt.sata_dma_regs->interrupt_clear.block.low,
+		 DMA_CHANNEL(c));
+	out_le32(&host_pvt.sata_dma_regs->interrupt_clear.srctran.low,
+		 DMA_CHANNEL(c));
+	out_le32(&host_pvt.sata_dma_regs->interrupt_clear.dsttran.low,
+		 DMA_CHANNEL(c));
+	out_le32(&host_pvt.sata_dma_regs->interrupt_clear.error.low,
+		 DMA_CHANNEL(c));
+}
+
+/*
+ * Function: dma_request_channel
+ * arguments: None
+ * returns channel number if available else -1
+ * This function assigns the next available DMA channel from the list
to the
+ * requester
+ */
+static int dma_request_channel(void)
+{
+	int i;
+
+	for (i =3D 0; i < DMA_NUM_CHANS; i++) {
+		if
(!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) & \
+				DMA_CHANNEL(i)))
+			return i;
+	}
+
+	/* warn of channel info */
+	dev_err(host_pvt.dwc_dev, "%s NO channel chan_en: 0x%08x\n",
__func__,
+		in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)));
+
+	return -1;
+}
+
+/*
+ * Function: dma_dwc_interrupt
+ * arguments: irq, dev_id, pt_regs
+ * returns channel number if available else -1
+ * Interrupt Handler for DW AHB SATA DMA
+ */
+static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
+{
+	int chan;
+	u32 tfr_reg, err_reg;
+
+	struct sata_dwc_device *hsdev =3D
+		(struct sata_dwc_device *) hsdev_instance;
+	struct ata_host *host =3D (struct ata_host *) hsdev->host;
+	struct ata_port *ap;
+	struct sata_dwc_device_port *hsdevp;
+	u8 tag =3D 0;
+	unsigned int port =3D 0;
+	struct sata_dwc_host_priv *hp;
+	hp =3D kmalloc(sizeof(*hp), GFP_KERNEL);
+
+	spin_lock(&host->lock);
+
+	ap =3D host->ports[port];
+	hsdevp =3D HSDEVP_FROM_AP(ap);
+	tag =3D ap->link.active_tag;
+
+	tfr_reg =3D
in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr.low));
+	err_reg =3D in_le32(&(host_pvt.sata_dma_regs-> \
+					interrupt_status.error.low));
+
+	dev_dbg(ap->dev, "eot=3D0x%08x err=3D0x%08x pending=3D%d active
port=3D%d\n",
+		tfr_reg, err_reg, hsdevp->dma_pending[tag], port);
+
+	for (chan =3D 0; chan < DMA_NUM_CHANS; chan++) {
+		/* Check for end-of-transfer interrupt. */
+		if (tfr_reg & DMA_CHANNEL(chan)) {
+			/* Each DMA command produces 2 interrupts.  Only
+			 * complete the command after both interrupts
have been
+			 * seen. (See sata_dwc_isr())
+			 */
+			hp->dma_interrupt_count++;
+
+			sata_dwc_clear_dmacr(hsdevp, tag);
+
+			if (hsdevp->dma_pending[tag] =3D=3D
+			    SATA_DWC_DMA_PENDING_NONE) {
+				dev_err(ap->dev, "DMA not pending
eot=3D0x%08x "
+					"err=3D0x%08x tag=3D0x%02x
pending=3D%d\n",
+					tfr_reg, err_reg, tag,
+					hsdevp->dma_pending[tag]);
+			}
+
+			if ((hp->dma_interrupt_count) % 2 =3D=3D 0)
+				sata_dwc_dma_xfer_complete(ap, 1);
+
+			/* Clear the interrupt */
+			out_le32(&(host_pvt.sata_dma_regs-> \
+				interrupt_clear.tfr.low),
DMA_CHANNEL(chan));
+		}
+
+		/* Check for error interrupt. */
+		if (err_reg & DMA_CHANNEL(chan)) {
+			/* Error handler ! */
+			dev_err(ap->dev, "error interrupt
err_reg=3D0x%08x\n",
+				err_reg);
+
+			/* Clear the interrupt. */
+
out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.\
+			error.low), DMA_CHANNEL(chan));
+		}
+	}
+
+	spin_unlock(&host->lock);
+	kfree(hp);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Function: dma_request_interrupts
+ * arguments: hsdev
+ * returns status
+ * This function registers ISR for a particular DMA channel interrupt
+ */
+static int dma_request_interrupts(struct sata_dwc_device *hsdev, int
irq)
+{
+	int retval =3D 0;
+	int chan;
+
+	for (chan =3D 0; chan < DMA_NUM_CHANS; chan++) {
+		/* Unmask error interrupt */
+
out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.error.low,
+			 DMA_ENABLE_CHAN(chan));
+
+		/* Unmask end-of-transfer interrupt */
+
out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.tfr.low,
+			 DMA_ENABLE_CHAN(chan));
+	}
+
+	retval =3D request_irq(irq, dma_dwc_interrupt, 0, "SATA DMA",
hsdev);
+	if (retval) {
+		dev_err(host_pvt.dwc_dev, "%s: No IRQ %d\n", __func__,
irq);
+		return -ENODEV;
+	}
+
+	/* Mark this interrupt as requested */
+	hsdev->irq_dma =3D irq;
+
+	return 0;
+}
+
+/*
+ * Function: map_sg_to_lli
+ * arguments: sg: scatter/gather list(sg)
+ *	      num_elems: no of elements in sg list
+ *	      dma_lli: LLI table
+ *	      dest: destination address
+ *	      read: whether the transfer is read or write
+ * returns array of AHB DMA Linked List Items
+ * This function creates a list of LLIs for DMA Xfr and returns the
number
+ * of elements in the DMA linked list.
+ *
+ * Note that the Synopsis driver did comment proposing that better
performance
+ * is possible by only enabling interrupts on the last item in the
linked list.
+ * However, it seems that could be a problem if an error happened on
one of the
+ * first items.  The transfer would halt, but no error interrupt would
occur.
+ *
+ * Currently this function sets interrupts enabled for each linked list
item:
+ * DMA_CTL_INT_EN.
+ */
+static int map_sg_to_lli(struct scatterlist *sg, int num_elems, struct
lli *lli
+		, dma_addr_t dma_lli, void __iomem *dmadr_addr, int dir)
+{
+	int i, idx =3D 0;
+	int fis_len =3D 0;
+	dma_addr_t next_llp;
+	int bl;
+
+	dev_dbg(host_pvt.dwc_dev, "%s: sg=3D%p nelem=3D%d lli=3D%p
dma_lli=3D0x%08x\n",
+		__func__, sg, num_elems, lli, (u32)dma_lli);
+
+	bl =3D get_burst_length_encode(AHB_DMA_BRST_DFLT);
+
+	for (i =3D 0; i < num_elems; i++, sg++) {
+		u32 addr, offset;
+		u32 sg_len, len;
+
+		addr =3D (u32) sg_dma_address(sg);
+		sg_len =3D sg_dma_len(sg);
+
+		dev_dbg(host_pvt.dwc_dev, "%s: elem=3D%d sg_addr=3D0x%x
sg_len"
+			"=3D%d\n", __func__, i, addr, sg_len);
+
+		while (sg_len) {
+
+			if (idx >=3D SATA_DWC_DMAC_LLI_NUM) {
+				/* The LLI table is not large enough. */
+				dev_err(host_pvt.dwc_dev, "LLI table
overrun "
+					"(idx=3D%d)\n", idx);
+				break;
+			}
+			len =3D (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ?
+				SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len;
+
+			offset =3D addr & 0xffff;
+			if ((offset + sg_len) > 0x10000)
+				len =3D 0x10000 - offset;
+
+			/*
+			 * Make sure a LLI block is not created that
will span a
+			 * 8K max FIS boundary.  If the block spans such
a FIS
+			 * boundary, there is a chance that a DMA burst
will
+			 * cross that boundary -- this results in an
error in
+			 * the host controller.
+			 */
+			if (fis_len + len > 8192) {
+				dev_dbg(host_pvt.dwc_dev, "SPLITTING:
fis_len"
+					"=3D%d(0x%x)len=3D%d(0x%x)\n",
fis_len,
+					fis_len, len, len);
+				len =3D 8192 - fis_len;
+				fis_len =3D 0;
+			} else {
+				fis_len +=3D len;
+			}
+			if (fis_len =3D=3D 8192)
+				fis_len =3D 0;
+
+			/*
+			 * Set DMA addresses and lower half of control
register
+			 * based on direction.
+			 */
+			if (dir =3D=3D DMA_FROM_DEVICE) {
+				lli[idx].dar =3D cpu_to_le32(addr);
+				lli[idx].sar =3D
cpu_to_le32((u32)dmadr_addr);
+
+				lli[idx].ctl.low =3D cpu_to_le32(
+
DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+					DMA_CTL_SMS(0) |
+					DMA_CTL_DMS(1) |
+					DMA_CTL_SRC_MSIZE(bl) |
+					DMA_CTL_DST_MSIZE(bl) |
+					DMA_CTL_SINC_NOCHANGE |
+					DMA_CTL_SRC_TRWID(2) |
+					DMA_CTL_DST_TRWID(2) |
+					DMA_CTL_INT_EN |
+					DMA_CTL_LLP_SRCEN |
+					DMA_CTL_LLP_DSTEN);
+			} else {	/* DMA_TO_DEVICE */
+				lli[idx].sar =3D cpu_to_le32(addr);
+				lli[idx].dar =3D
cpu_to_le32((u32)dmadr_addr);
+
+				lli[idx].ctl.low =3D cpu_to_le32(
+
DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+					DMA_CTL_SMS(1) |
+					DMA_CTL_DMS(0) |
+					DMA_CTL_SRC_MSIZE(bl) |
+					DMA_CTL_DST_MSIZE(bl) |
+					DMA_CTL_DINC_NOCHANGE |
+					DMA_CTL_SRC_TRWID(2) |
+					DMA_CTL_DST_TRWID(2) |
+					DMA_CTL_INT_EN |
+					DMA_CTL_LLP_SRCEN |
+					DMA_CTL_LLP_DSTEN);
+			}
+
+			dev_dbg(host_pvt.dwc_dev, "%s setting ctl.high
len: "
+				"0x%08x val: 0x%08x\n",	__func__, len,
+				DMA_CTL_BLK_TS(len / 4));
+
+			/* Program the LLI CTL high register */
+			lli[idx].ctl.high =3D cpu_to_le32(DMA_CTL_BLK_TS \
+						(len / 4));
+
+			/* Program the next pointer.  The next pointer
must be
+			 * the physical address, not the virtual
address.
+			 */
+			next_llp =3D (dma_lli + ((idx + 1) * \
+						sizeof(struct lli)));
+
+			/* The last 2 bits encode the list master
select. */
+			next_llp =3D DMA_LLP_LMS(next_llp,
DMA_LLP_AHBMASTER2);
+
+			lli[idx].llp =3D cpu_to_le32(next_llp);
+
+			idx++;
+			sg_len -=3D len;
+			addr +=3D len;
+		}
+	}
+
+	/*
+	 * The last next ptr has to be zero and the last control low
register
+	 * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer
source
+	 * and destination enable) set back to 0 (disabled.) This is
what tells
+	 * the core that this is the last item in the linked list.
+	 */
+	if (idx) {
+		lli[idx-1].llp =3D 0x00000000;
+		lli[idx-1].ctl.low &=3D DMA_CTL_LLP_DISABLE_LE32;
+
+		/* Flush cache to memory */
+		dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx),
+			       DMA_BIDIRECTIONAL);
+	}
+
+	return idx;
+}
+
+/*
+ * Function: dma_dwc_xfer_start
+ * arguments: Channel number
+ * Return : None
+ * Enables the DMA channel
+ */
+static void dma_dwc_xfer_start(int dma_ch)
+{
+	/* Enable the DMA channel */
+	out_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low),
+		 in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) |
+		 DMA_ENABLE_CHAN(dma_ch));
+
+}
+
+
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+			      struct lli *lli, dma_addr_t dma_lli,
+			      void __iomem *addr, int dir)
+{
+	int dma_ch;
+	int num_lli;
+
+	/* Acquire DMA channel */
+	dma_ch =3D dma_request_channel();
+	if (dma_ch =3D=3D -1) {
+		dev_err(host_pvt.dwc_dev, "%s: dma channel
unavailable\n",
+			 __func__);
+		return -EAGAIN;
+	}
+
+	/* Convert SG list to linked list of items (LLIs) for AHB DMA */
+	num_lli =3D map_sg_to_lli(sg, num_elems, lli, dma_lli, addr, dir);
+
+	dev_dbg(host_pvt.dwc_dev, "%s sg: 0x%p, count: %d lli: %p
dma_lli:"
+		"0x%0xlx addr: %p lli count: %d\n", __func__, sg,
num_elems,
+		 lli, (u32)dma_lli, addr, num_lli);
+
+	/* Clear channel interrupts */
+	clear_chan_interrupts(dma_ch);
+
+	/* Program the CFG register. */
+	out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high),
+		 DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
+	out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low),
0);
+
+	/* Program the address of the linked list */
+	out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low),
+		 DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
+
+	/* Program the CTL register with src enable / dst enable */
+	out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].ctl.low),
+		 DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN);
+
+	return 0;
+}
+
+/*
+ * Function: dma_dwc_exit
+ * arguments: None
+ * returns status
+ * This function exits the SATA DMA driver
+ */
+static void dma_dwc_exit(struct sata_dwc_device *hsdev)
+{
+	dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__);
+	if (host_pvt.sata_dma_regs)
+		iounmap(host_pvt.sata_dma_regs);
+
+	if (hsdev->irq_dma)
+		free_irq(hsdev->irq_dma, hsdev);
+}
+
+/*
+ * Function: dma_dwc_init
+ * arguments: hsdev
+ * returns status
+ * This function initializes the SATA DMA driver
+ */
+static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
+{
+	int err;
+	err =3D dma_request_interrupts(hsdev, irq);
+	if (err) {
+		dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts"
+			" returns %d\n", __func__, err);
+		goto error_out;
+	}
+
+	/* Enabe DMA */
+	out_le32(&(host_pvt.sata_dma_regs->dma_cfg.low), DMA_EN);
+
+	dev_notice(host_pvt.dwc_dev, "DMA initialized\n");
+	dev_dbg(host_pvt.dwc_dev, "SATA DMA registers=3D0x%p\n",
+		host_pvt.sata_dma_regs);
+
+	return 0;
+
+error_out:
+	dma_dwc_exit(hsdev);
+
+	return err;
+}
+
+static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr,
u32 *val)
+{
+	if (scr > SCR_NOTIFICATION) {
+		dev_err(link->ap->dev, "%s: Incorrect SCR offset
0x%02x\n",
+			__func__, scr);
+		return -EINVAL;
+	}
+
+	*val =3D in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
+	dev_dbg(link->ap->dev, "%s: id=3D%d reg=3D%d val=3Dval=3D0x%08x\n",
+		__func__, link->ap->print_id, scr, *val);
+
+	return 0;
+}
+
+static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr,
u32 val)
+{
+	dev_dbg(link->ap->dev, "%s: id=3D%d reg=3D%d val=3Dval=3D0x%08x\n",
+		__func__, link->ap->print_id, scr, val);
+	if (scr > SCR_NOTIFICATION) {
+		dev_err(link->ap->dev, "%s: Incorrect SCR offset
0x%02x\n",
+			__func__, scr);
+		return -EINVAL;
+	}
+	out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
+
+	return 0;
+}
+
+static inline u32 core_scr_read(unsigned int scr)
+{
+	return in_le32((host_pvt.scr_addr_sstatus) + (scr * 4));
+}
+
+static inline void core_scr_write(unsigned int scr, u32 val)
+{
+	out_le32((host_pvt.scr_addr_sstatus) + (scr * 4), val);
+}
+
+static inline void clear_serror(void)
+{
+	out_le32((host_pvt.scr_addr_sstatus) + 4,
+		 in_le32((host_pvt.scr_addr_sstatus) + 4));
+}
+
+static inline void clear_intpr(struct sata_dwc_device *hsdev)
+{
+	out_le32(&hsdev->sata_dwc_regs->intpr,
+		 in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static inline void clear_interrupt_bit(struct sata_dwc_device *hsdev,
u32 bit)
+{
+	out_le32(&hsdev->sata_dwc_regs->intpr,
+		 in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static inline void disable_err_irq(struct sata_dwc_device *hsdev)
+{
+	out_le32(&hsdev->sata_dwc_regs->intmr,
+		 in_le32(&hsdev->sata_dwc_regs->intmr) &
~SATA_DWC_INTMR_ERRM);
+	out_le32(&hsdev->sata_dwc_regs->errmr,
~SATA_DWC_SERROR_ERR_BITS);
+}
+
+static inline void enable_err_irq(struct sata_dwc_device *hsdev)
+{
+	out_le32(&hsdev->sata_dwc_regs->intmr,
+		 in_le32(&hsdev->sata_dwc_regs->intmr) |
SATA_DWC_INTMR_ERRM);
+	out_le32(&hsdev->sata_dwc_regs->errmr,
SATA_DWC_SERROR_ERR_BITS);
+}
+
+static inline u32 qcmd_tag_to_mask(u8 tag)
+{
+	return 0x00000001 << (tag & 0x1f);
+}
+
+/* See ahci.c */
+static void sata_dwc_error_intr(struct ata_port *ap,
+				struct sata_dwc_device *hsdev, uint
intpr)
+{
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+	struct ata_eh_info *ehi =3D &ap->link.eh_info;
+	unsigned int err_mask =3D 0, action =3D 0;
+	struct ata_queued_cmd *qc;
+	u32 serror;
+	u8 status, tag;
+	u32 err_reg;
+	struct sata_dwc_host_priv *hp;
+	hp =3D kmalloc(sizeof(*hp), GFP_KERNEL);
+
+	ata_ehi_clear_desc(ehi);
+
+	serror =3D core_scr_read(SCR_ERROR);
+	status =3D ap->ops->sff_check_status(ap);
+
+	err_reg =3D in_le32(&(host_pvt.sata_dma_regs-> \
+				interrupt_status.error.low));
+	tag =3D ap->link.active_tag;
+
+	dev_err(ap->dev, "%s SCR_ERROR=3D0x%08x intpr=3D0x%08x status=3D0x%08x
"
+		"dma_intp=3D%d pending=3D%d issued=3D%d
dma_err_status=3D0x%08x\n",
+		__func__, serror, intpr, status,
hp->dma_interrupt_count,
+		hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag],
err_reg);
+
+	/* Clear error register and interrupt bit */
+	clear_serror();
+	clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR);
+
+	/* This is the only error happening now. */
+	err_mask |=3D AC_ERR_HOST_BUS;
+	action |=3D ATA_EH_RESET;
+
+	/* Pass this on to EH */
+	ehi->serror |=3D serror;
+	ehi->action |=3D action;
+
+	qc =3D ata_qc_from_tag(ap, tag);
+	if (qc)
+		qc->err_mask |=3D err_mask;
+	else
+		ehi->err_mask |=3D err_mask;
+
+	ata_port_abort(ap);
+	kfree(hp);
+
+	/*
+	  if (irq_stat & PORT_IRQ_FREEZE)
+	  ata_port_freeze(ap);
+	  else
+	  ata_port_abort(ap);
+	*/
+}
+
+/*
+ * Function : sata_dwc_isr
+ * arguments : irq, void *dev_instance, struct pt_regs *regs
+ * Return value : irqreturn_t - status of IRQ
+ * This Interrupt handler called via port ops registered function.
+ * .irq_handler =3D sata_dwc_isr
+ */
+static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
+{
+	u8 status, tag;
+	int handled, num_processed, port =3D 0;
+	uint intpr, sactive, sactive2, tag_mask;
+	struct sata_dwc_device_port *hsdevp;
+	struct ata_host *host =3D (struct ata_host *)dev_instance;
+	struct sata_dwc_device *hsdev =3D HSDEV_FROM_HOST(host);
+	struct ata_port *ap;
+	struct ata_queued_cmd *qc;
+	struct sata_dwc_host_priv *hp;
+
+	hp =3D kmalloc(sizeof(*hp), GFP_KERNEL);
+	hp->sata_dwc_sactive_issued =3D 0;
+
+	spin_lock(&host->lock);
+
+	/* Read the interrupt register */
+	intpr =3D in_le32(&hsdev->sata_dwc_regs->intpr);
+
+	ap =3D host->ports[port];
+	hsdevp =3D HSDEVP_FROM_AP(ap);
+
+	dev_dbg(ap->dev, "%s intpr=3D0x%08x active_tag=3D%d\n", __func__,
intpr,
+		ap->link.active_tag);
+
+	/* Check for error interrupt */
+	if (intpr & SATA_DWC_INTPR_ERR) {
+		sata_dwc_error_intr(ap, hsdev, intpr);
+		handled =3D 1;
+		goto DONE;
+	}
+
+	/* Check for DMA SETUP FIS (FP DMA) interrupt */
+	if (intpr & SATA_DWC_INTPR_NEWFP) {
+		clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
+
+		tag =3D (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr));
+		dev_dbg(ap->dev, "%s: NEWFP tag=3D%d\n", __func__, tag);
+		if (hsdevp->cmd_issued[tag] !=3D SATA_DWC_CMD_ISSUED_PEND)
+			dev_warn(ap->dev, "CMD tag=3D%d not pending?\n",
tag);
+
+		hp->sata_dwc_sactive_issued |=3D qcmd_tag_to_mask(tag);
+
+		qc =3D ata_qc_from_tag(ap, tag);
+		/* Start FP DMA for NCQ command.  At this point the tag
is the
+		 * active tag.  It is the tag that matches the command
about to
+		 * be completed.
+		 */
+		qc->ap->link.active_tag =3D tag;
+		sata_dwc_bmdma_start_by_tag(qc, tag);
+
+		handled =3D 1;
+		goto DONE;
+	}
+	sactive =3D core_scr_read(SCR_ACTIVE);
+	tag_mask =3D (hp->sata_dwc_sactive_issued | sactive) ^ sactive;
+
+	/* If no sactive issued and tag_mask is zero then this is not
NCQ */
+	if (hp->sata_dwc_sactive_issued =3D=3D 0 && tag_mask =3D=3D 0) {
+		if (ap->link.active_tag =3D=3D ATA_TAG_POISON)
+			tag =3D 0;
+		else
+			tag =3D ap->link.active_tag;
+		qc =3D ata_qc_from_tag(ap, tag);
+
+		/* DEV interrupt w/ no active qc? */
+		if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING)))
{
+			dev_err(ap->dev, "%s interrupt with no active qc
"
+				"qc=3D%p\n", __func__, qc);
+			ata_sff_check_status(ap);
+			handled =3D 1;
+			goto DONE;
+		}
+
+		status =3D ap->ops->sff_check_status(ap);
+
+		qc->ap->link.active_tag =3D tag;
+		hsdevp->cmd_issued[tag] =3D SATA_DWC_CMD_ISSUED_NOT;
+
+		if (status & ATA_ERR) {
+			dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n",
status);
+			sata_dwc_qc_complete(ap, qc, 1);
+			handled =3D 1;
+			goto DONE;
+		}
+
+		dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol:
%s\n",
+			__func__, prot_2_txt(qc->tf.protocol));
+DRVSTILLBUSY:
+		if (ata_is_dma(qc->tf.protocol)) {
+			/* Each DMA transaction produces 2 interrupts.
The DMAC
+			 * transfer complete interrupt and the SATA
controller
+			 * operation done interrupt. The command should
be
+			 * completed only after both interrupts are
seen.
+			 */
+			hp->dma_interrupt_count++;
+			if (hsdevp->dma_pending[tag] =3D=3D \
+					SATA_DWC_DMA_PENDING_NONE) {
+				dev_err(ap->dev, "%s: DMA not pending "
+				"intpr=3D0x%08x status=3D0x%08x
pending=3D%d\n",
+				__func__, intpr, status,
+					hsdevp->dma_pending[tag]);
+			}
+
+			if ((hp->dma_interrupt_count) % 2 =3D=3D 0)
+				sata_dwc_dma_xfer_complete(ap, 1);
+		} else if (ata_is_pio(qc->tf.protocol)) {
+			ata_sff_hsm_move(ap, qc, status, 0);
+			handled =3D 1;
+			goto DONE;
+		} else {
+			if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+				goto DRVSTILLBUSY;
+		}
+
+		handled =3D 1;
+		goto DONE;
+	}
+
+	/*
+	 * This is NCQ command.  At this point we need to figure out for
which
+	 * tags we have gotten a completion interrupt.  One interrupt
may serve
+	 * as completion for more than one operation when commands are
queued
+	 * (NCQ).  We need to process each completed command.
+	 */
+
+PROCESS:  /* process completed commands */
+	sactive =3D core_scr_read(SCR_ACTIVE);
+	tag_mask =3D (hp->sata_dwc_sactive_issued | sactive) ^ sactive;
+
+	if (sactive !=3D 0 || hp->sata_dwc_sactive_issued > 1 || tag_mask
> 1) {
+		dev_dbg(ap->dev, "%s NCQ:sactive=3D0x%08x
sactive_issued=3D0x%08x "
+			"tag_mask=3D0x%08x\n", __func__, sactive,
+			hp->sata_dwc_sactive_issued, tag_mask);
+	}
+
+	if ((tag_mask | (hp->sata_dwc_sactive_issued)) !=3D \
+				(hp->sata_dwc_sactive_issued)) {
+		dev_warn(ap->dev, "Bad tag mask?  sactive=3D0x%08x "
+			 "hp->sata_dwc_sactive_issued=3D0x%08x
tag_mask=3D0x%08x\n"
+			 , sactive, hp->sata_dwc_sactive_issued,
tag_mask);
+	}
+
+	/* read just to clear ... not bad if currently still busy */
+	status =3D ap->ops->sff_check_status(ap);
+	dev_dbg(ap->dev, "%s ATA status register=3D0x%x\n", __func__,
status);
+
+	tag =3D 0;
+	num_processed =3D 0;
+	while (tag_mask) {
+		num_processed++;
+		while (!(tag_mask & 0x00000001)) {
+			tag++;
+			tag_mask >>=3D 1;
+		}
+		tag_mask &=3D (~0x00000001);
+		qc =3D ata_qc_from_tag(ap, tag);
+
+		/* To be picked up by completion functions */
+		qc->ap->link.active_tag =3D tag;
+		hsdevp->cmd_issued[tag] =3D SATA_DWC_CMD_ISSUED_NOT;
+
+		/* Let libata/scsi layers handle error */
+		if (status & ATA_ERR) {
+			dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n",
__func__,
+				status);
+			sata_dwc_qc_complete(ap, qc, 1);
+			handled =3D 1;
+			goto DONE;
+		}
+
+		/* Process completed command */
+		dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n",
__func__,
+			prot_2_txt(qc->tf.protocol));
+		if (ata_is_dma(qc->tf.protocol)) {
+			hp->dma_interrupt_count++;
+			if (hsdevp->dma_pending[tag] =3D=3D \
+					SATA_DWC_DMA_PENDING_NONE)
+				dev_warn(ap->dev, "%s: DMA not
pending?\n",
+					__func__);
+			if ((hp->dma_interrupt_count) % 2 =3D=3D 0)
+				sata_dwc_dma_xfer_complete(ap, 1);
+		} else {
+			if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+				goto STILLBUSY;
+		}
+		continue;
+
+STILLBUSY:
+		ap->stats.idle_irq++;
+		dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n",
+			 ap->print_id);
+	} /* while tag_mask */
+
+	/*
+	 * Check to see if any commands completed while we were
processing our
+	 * initial set of completed commands (reading of status clears
+	 * interrupts, so we might miss a completed command interrupt if
one
+	 * came in while we were processing --we read status as part of
+	 * processing a completed command).
+	 */
+	sactive2 =3D core_scr_read(SCR_ACTIVE);
+	if (sactive2 !=3D sactive) {
+		dev_dbg(ap->dev, "More completed-sactive=3D0x%x
sactive2=3D0x%x\n",
+			sactive, sactive2);
+		goto PROCESS;
+	}
+	handled =3D 1;
+
+DONE:
+	spin_unlock(&host->lock);
+
+	kfree(hp);
+	return IRQ_RETVAL(handled);
+}
+
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp,
u8 tag)
+{
+	struct sata_dwc_device *hsdev =3D HSDEV_FROM_HSDEVP(hsdevp);
+
+	if (hsdevp->dma_pending[tag] =3D=3D SATA_DWC_DMA_PENDING_RX) {
+		out_le32(&(hsdev->sata_dwc_regs->dmacr),
+			 SATA_DWC_DMACR_RX_CLEAR(
+
in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+	} else if (hsdevp->dma_pending[tag] =3D=3D SATA_DWC_DMA_PENDING_TX)
{
+		out_le32(&(hsdev->sata_dwc_regs->dmacr),
+			 SATA_DWC_DMACR_TX_CLEAR(
+
in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+	} else {
+		/* This should not happen, it indicates the driver is
out of
+		 * sync.  If it does happen, clear dmacr anyway.
+		 */
+		dev_err(host_pvt.dwc_dev, "%s DMA protocol RX and TX DMA
not"
+			" pending tag=3D0x%02x pending=3D%d dmacr:
0x%08x\n",
+			__func__, tag, hsdevp->dma_pending[tag],
+			in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+		out_le32(&(hsdev->sata_dwc_regs->dmacr),
+			SATA_DWC_DMACR_TXRXCH_CLEAR);
+	}
+}
+
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32
check_status)
+{
+	struct ata_queued_cmd *qc;
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+	struct sata_dwc_device *hsdev =3D HSDEV_FROM_AP(ap);
+	u8 tag =3D 0;
+
+	tag =3D ap->link.active_tag;
+	qc =3D ata_qc_from_tag(ap, tag);
+
+#ifdef DEBUG_NCQ
+	if (tag > 0) {
+		dev_info(ap->dev, "%s tag=3D%u cmd=3D0x%02x dma dir=3D%s
proto=3D%s "
+			 "dmacr=3D0x%08x\n", __func__, qc->tag,
qc->tf.command,
+			 dir_2_txt(qc->dma_dir),
prot_2_txt(qc->tf.protocol),
+			 in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+	}
+#endif
+
+	if (ata_is_dma(qc->tf.protocol)) {
+		if (hsdevp->dma_pending[tag] =3D=3D
SATA_DWC_DMA_PENDING_NONE) {
+			dev_err(ap->dev, "%s DMA protocol RX and TX DMA
not "
+				"pending dmacr: 0x%08x\n", __func__,
+
in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+		}
+
+		hsdevp->dma_pending[tag] =3D SATA_DWC_DMA_PENDING_NONE;
+		sata_dwc_qc_complete(ap, qc, check_status);
+		ap->link.active_tag =3D ATA_TAG_POISON;
+	} else {
+		sata_dwc_qc_complete(ap, qc, check_status);
+	}
+}
+
+static int sata_dwc_qc_complete(struct ata_port *ap, struct
ata_queued_cmd *qc,
+				u32 check_status)
+{
+	u8 status =3D 0;
+	int i =3D 0;
+	u32 mask =3D 0x0;
+	u8 tag =3D qc->tag;
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+	u32 serror;
+	struct sata_dwc_host_priv *hp;
+	hp =3D kmalloc(sizeof(*hp), GFP_KERNEL);
+
+	hp->sata_dwc_sactive_issued =3D 0;
+	hp->sata_dwc_sactive_queued =3D 0;
+
+	dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__,
check_status);
+
+	if (hsdevp->dma_pending[tag] =3D=3D SATA_DWC_DMA_PENDING_TX)
+		dev_err(ap->dev, "TX DMA PENDING\n");
+	else if (hsdevp->dma_pending[tag] =3D=3D SATA_DWC_DMA_PENDING_RX)
+		dev_err(ap->dev, "RX DMA PENDING\n");
+
+	if (check_status) {
+		i =3D 0;
+		do {
+			/* check main status, clearing INTRQ */
+			status =3D ap->ops->sff_check_status(ap);
+			if (status & ATA_BUSY) {
+				dev_dbg(ap->dev, "STATUS BUSY (0x%02x)
[%d]\n",
+						status, i);
+			}
+			if (++i > 10)
+				break;
+		} while (status & ATA_BUSY);
+
+		status =3D ap->ops->sff_check_status(ap);
+		if (unlikely(status & ATA_BUSY))
+			dev_err(ap->dev, "QC complete cmd=3D0x%02x STATUS
BUSY"
+				" (0x%02x) [%d]\n", qc->tf.command,
status, i);
+		serror =3D core_scr_read(SCR_ERROR);
+		if (serror & SATA_DWC_SERROR_ERR_BITS)
+			dev_err(ap->dev, "****** SERROR=3D0x%08x
******\n",
+				serror);
+	}
+	dev_dbg(ap->dev, "QC complete cmd=3D0x%02x status=3D0x%02x ata%u:"
+		" protocol=3D%d\n", qc->tf.command, status, ap->print_id,
+		 qc->tf.protocol);
+
+	/* clear active bit */
+	mask =3D ~(qcmd_tag_to_mask(tag));
+	hp->sata_dwc_sactive_queued =3D hp->sata_dwc_sactive_queued &
mask;
+	hp->sata_dwc_sactive_issued =3D hp->sata_dwc_sactive_issued &
mask;
+
+	/* Complete taskfile transaction (does not read SCR registers)
*/
+	ata_qc_complete(qc);
+
+	return 0;
+}
+
+static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
+{
+	/* Enable selective interrupts by setting the interrupt mask
register */
+	out_le32(&hsdev->sata_dwc_regs->intmr,
+		 SATA_DWC_INTMR_ERRM |
+		 SATA_DWC_INTMR_NEWFPM |
+		 SATA_DWC_INTMR_PMABRTM |
+		 SATA_DWC_INTMR_DMATM);
+
+	/* Unmask the error bits that should trigger an error interrupt
by
+	 * setting the error mask register.
+	 */
+	out_le32(&hsdev->sata_dwc_regs->errmr,
SATA_DWC_SERROR_ERR_BITS);
+
+	dev_dbg(host_pvt.dwc_dev, "%s: INTMR =3D 0x%08x, ERRMR =3D
0x%08x\n",
+		__func__, in_le32(&hsdev->sata_dwc_regs->intmr),
+		in_le32(&hsdev->sata_dwc_regs->errmr));
+}
+
+static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long
base)
+{
+	port->cmd_addr =3D (void *)(base + 0x00);
+	port->data_addr =3D (void *)(base + 0x00);
+
+	port->error_addr =3D (void *)(base + 0x04);
+	port->feature_addr =3D (void *)(base + 0x04);
+
+	port->nsect_addr =3D (void *)(base + 0x08);
+
+	port->lbal_addr =3D (void *)(base + 0x0c);
+	port->lbam_addr =3D (void *)(base + 0x10);
+	port->lbah_addr =3D (void *)(base + 0x14);
+
+	port->device_addr =3D (void *)(base + 0x18);
+	port->command_addr =3D (void *)(base + 0x1c);
+	port->status_addr =3D (void *)(base + 0x1c);
+
+	port->altstatus_addr =3D (void *)(base + 0x20);
+	port->ctl_addr =3D (void *)(base + 0x20);
+}
+
+/*
+ * Function : sata_dwc_port_start
+ * arguments : struct ata_ioports *port
+ * Return value : returns 0 if success, error code otherwise
+ * This function allocates the scatter gather LLI table for AHB DMA
+ */
+static int sata_dwc_port_start(struct ata_port *ap)
+{
+	int err =3D 0;
+	struct sata_dwc_device *hsdev;
+	struct sata_dwc_device_port *hsdevp =3D NULL;
+	struct device *pdev;
+	u32 sstatus;
+	int i;
+
+	hsdev =3D HSDEV_FROM_AP(ap);
+
+	dev_dbg(ap->dev, "%s: port_no=3D%d\n", __func__, ap->port_no);
+
+	hsdev->host =3D ap->host;
+	pdev =3D ap->host->dev;
+	if (!pdev) {
+		dev_err(ap->dev, "%s: no ap->host->dev\n", __func__);
+		err =3D -ENODEV;
+		goto CLEANUP;
+	}
+
+	/* Allocate Port Struct */
+	hsdevp =3D kmalloc(sizeof(*hsdevp), GFP_KERNEL);
+	if (!hsdevp) {
+		dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n",
__func__);
+		err =3D -ENOMEM;
+		goto CLEANUP;
+	}
+	memset(hsdevp, 0, sizeof(*hsdevp));
+	hsdevp->hsdev =3D hsdev;
+
+	for (i =3D 0; i < SATA_DWC_QCMD_MAX; i++)
+		hsdevp->cmd_issued[i] =3D SATA_DWC_CMD_ISSUED_NOT;
+
+	ap->prd =3D 0;	/* set these so libata doesn't use them */
+	ap->prd_dma =3D 0;
+
+	/*
+	 * DMA - Assign scatter gather LLI table. We can't use the
libata
+	 * version since it's PRD is IDE PCI specific.
+	 */
+	for (i =3D 0; i < SATA_DWC_QCMD_MAX; i++) {
+		hsdevp->llit[i] =3D dma_alloc_coherent(pdev,
+
SATA_DWC_DMAC_LLI_TBL_SZ,
+
&(hsdevp->llit_dma[i]),
+						     GFP_ATOMIC);
+		if (!hsdevp->llit[i]) {
+			dev_err(ap->dev, "%s: dma_alloc_coherent
failed\n",
+				__func__);
+			err =3D -ENOMEM;
+			goto CLEANUP;
+		}
+	}
+
+	if (ap->port_no =3D=3D 0)  {
+		dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in
DMAC\n",
+			__func__);
+		out_le32(&hsdev->sata_dwc_regs->dmacr,
+				 SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+		dev_dbg(ap->dev, "%s:setting burst size in DBTSR\n",
__func__);
+		out_le32(&hsdev->sata_dwc_regs->dbtsr,
+			 (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+			  SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)));
+	}
+
+	/* Clear any error bits before libata starts issuing commands */
+	clear_serror();
+
+	ap->private_data =3D hsdevp;
+
+	/* Are we in Gen I or II */
+	sstatus =3D core_scr_read(SCR_STATUS);
+	switch (SATA_DWC_SCR0_SPD_GET(sstatus)) {
+	case 0x0:
+		dev_info(ap->dev, "**** No negotiated speed (nothing
attached?"
+			") ****\n");
+		break;
+	case 0x1:
+		dev_info(ap->dev, "**** GEN I speed rate negotiated
****\n");
+		break;
+	case 0x2:
+		dev_info(ap->dev, "**** GEN II speed rate negotiated
****\n");
+		break;
+	}
+
+CLEANUP:
+	if (err) {
+		kfree(hsdevp);
+		sata_dwc_port_stop(ap);
+		dev_dbg(ap->dev, "%s: fail\n", __func__);
+	} else {
+		dev_dbg(ap->dev, "%s: done\n", __func__);
+	}
+
+	return err;
+}
+
+static void sata_dwc_port_stop(struct ata_port *ap)
+{
+	int i;
+	struct sata_dwc_device *hsdev =3D HSDEV_FROM_AP(ap);
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+
+	dev_dbg(ap->dev, "%s: ap->id =3D %d\n", __func__, ap->print_id);
+
+	if (hsdevp && hsdev) {
+		/* deallocate LLI table */
+		for (i =3D 0; i < SATA_DWC_QCMD_MAX; i++) {
+			dma_free_coherent(ap->host->dev,
+					  SATA_DWC_DMAC_LLI_TBL_SZ,
+					 hsdevp->llit[i],
hsdevp->llit_dma[i]);
+		}
+
+		kfree(hsdevp);
+	}
+	ap->private_data =3D NULL;
+}
+
+/*
+ * Function : sata_dwc_exec_command_by_tag
+ * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued
+ * Return value : None
+ * This function keeps track of individual command tag ids and calls
+ * ata_exec_command in libata
+ */
+static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
+					 struct ata_taskfile *tf,
+					 u8 tag, u32 cmd_issued)
+{
+
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+
+	dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=3D%d\n", __func__,
tf->command,
+		ata_cmd_2_txt(tf), tag);
+
+	spin_lock(&ap->host->lock);
+	hsdevp->cmd_issued[tag] =3D cmd_issued;
+	spin_unlock(&ap->host->lock);
+
+	/* Clear SError before executing a new command.
+	 *
+	 * Read a PM's registers now, we will throw away the task
+	 * file values loaded into the shadow registers for this
command.
+	 *
+	 * sata_dwc_scr_write and read can not be used here. Clearing
the PM
+	 * managed SError register for the disk needs to be done before
the
+	 * task file is loaded.
+	 */
+	clear_serror();
+	ata_sff_exec_command(ap, tf);
+}
+
+static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8
tag)
+{
+	sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag,
+				     SATA_DWC_CMD_ISSUED_PEND);
+}
+
+static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	u8 tag =3D qc->tag;
+
+	if (ata_is_ncq(qc->tf.protocol)) {
+		dev_dbg(qc->ap->dev, "%s: ap->link.sactive=3D0x%08x
tag=3D%d\n",
+			__func__, qc->ap->link.sactive, tag);
+	} else {
+		tag =3D 0;
+	}
+
+	sata_dwc_bmdma_setup_by_tag(qc, tag);
+}
+
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8
tag)
+{
+	int start_dma;
+	u32 reg, dma_chan;
+	struct sata_dwc_device *hsdev =3D HSDEV_FROM_QC(qc);
+	struct ata_port *ap =3D qc->ap;
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+	int dir =3D qc->dma_dir;
+	dma_chan =3D hsdevp->dma_chan[tag];
+
+	/* Used for ata_bmdma_start(qc) -- we are not BMDMA compatible
*/
+
+	if (hsdevp->cmd_issued[tag] !=3D SATA_DWC_CMD_ISSUED_NOT) {
+		start_dma =3D 1;
+		if (dir =3D=3D DMA_TO_DEVICE)
+			hsdevp->dma_pending[tag] =3D
SATA_DWC_DMA_PENDING_TX;
+		else
+			hsdevp->dma_pending[tag] =3D
SATA_DWC_DMA_PENDING_RX;
+	} else {
+		dev_err(ap->dev, "%s:Command not pending cmd_issued=3D%d"
+			" (tag=3D%d)- DMA NOT started\n", __func__,
+			 hsdevp->cmd_issued[tag], tag);
+		start_dma =3D 0;
+	}
+
+	dev_dbg(ap->dev, "%s qc=3D%p tag: %x cmd: 0x%02x dma_dir: %s
start_dma?"
+		" %x\n", __func__, qc, tag, qc->tf.command,
+		dir_2_txt(qc->dma_dir), start_dma);
+	sata_dwc_tf_dump(&(qc->tf));
+
+	if (start_dma) {
+		reg =3D core_scr_read(SCR_ERROR);
+		if (reg & SATA_DWC_SERROR_ERR_BITS) {
+			dev_err(ap->dev, "%s: ****** SError=3D0x%08x
******\n",
+				__func__, reg);
+		}
+
+		if (dir =3D=3D DMA_TO_DEVICE)
+			out_le32(&hsdev->sata_dwc_regs->dmacr,
+				SATA_DWC_DMACR_TXCHEN);
+		else
+			out_le32(&hsdev->sata_dwc_regs->dmacr,
+				SATA_DWC_DMACR_RXCHEN);
+
+		/* Enable AHB DMA transfer on the specified channel */
+		dma_dwc_xfer_start(dma_chan);
+	}
+}
+
+static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
+{
+	u8 tag =3D qc->tag;
+
+	if (ata_is_ncq(qc->tf.protocol)) {
+		dev_dbg(qc->ap->dev, "%s: ap->link.sactive=3D0x%08x
tag=3D%d\n",
+			__func__, qc->ap->link.sactive, tag);
+	} else {
+		tag =3D 0;
+	}
+
+	dev_dbg(qc->ap->dev, "%s\n", __func__);
+	sata_dwc_bmdma_start_by_tag(qc, tag);
+}
+
+/*
+ * Function : sata_dwc_qc_prep_by_tag
+ * arguments : ata_queued_cmd *qc, u8 tag
+ * Return value : None
+ * qc_prep for a particular queued command based on tag
+ */
+static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+	struct scatterlist *sg =3D qc->sg;
+	struct ata_port *ap =3D qc->ap;
+	u32 dma_chan;
+	struct sata_dwc_device *hsdev =3D HSDEV_FROM_AP(ap);
+	struct sata_dwc_device_port *hsdevp =3D HSDEVP_FROM_AP(ap);
+	int err;
+
+	dev_dbg(ap->dev, "%s: port=3D%d dma dir=3D%s n_elem=3D%d\n",
+		__func__, ap->port_no, dir_2_txt(qc->dma_dir),
qc->n_elem);
+
+	dma_chan =3D dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
+			hsdevp->llit_dma[tag],
+			(void *__iomem)(&hsdev->sata_dwc_regs->dmadr),
+			qc->dma_dir);
+	if (dma_chan < 0) {
+		dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err
%d\n",
+			__func__, err);
+		return;
+	}
+
+	hsdevp->dma_chan[tag] =3D dma_chan;
+}
+
+static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap =3D qc->ap;
+
+#ifdef DEBUG_NCQ
+	if (qc->tag > 0 || ap->link.sactive > 1)
+		dev_info(ap->dev, "%s ap id=3D%d cmd(0x%02x)=3D%s qc tag=3D%d
"
+			 "prot=3D%s ap active_tag=3D0x%08x ap
sactive=3D0x%08x\n",
+			 __func__, ap->print_id, qc->tf.command,
+			 ata_cmd_2_txt(&qc->tf), qc->tag,
+			 prot_2_txt(qc->tf.protocol),
ap->link.active_tag,
+			 ap->link.sactive);
+#endif
+
+	if (ata_is_ncq(qc->tf.protocol)) {
+		ap->ops->sff_tf_load(ap, &qc->tf);
+		sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag,
+					     SATA_DWC_CMD_ISSUED_PEND);
+	} else {
+		ata_sff_qc_issue(qc);
+	}
+
+	return 0;
+}
+
+/*
+ * Function : sata_dwc_qc_prep
+ * arguments : ata_queued_cmd *qc
+ * Return value : None
+ * qc_prep for a particular queued command
+ */
+static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
+{
+	u32 sactive;
+	u8 tag =3D qc->tag;
+
+	if ((qc->dma_dir =3D=3D DMA_NONE) || (qc->tf.protocol =3D=3D
ATA_PROT_PIO))
+		return;
+
+#ifdef DEBUG_NCQ
+	if (qc->tag > 0)
+		dev_info(qc->ap->dev, "%s: qc->tag=3D%d
ap->active_tag=3D0x%08x\n",
+			 __func__, tag, qc->ap->link.active_tag);
+#endif
+
+	if (ata_is_ncq(qc->tf.protocol)) {
+		sactive =3D core_scr_read(SCR_ACTIVE);
+		sactive |=3D (0x00000001 << tag);
+		core_scr_write(SCR_ACTIVE, sactive);
+		dev_dbg(qc->ap->dev, "%s: tag=3D%d ap->link.sactive =3D
0x%08x "
+		"sactive=3D0x%08x\n", __func__, tag, qc->ap->link.sactive,
+		 sactive);
+	} else {
+		tag =3D 0;
+	}
+
+	sata_dwc_qc_prep_by_tag(qc, tag);
+}
+
+static void sata_dwc_error_handler(struct ata_port *ap)
+{
+	ap->link.flags |=3D ATA_LFLAG_NO_HRST;
+	ata_sff_error_handler(ap);
+	ap->link.flags &=3D ~ATA_LFLAG_NO_HRST;
+}
+
+/*
+ * scsi mid-layer and libata interface structures
+ */
+static struct scsi_host_template sata_dwc_sht =3D {
+	ATA_NCQ_SHT(DRV_NAME),
+	/*
+	 * test-only: Currently this driver doesn't handle NCQ
+	 * correctly. We enable NCQ but set the queue depth to a
+	 * max of 1. This will get fixed in in a future release.
+	 */
+	.sg_tablesize		=3D LIBATA_MAX_PRD,
+	.can_queue		=3D ATA_DEF_QUEUE,	/* ATA_MAX_QUEUE
*/
+	.dma_boundary		=3D ATA_DMA_BOUNDARY,
+};
+
+static struct ata_port_operations sata_dwc_ops =3D {
+	.inherits		=3D &ata_sff_port_ops,
+
+	.error_handler		=3D sata_dwc_error_handler,
+
+	.qc_prep		=3D sata_dwc_qc_prep,
+	.qc_issue		=3D sata_dwc_qc_issue,
+
+	.scr_read		=3D sata_dwc_scr_read,
+	.scr_write		=3D sata_dwc_scr_write,
+
+	.port_start		=3D sata_dwc_port_start,
+	.port_stop		=3D sata_dwc_port_stop,
+
+	.bmdma_setup		=3D sata_dwc_bmdma_setup,
+	.bmdma_start		=3D sata_dwc_bmdma_start,
+};
+
+static const struct ata_port_info sata_dwc_port_info[] =3D {
+	{
+		.flags		=3D ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+		.pio_mask	=3D 0x1f,	/* pio 0-4 */
+		.udma_mask	=3D ATA_UDMA6,
+		.port_ops	=3D &sata_dwc_ops,
+	},
+};
+
+static int sata_dwc_probe(struct of_device *ofdev,
+			const struct of_device_id *match)
+{
+	struct sata_dwc_device *hsdev;
+	u32 idr, versionr;
+	char *ver =3D (char *) &versionr;
+	u8 *base =3D NULL;
+	int err =3D 0;
+	int irq;
+	struct ata_host *host;
+	struct ata_port_info pi =3D sata_dwc_port_info[0];
+	const struct ata_port_info *ppi[] =3D { &pi, NULL };
+	struct sata_dwc_host_priv *hp;
+	hp =3D kmalloc(sizeof(*hp), GFP_KERNEL);
+	/* Allocate DWC SATA device */
+	hsdev =3D kmalloc(sizeof(*hsdev), GFP_KERNEL);
+	if (hsdev =3D=3D NULL) {
+		dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
+		err =3D -ENOMEM;
+		goto error_out;
+	}
+	memset(hsdev, 0, sizeof(*hsdev));
+
+	/* Ioremap SATA registers */
+	base =3D of_iomap(ofdev->node, 0);
+	if (!base) {
+		dev_err(&ofdev->dev, "ioremap failed for SATA register"
+		" address\n");
+		err =3D -ENODEV;
+		goto error_out;
+	}
+	hsdev->reg_base =3D base;
+	dev_dbg(&ofdev->dev, "ioremap done for SATA register
address\n");
+
+	/* Synopsys DWC SATA specific Registers */
+	hsdev->sata_dwc_regs =3D (void *__iomem)(base +
SATA_DWC_REG_OFFSET);
+
+	/* Allocate and fill host */
+	host =3D ata_host_alloc_pinfo(&ofdev->dev, ppi,
SATA_DWC_MAX_PORTS);
+	if (!host) {
+		dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
+		err =3D -ENOMEM;
+		goto error_out;
+	}
+
+	host->private_data =3D hsdev;
+
+	/* Setup port */
+	host->ports[0]->ioaddr.cmd_addr =3D base;
+	host->ports[0]->ioaddr.scr_addr =3D base + SATA_DWC_SCR_OFFSET;
+	host_pvt.scr_addr_sstatus =3D base + SATA_DWC_SCR_OFFSET;
+	sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned
long)base);
+
+	/* Read the ID and Version Registers */
+	idr =3D in_le32(&hsdev->sata_dwc_regs->idr);
+	versionr =3D in_le32(&hsdev->sata_dwc_regs->versionr);
+	dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n",
+		   idr, ver[0], ver[1], ver[2]);
+
+	/* Get SATA DMA interrupt number */
+	irq =3D irq_of_parse_and_map(ofdev->node, 1);
+	if (irq =3D=3D NO_IRQ) {
+		dev_err(&ofdev->dev, "no SATA DMA irq\n");
+		err =3D -ENODEV;
+		goto error_out;
+	}
+
+	/* Get physical SATA DMA register base address */
+	host_pvt.sata_dma_regs =3D of_iomap(ofdev->node, 1);
+	if (!host_pvt.sata_dma_regs) {
+		dev_err(&ofdev->dev, "ioremap failed for AHBDMA
register"
+		" address\n");
+		err =3D -ENODEV;
+		goto error_out;
+	}
+
+	/* Save dev for later use in dev_xxx() routines */
+	host_pvt.dwc_dev =3D &ofdev->dev;
+
+	/* Initialize AHB DMAC */
+	dma_dwc_init(hsdev, irq);
+
+	/* Enable SATA Interrupts */
+	sata_dwc_enable_interrupts(hsdev);
+
+	/* Get SATA interrupt number */
+	irq =3D irq_of_parse_and_map(ofdev->node, 0);
+	if (irq =3D=3D NO_IRQ) {
+		dev_err(&ofdev->dev, "no SATA DMA irq\n");
+		err =3D -ENODEV;
+		goto error_out;
+	}
+
+	/*
+	 * Now, register with libATA core, this will also initiate the
+	 * device discovery process, invoking our port_start() handler &
+	 * error_handler() to execute a dummy Softreset EH session
+	 */
+	ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
+
+	dev_set_drvdata(&ofdev->dev, host);
+
+	/* Everything is fine */
+	return 0;
+
+error_out:
+	/* Free SATA DMA resources */
+	dma_dwc_exit(hsdev);
+
+	if (base)
+		iounmap(base);
+
+	kfree(hsdev);
+
+	return err;
+}
+
+static int sata_dwc_remove(struct of_device *ofdev)
+{
+	struct device *dev =3D &ofdev->dev;
+	struct ata_host *host =3D dev_get_drvdata(dev);
+	struct sata_dwc_device *hsdev =3D host->private_data;
+
+	ata_host_detach(host);
+
+	dev_set_drvdata(dev, NULL);
+
+	/* Free SATA DMA resources */
+	dma_dwc_exit(hsdev);
+
+	iounmap(hsdev->reg_base);
+	kfree(hsdev);
+	kfree(host);
+
+	dev_dbg(&ofdev->dev, "done\n");
+
+	return 0;
+}
+
+static const struct of_device_id sata_dwc_match[] =3D {
+	{ .compatible =3D "amcc,sata-460ex", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sata_dwc_match);
+
+static struct of_platform_driver sata_dwc_driver =3D {
+	.name =3D "sata-dwc",
+	.match_table =3D sata_dwc_match,
+	.probe =3D sata_dwc_probe,
+	.remove =3D sata_dwc_remove,
+};
+
+static int __init sata_dwc_init(void)
+{
+	return of_register_platform_driver(&sata_dwc_driver);
+}
+
+static void __exit sata_dwc_exit(void)
+{
+	of_unregister_platform_driver(&sata_dwc_driver);
+}
+
+module_init(sata_dwc_init);
+module_exit(sata_dwc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@appliedmicro.com>");
+MODULE_DESCRIPTION("DesignWare Cores SATA controller low lever
driver");
+MODULE_VERSION(DRV_VERSION);
--=20
1.5.6.3

^ permalink raw reply related

* Re: Problem with PCI bus rescan on 460EX
From: Kenji Kaneshige @ 2010-03-17  1:03 UTC (permalink / raw)
  To: Felix Radensky; +Cc: linux-pci, yinghai, Alex Chiang, linuxppc-dev@ozlabs.org
In-Reply-To: <4B9FFAD1.8030309@embedded-sol.com>

Felix Radensky wrote:
> Hello, Kenji-san
> 
> Kenji Kaneshige wrote:
>>
>> I misunderstood the problem.
>> My understanding was memory resource was not enabled even though Linux 
>> set
>> the Memory Space bit in the command register. But it was not correct. The
>> bridge memory window was marked unused and Linux didn't try to set Memory
>> Space bit in the command register. Current my understanding is as 
>> follows.
>> Please correct me if I'm still misunderstanding something.
>>
>> 1) Your BIOS doesn't assign any resource to the bridge if its child PCI
>>   hot-plug slot is not occupied.
>>
>> 2) At the boot time, pci_assign_unassigned_resources() try to assign
>>   memory resouces to the bridge using pci_bus_assign_resource(), but
>>   it was disabled because there are no devices require memory resource.
>>
>> 3) And then pci_assign_unassigned_resouces() calls pci_enable_bridge(),
>>   but Memory Space bit in the command register was not set because no
>>   memory resource are assigned to the bridge. At the same time,
>>   pci_dev->enable_cnt was incremented.
>>
>> 4) At the rescan time, pci_setup_bridge() and pci_enable_bridge() doesn't
>>   work because the bridge is already marked "enabled" (i.e.
>>   pci_dev->enable_cnt is not zero).
>>
>> I don't have any concrete idea how to fix that so far, but I can say 
>> my idea
>> (pcibios_enable_device() should return an error) was wrong.
>>
>>
> I was wandering if setting is_hotplug_bridge property for this bridge 
> (e.g. via
> header quirk) can be an acceptable solution. This will allow passing 
> hpmemsize
> kernel parameter, to specify the amount of memory to assign to the bridge.
> I've tested this approach and it seems to work.

Looks good to me.

By the way, I think Yinghai's bridge resource reallocation patch series
might help you. It is in Jesse's PCI tree. Please take a look.

Thanks,
Kenji Kaneshige

^ permalink raw reply

* Re: [PATCH v4 05/11] swiotlb: add swiotlb_set_default_size()
From: FUJITA Tomonori @ 2010-03-16 23:16 UTC (permalink / raw)
  To: beckyb
  Cc: x86, linux-ia64, albert_herranz, linux-usb, linux-kernel,
	fujita.tomonori, linuxppc-dev
In-Reply-To: <C200C089-E6B9-4836-A7B5-3233EB2CE5FB@kernel.crashing.org>

On Tue, 16 Mar 2010 14:28:09 -0500
Becky Bruce <beckyb@kernel.crashing.org> wrote:

> 
> On Mar 16, 2010, at 5:08 AM, FUJITA Tomonori wrote:
> 
> > On Tue, 16 Mar 2010 06:58:41 +0100
> > Albert Herranz <albert_herranz@yahoo.es> wrote:
> >
> >> FUJITA Tomonori wrote:
> >>> On Fri, 12 Mar 2010 20:12:40 +0100
> >>> Albert Herranz <albert_herranz@yahoo.es> wrote:
> >>>
> >>>> The current SWIOTLB code uses a default of 64MB for the IO TLB  
> >>>> area.
> >>>> This size can be influenced using a kernel command line parameter  
> >>>> "swiotlb".
> >>>> Unfortunately, the parsing of the kernel command line is done  
> >>>> _after_ the
> >>>> swiotlb is initialized on some architectures.
> >>>>
> >>>> This patch adds a new function swiotlb_set_default_size() which  
> >>>> can be used
> >>>> before swiotlb_init() to indicate the desired IO TLB area size in  
> >>>> bytes.
> >>>>
> >>>> This will be used later to implement a smaller IO TLB on the  
> >>>> Nintendo Wii
> >>>> video game console which just comes with 24MB + 64MB of RAM.
> >>>>
> >>>> CC: linuxppc-dev@lists.ozlabs.org
> >>>> CC: linux-kernel@vger.kernel.org
> >>>> CC: x86@kernel.org
> >>>> CC: linux-ia64@vger.kernel.org
> >>>> Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
> >>>> ---
> >>>> include/linux/swiotlb.h |    2 ++
> >>>> lib/swiotlb.c           |   20 ++++++++++++++++++++
> >>>> 2 files changed, 22 insertions(+), 0 deletions(-)
> >>>
> >>> Please fix the powerpc swiotlb initialization instead.
> >>>
> >>> Calling swiotlb_init() before parsing kernel parameters sounds
> >>> wrong. Any reasons why you can't fix it?
> >>>
> >>
> >> I think that this would be better asked by a PowerPC maintainer. Ben?
> >>
> >> If this is really a problem the swiotlb late init may be a solution  
> >> too in this particular case.
> >
> > Hmm, why swiotlb_late_init_with_default_size()?
> >
> > Why can't you initialize swiotlb in mem_init() like this (only compile
> > tested)? Any time before freeing bootmem works for swiotlb.
> 
> This is an oops in the original patchset -  I think it should be fine  
> to move the swiotlb_init later as Fujita suggests, at least for 32-bit  
> powerpc.  I just booted this on mpc8641 and everything seems OK.

Thanks!

I'll resend this patch in the proper format. This patch fixes the
problem that powerpc ignores swiotlb boot options so we can merge it
independent of Albert's patchset.

^ permalink raw reply

* [PATCH] powerpc: fix swiotlb to respect the boot option
From: FUJITA Tomonori @ 2010-03-16 23:16 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: albert_herranz, linux-kernel

powerpc initializes swiotlb before parsing the kernel boot options so
swiotlb options (e.g. specifying the swiotlb buffer size) are ignored.

Any time before freeing bootmem works for swiotlb so this patch moves
powerpc's swiotlb initialization after parsing the kernel boot
options, mem_init (as x86 does).

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Tested-by: Becky Bruce <beckyb@kernel.crashing.org>
---
 arch/powerpc/kernel/setup_32.c |    6 ------
 arch/powerpc/kernel/setup_64.c |    6 ------
 arch/powerpc/mm/mem.c          |    6 ++++++
 3 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index b152de3..8f58986 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -39,7 +39,6 @@
 #include <asm/serial.h>
 #include <asm/udbg.h>
 #include <asm/mmu_context.h>
-#include <asm/swiotlb.h>
 
 #include "setup.h"
 
@@ -343,11 +342,6 @@ void __init setup_arch(char **cmdline_p)
 		ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
-#ifdef CONFIG_SWIOTLB
-	if (ppc_swiotlb_enable)
-		swiotlb_init(1);
-#endif
-
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 6354739..9143891 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -61,7 +61,6 @@
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 #include <asm/kexec.h>
-#include <asm/swiotlb.h>
 #include <asm/mmu_context.h>
 
 #include "setup.h"
@@ -541,11 +540,6 @@ void __init setup_arch(char **cmdline_p)
 	if (ppc_md.setup_arch)
 		ppc_md.setup_arch();
 
-#ifdef CONFIG_SWIOTLB
-	if (ppc_swiotlb_enable)
-		swiotlb_init(1);
-#endif
-
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 311224c..448f972 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -48,6 +48,7 @@
 #include <asm/sparsemem.h>
 #include <asm/vdso.h>
 #include <asm/fixmap.h>
+#include <asm/swiotlb.h>
 
 #include "mmu_decl.h"
 
@@ -320,6 +321,11 @@ void __init mem_init(void)
 	struct page *page;
 	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
 
+#ifdef CONFIG_SWIOTLB
+	if (ppc_swiotlb_enable)
+		swiotlb_init(1);
+#endif
+
 	num_physpages = lmb.memory.size >> PAGE_SHIFT;
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
-- 
1.7.0

^ permalink raw reply related

* Can the OpenRB board descriptions be merged into the mainline kernel?
From: David Goodenough @ 2010-03-16 22:49 UTC (permalink / raw)
  To: linuxppc-dev

OpenWRT has some fixes which adds the board descriptions for the OpenRB
(ppc504 based boards).  Is there any reason why these should not be
merged into the mainline kernel?  The fixes are all licences GPL2.

If not do you want the original authors to submit them, or shall I take the
OpenWRT specific bits out and post them here?

David

^ permalink raw reply

* Re: Can the OpenRB board descriptions be merged into the mainline kernel?
From: Imre Kaloz @ 2010-03-16 21:58 UTC (permalink / raw)
  To: Josh Boyer, David Goodenough; +Cc: linuxppc-dev
In-Reply-To: <20100316143903.GK8963@zod.rchland.ibm.com>

On Tue, 16 Mar 2010 15:39:03 +0100, Josh Boyer <jwboyer@linux.vnet.ibm.com> wrote:

> On Tue, Mar 16, 2010 at 12:23:19PM +0000, David Goodenough wrote:
>> OpenWRT has some fixes which adds the board descriptions for the OpenRB
>> (ppc504 based boards).  Is there any reason why these should not be
>
> ppc504?  I've not heard of that one.  Is that a typo for 405?

Typo.

>> merged into the mainline kernel?  The fixes are all licences GPL2.
>>
>> If not do you want the original authors to submit them, or shall I take the
>> OpenWRT specific bits out and post them here?
>
> What exactly do you mean by "board description"?

These are part of the patches I've told you about over IRC. The port uses the
ppc40x_simple stuff with cuImage wrapper. It also has a CF connector, so
that driver needs to be merged, too..

I'll submit everything when I'm a bit better.. Spent the last two weeks in bed :/


Imre

^ permalink raw reply

* Re: Problem with PCI bus rescan on 460EX
From: Felix Radensky @ 2010-03-16 21:40 UTC (permalink / raw)
  To: Kenji Kaneshige; +Cc: linux-pci, Alex Chiang, linuxppc-dev@ozlabs.org
In-Reply-To: <4B9F19E2.2090709@jp.fujitsu.com>

Hello, Kenji-san

Kenji Kaneshige wrote:
>
> I misunderstood the problem.
> My understanding was memory resource was not enabled even though Linux 
> set
> the Memory Space bit in the command register. But it was not correct. The
> bridge memory window was marked unused and Linux didn't try to set Memory
> Space bit in the command register. Current my understanding is as 
> follows.
> Please correct me if I'm still misunderstanding something.
>
> 1) Your BIOS doesn't assign any resource to the bridge if its child PCI
>   hot-plug slot is not occupied.
>
> 2) At the boot time, pci_assign_unassigned_resources() try to assign
>   memory resouces to the bridge using pci_bus_assign_resource(), but
>   it was disabled because there are no devices require memory resource.
>
> 3) And then pci_assign_unassigned_resouces() calls pci_enable_bridge(),
>   but Memory Space bit in the command register was not set because no
>   memory resource are assigned to the bridge. At the same time,
>   pci_dev->enable_cnt was incremented.
>
> 4) At the rescan time, pci_setup_bridge() and pci_enable_bridge() doesn't
>   work because the bridge is already marked "enabled" (i.e.
>   pci_dev->enable_cnt is not zero).
>
> I don't have any concrete idea how to fix that so far, but I can say 
> my idea
> (pcibios_enable_device() should return an error) was wrong.
>
>
I was wandering if setting is_hotplug_bridge property for this bridge 
(e.g. via
header quirk) can be an acceptable solution. This will allow passing 
hpmemsize
kernel parameter, to specify the amount of memory to assign to the bridge.
I've tested this approach and it seems to work.

Thanks.
Felix.

Felix.

^ permalink raw reply

* Re: [PATCH 3/4] 8xx: Don't touch ACCESSED when no SWAP.
From: Benjamin Herrenschmidt @ 2010-03-16 21:20 UTC (permalink / raw)
  To: Joakim Tjernlund; +Cc: linuxppc-dev
In-Reply-To: <1267172983-28721-4-git-send-email-Joakim.Tjernlund@transmode.se>

On Fri, 2010-02-26 at 09:29 +0100, Joakim Tjernlund wrote:
> Only the swap function cares about the ACCESSED bit in
> the pte. Do not waste cycles updateting ACCESSED when swap
> is not compiled into the kernel.
> ---

Your changeset comment is a bit misleading since the code isn't actually
updating ACCESSED... it's testing if ACCESSED is set and goes to the
higher level fault if not (which might then update ACCESSED).

Cheers,
Ben.

>  arch/powerpc/kernel/head_8xx.S |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
> index 84ca1d9..6478a96 100644
> --- a/arch/powerpc/kernel/head_8xx.S
> +++ b/arch/powerpc/kernel/head_8xx.S
> @@ -343,10 +343,11 @@ InstructionTLBMiss:
>  	mfspr	r11, SPRN_MD_TWC	/* ....and get the pte address */
>  	lwz	r10, 0(r11)	/* Get the pte */
>  
> +#ifdef CONFIG_SWAP
>  	andi.	r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT
>  	cmpwi	cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT
>  	bne-	cr0, 2f
> -
> +#endif
>  	/* The Linux PTE won't go exactly into the MMU TLB.
>  	 * Software indicator bits 21 and 28 must be clear.
>  	 * Software indicator bits 24, 25, 26, and 27 must be
> @@ -439,10 +440,11 @@ DataStoreTLBMiss:
>  	 * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5));
>  	 * r10 = (r10 & ~PRESENT) | r11;
>  	 */
> +#ifdef CONFIG_SWAP
>  	rlwinm	r11, r10, 32-5, _PAGE_PRESENT
>  	and	r11, r11, r10
>  	rlwimi	r10, r11, 0, _PAGE_PRESENT
> -
> +#endif
>  	/* Honour kernel RO, User NA */
>  	/* 0x200 == Extended encoding, bit 22 */
>  	rlwimi	r10, r10, 32-2, 0x200 /* Copy USER to bit 22, 0x200 */

^ permalink raw reply

* Re: [PATCH 2/4] 8xx: Avoid testing for kernel space in ITLB Miss.
From: Benjamin Herrenschmidt @ 2010-03-16 21:19 UTC (permalink / raw)
  To: Joakim Tjernlund; +Cc: linuxppc-dev
In-Reply-To: <1267172983-28721-3-git-send-email-Joakim.Tjernlund@transmode.se>

On Fri, 2010-02-26 at 09:29 +0100, Joakim Tjernlund wrote:
> +#ifdef CONFIG_MODULES
> +       /* Only modules will cause ITLB Misses as we always
> +        * pin the first 8MB of kernel memory */
>         andi.   r11, r10, 0x0800        /* Address >= 0x80000000 */
>         beq     3f
>         lis     r11, swapper_pg_dir@h
>         ori     r11, r11, swapper_pg_dir@l
>         rlwimi  r10, r11, 0, 2, 19
>  3:
> +#endif

You can optimize that further I think...

You can probably just remove the code above, and add something to
do_page_fault() that lazily copies the kernel PGD entries from
swapper_pg_dir to the app pgdir. (You can even pre-fill that when
creating a new mm).

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] powerpc/perf_events: Implement perf_arch_fetch_caller_regs for powerpc
From: Frederic Weisbecker @ 2010-03-16 20:56 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: Peter Zijlstra, linux-kernel, linuxppc-dev, anton, Ingo Molnar
In-Reply-To: <20100316032213.GA3656@drongo>

On Tue, Mar 16, 2010 at 02:22:13PM +1100, Paul Mackerras wrote:
> On Mon, Mar 15, 2010 at 10:04:54PM +0100, Frederic Weisbecker wrote:
> > On Mon, Mar 15, 2010 at 04:46:15PM +1100, Paul Mackerras wrote:
> 
> > >     14.99%            perf  [kernel.kallsyms]  [k] ._raw_spin_lock
> > >                       |
> > >                       --- ._raw_spin_lock
> > >                          |          
> > >                          |--25.00%-- .alloc_fd
> > >                          |          (nil)
> > >                          |          |          
> > >                          |          |--50.00%-- .anon_inode_getfd
> > >                          |          |          .sys_perf_event_open
> > >                          |          |          syscall_exit
> > >                          |          |          syscall
> > >                          |          |          create_counter
> > >                          |          |          __cmd_record
> > >                          |          |          run_builtin
> > >                          |          |          main
> > >                          |          |          0xfd2e704
> > >                          |          |          0xfd2e8c0
> > >                          |          |          (nil)
> > > 
> > > ... etc.
> > > 
> > > Signed-off-by: Paul Mackerras <paulus@samba.org>
> > 
> > 
> > Cool!
> 
> By the way, I notice that gcc tends to inline the tracing functions,
> which means that by going up 2 stack frames we miss some of the
> functions.  For example, for the lock:lock_acquire event, we have
> _raw_spin_lock() -> lock_acquire() -> trace_lock_acquire() ->
> perf_trace_lock_acquire() -> perf_trace_templ_lock_acquire() ->
> perf_fetch_caller_regs() -> perf_arch_fetch_caller_regs().
> 
> But in the ppc64 kernel binary I just built, gcc inlined
> trace_lock_acquire in lock_acquire, and perf_trace_templ_lock_acquire
> in perf_trace_lock_acquire.  Given that perf_fetch_caller_regs is
> explicitly inlined, going up two levels from perf_fetch_caller_regs
> gets us to _raw_spin_lock, whereas I think you intended it to get us
> to trace_lock_acquire.  I'm not sure what to do about that - any
> thoughts?



Yeah I've indeed seen this, and the problem is especially
the fact perf_trace_templ_lock_acquire may or may not be
inlined.

It is used for trace events that use the TRACE_EVENT_CLASS
thing. We define a pattern of event structure that is shared
among several events.

For example event A and event B share perf_trace_templ_foo.
Both will have a different perf_trace_blah but those
perf_trace_blah will both call the same perf_trace_templ_foo(),
in this case, it won't be inlined.

Events that don't share a pattern will have their
perf_trace_templ inlined, because there will be an exclusive 1:1
relationship between both.

The rewind of 2 is well suited for events sharing a pattern, ip
will match the right event source, and not one of its callers.

Unfortunately, the others are more unlucky.
I didn't mind much about this yet because it  had no bad effect
on lock events. Quite the opposite actually. It's not very interesting
to have lock_acquire as the event source unless you have a callchain.

If you have no callchain, you'll see a lot of such in perf report:

sym1	lock_aquire
sym2	lock_acquire
sym3	lock_acquire

What you want here is the function that called lock_acquire.

But if you have a callchain it's fine, because you have the nature
of the event (lock_aquire) and the origin as well.

That said, lock events are an exception where the mistake
has a lucky result. Other inlined events are harmed as we lose
their most important caller. So I'm going to fix that.

I can just fetch the regs from perf_trace_foo() and pass them
to perf_trace_templ_foo() and here we are.

Thanks.

^ permalink raw reply

* Re: [PATCH v4 05/11] swiotlb: add swiotlb_set_default_size()
From: Becky Bruce @ 2010-03-16 19:28 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: x86, linux-ia64, albert_herranz, linux-usb, linux-kernel,
	linuxppc-dev
In-Reply-To: <20100316190805Z.fujita.tomonori@lab.ntt.co.jp>


On Mar 16, 2010, at 5:08 AM, FUJITA Tomonori wrote:

> On Tue, 16 Mar 2010 06:58:41 +0100
> Albert Herranz <albert_herranz@yahoo.es> wrote:
>
>> FUJITA Tomonori wrote:
>>> On Fri, 12 Mar 2010 20:12:40 +0100
>>> Albert Herranz <albert_herranz@yahoo.es> wrote:
>>>
>>>> The current SWIOTLB code uses a default of 64MB for the IO TLB  
>>>> area.
>>>> This size can be influenced using a kernel command line parameter  
>>>> "swiotlb".
>>>> Unfortunately, the parsing of the kernel command line is done  
>>>> _after_ the
>>>> swiotlb is initialized on some architectures.
>>>>
>>>> This patch adds a new function swiotlb_set_default_size() which  
>>>> can be used
>>>> before swiotlb_init() to indicate the desired IO TLB area size in  
>>>> bytes.
>>>>
>>>> This will be used later to implement a smaller IO TLB on the  
>>>> Nintendo Wii
>>>> video game console which just comes with 24MB + 64MB of RAM.
>>>>
>>>> CC: linuxppc-dev@lists.ozlabs.org
>>>> CC: linux-kernel@vger.kernel.org
>>>> CC: x86@kernel.org
>>>> CC: linux-ia64@vger.kernel.org
>>>> Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
>>>> ---
>>>> include/linux/swiotlb.h |    2 ++
>>>> lib/swiotlb.c           |   20 ++++++++++++++++++++
>>>> 2 files changed, 22 insertions(+), 0 deletions(-)
>>>
>>> Please fix the powerpc swiotlb initialization instead.
>>>
>>> Calling swiotlb_init() before parsing kernel parameters sounds
>>> wrong. Any reasons why you can't fix it?
>>>
>>
>> I think that this would be better asked by a PowerPC maintainer. Ben?
>>
>> If this is really a problem the swiotlb late init may be a solution  
>> too in this particular case.
>
> Hmm, why swiotlb_late_init_with_default_size()?
>
> Why can't you initialize swiotlb in mem_init() like this (only compile
> tested)? Any time before freeing bootmem works for swiotlb.

This is an oops in the original patchset -  I think it should be fine  
to move the swiotlb_init later as Fujita suggests, at least for 32-bit  
powerpc.  I just booted this on mpc8641 and everything seems OK.

-Becky

>
>
> diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/ 
> setup_32.c
> index b152de3..8f58986 100644
> --- a/arch/powerpc/kernel/setup_32.c
> +++ b/arch/powerpc/kernel/setup_32.c
> @@ -39,7 +39,6 @@
> #include <asm/serial.h>
> #include <asm/udbg.h>
> #include <asm/mmu_context.h>
> -#include <asm/swiotlb.h>
>
> #include "setup.h"
>
> @@ -343,11 +342,6 @@ void __init setup_arch(char **cmdline_p)
> 		ppc_md.setup_arch();
> 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
>
> -#ifdef CONFIG_SWIOTLB
> -	if (ppc_swiotlb_enable)
> -		swiotlb_init(1);
> -#endif
> -
> 	paging_init();
>
> 	/* Initialize the MMU context management stuff */
> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/ 
> setup_64.c
> index 6354739..9143891 100644
> --- a/arch/powerpc/kernel/setup_64.c
> +++ b/arch/powerpc/kernel/setup_64.c
> @@ -61,7 +61,6 @@
> #include <asm/xmon.h>
> #include <asm/udbg.h>
> #include <asm/kexec.h>
> -#include <asm/swiotlb.h>
> #include <asm/mmu_context.h>
>
> #include "setup.h"
> @@ -541,11 +540,6 @@ void __init setup_arch(char **cmdline_p)
> 	if (ppc_md.setup_arch)
> 		ppc_md.setup_arch();
>
> -#ifdef CONFIG_SWIOTLB
> -	if (ppc_swiotlb_enable)
> -		swiotlb_init(1);
> -#endif
> -
> 	paging_init();
>
> 	/* Initialize the MMU context management stuff */
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 311224c..448f972 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -48,6 +48,7 @@
> #include <asm/sparsemem.h>
> #include <asm/vdso.h>
> #include <asm/fixmap.h>
> +#include <asm/swiotlb.h>
>
> #include "mmu_decl.h"
>
> @@ -320,6 +321,11 @@ void __init mem_init(void)
> 	struct page *page;
> 	unsigned long reservedpages = 0, codesize, initsize, datasize,  
> bsssize;
>
> +#ifdef CONFIG_SWIOTLB
> +	if (ppc_swiotlb_enable)
> +		swiotlb_init(1);
> +#endif
> +
> 	num_physpages = lmb.memory.size >> PAGE_SHIFT;
> 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux- 
> kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* RE: Failure with the 2.6.34-rc1 kernel
From: Jiri Kosina @ 2010-03-16 16:26 UTC (permalink / raw)
  To: Rupjyoti Sarmah; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <AC311A8E81420D4EBC1F26E6479848FE065B7D5B@SDCEXCHANGE01.ad.amcc.com>

On Tue, 16 Mar 2010, Rupjyoti Sarmah wrote:

> -----Original Message-----
> From: Jiri Kosina [mailto:jkosina@suse.cz] 
> Sent: Tuesday, March 16, 2010 9:18 PM
> To: Rupjyoti Sarmah
> Cc: linux-kernel@vger.kernel.org
> Subject: Re: Failure with the 2.6.34-rc1 kernel
> 
> On Tue, 16 Mar 2010, Rupjyoti Sarmah wrote:
> 
> > We are seeing issues in booting some of our boards with this new
> kernel.
> > Kernel version upto 2.6.33 works fine on the boards like Canyonlands,
> > Katmai, Glacier etc.
> > These boards are not booting with kernel later than 2.6.33. Please let
> > me know how about fixing these issues ?
> 
> You'd need to provide at least dmesg from the working and non-working 
> cases.
> 
> Also git-bisect between 2.6.33 and 2.6.34-rc1 might help you identify
> the 
> commit that broke your hardware.

> It has been failing from this commit.
> 
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commi
> t;h=ef1a8de8ea004a689b2aa9f5cefcba2b1a0262f2 .
> 
> Also, the u-boot restarts the board very quickly. It does not go to the
> kernel prompt at all. 
> 

That is a merge commit. There must be actuall non-merge commit that
introduced the change.

If you are sure that this particular commit brought in the change that
broke your system, you can do git bisect between
00ebfe58b002f0ff387f60c7cd23bc2b274fce1a and
ef1a8de8ea004a689b2aa9f5cefcba2b1a0262f2 to see which of the 88 commits
merged as part of ef1a8de8ea004a689b2aa9f5cefcba2b1a0262f2 is the actual
culprit.

Also adding linuxpcc-dev@ to CC.

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply

* Re: Can the OpenRB board descriptions be merged into the mainline kernel?
From: Josh Boyer @ 2010-03-16 14:39 UTC (permalink / raw)
  To: David Goodenough; +Cc: linuxppc-dev
In-Reply-To: <201003161223.19238.david.goodenough@btconnect.com>

On Tue, Mar 16, 2010 at 12:23:19PM +0000, David Goodenough wrote:
>OpenWRT has some fixes which adds the board descriptions for the OpenRB
>(ppc504 based boards).  Is there any reason why these should not be

ppc504?  I've not heard of that one.  Is that a typo for 405?

>merged into the mainline kernel?  The fixes are all licences GPL2.
>
>If not do you want the original authors to submit them, or shall I take the
>OpenWRT specific bits out and post them here?

What exactly do you mean by "board description"?

josh

^ permalink raw reply

* Can the OpenRB board descriptions be merged into the mainline kernel?
From: David Goodenough @ 2010-03-16 12:23 UTC (permalink / raw)
  To: linuxppc-dev

OpenWRT has some fixes which adds the board descriptions for the OpenRB
(ppc504 based boards).  Is there any reason why these should not be
merged into the mainline kernel?  The fixes are all licences GPL2.

If not do you want the original authors to submit them, or shall I take the
OpenWRT specific bits out and post them here?

David

^ permalink raw reply

* Re: [PATCH 0/4] Some typo fixing
From: Jiri Kosina @ 2010-03-16 10:32 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: Karsten Keil, Lin Ming, Takashi Iwai, Jaroslav Kysela,
	Pavel Machek, David Brownell, linux-acpi, KOSAKI Motohiro,
	Bjorn Helgaas, Rusty Russell, Li Zefan, Steve Conklin,
	Ralph Campbell, Anton Vorontsov, cbe-oss-dev, KAMEZAWA Hiroyuki,
	Liam Girdwood, Anthony Liguori, linux-kernel, Joe Perches,
	Andrew Morton, linux-media, Pieter Palmers, Anand Gadiyar,
	alsa-devel, linux-doc, David Airlie, Clemens Ladisch, linux-mm,
	James E.J. Bottomley, Håkan Johansson, linux-s390,
	Markus Heidelberg, linuxppc-dev, Dave Airlie, Tobias Klauser,
	dri-devel, Hal Rosenstock, Len Brown, linux-kbuild,
	Mauro Carvalho Chehab, Rafael J. Wysocki, Amit Shah, Daniel Mack,
	spi-devel-general, containers, Mark Brown, Martin Schwidefsky,
	linux390, Michal Sojka, Christoph Lameter, linux-pci,
	Heiko Carstens, Jesse Barnes, Kenji Kaneshige, Dave Kleikamp,
	Sean Hefty, Sam Ravnborg, linux-rdma, Matthew Wilcox, Ingo Molnar,
	Jeff Garzik, Alexey Dobriyan, Alex Chiang, Mel Gorman,
	Zhenyu Wang, Pekka Enberg, Jing Huang, Jiri Pirko,
	Greg Kroah-Hartman, Stefan Richter, Jean Delvare, Tejun Heo,
	David S. Miller, jfs-discussion, Jay Fenlason,
	Bartlomiej Zolnierkiewicz, Michael S. Tsirkin, Henrik Austad,
	linux-ide, Jonathan Cameron, Bernhard Schiffner, linux1394-devel,
	devel, Amit Kucheria, Douglas Schilling Landgraf, linux-scsi,
	Yu Zhao, André Goddard Rosa, Shirley Ma, Thomas Weber,
	Steve Glendinning, Paul Menage, Alan Cox, Michal Marek,
	Michal Simek, Ben Blum, netdev, Akihiro Tsukada, Johannes Berg,
	Inaky Perez-Gonzalez, Larry Finger
In-Reply-To: <4B9EA214.7010203@xenotime.net>

On Mon, 15 Mar 2010, Randy Dunlap wrote:

> > I have fixed some typos.
> 
> Acked-by: Randy Dunlap <rdunlap@xenotime.net>
> 
> Jiri, can you merge these, please, unless someone objects (?).

Yes, I will take it, thanks. A couple comments though:

- [important!] Thomas, it's not necessary to CC zillions of people on such 
  patches. Just submit them to trivial@kernel.org (and eventually CC 
  lkml), and that's it. I believe many people might get annoyed by this.
- I will not be applying the drivers/staging hunks. Staging patches are 
  moving target, the code is changing quickly (including complete 
  drops/rewrites) so we'll likely be getting conflicts there. I will 
  reroute them to Greg.
- I will fold all the patches into one. We don't need one commit per one 
  specific typo.

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply

* Re: [PATCH v4 05/11] swiotlb: add swiotlb_set_default_size()
From: FUJITA Tomonori @ 2010-03-16 10:08 UTC (permalink / raw)
  To: albert_herranz
  Cc: linux-usb, linux-ia64, x86, linux-kernel, fujita.tomonori,
	linuxppc-dev
In-Reply-To: <4B9F1E11.80201@yahoo.es>

On Tue, 16 Mar 2010 06:58:41 +0100
Albert Herranz <albert_herranz@yahoo.es> wrote:

> FUJITA Tomonori wrote:
> > On Fri, 12 Mar 2010 20:12:40 +0100
> > Albert Herranz <albert_herranz@yahoo.es> wrote:
> > 
> >> The current SWIOTLB code uses a default of 64MB for the IO TLB area.
> >> This size can be influenced using a kernel command line parameter "swiotlb".
> >> Unfortunately, the parsing of the kernel command line is done _after_ the
> >> swiotlb is initialized on some architectures.
> >>
> >> This patch adds a new function swiotlb_set_default_size() which can be used
> >> before swiotlb_init() to indicate the desired IO TLB area size in bytes.
> >>
> >> This will be used later to implement a smaller IO TLB on the Nintendo Wii
> >> video game console which just comes with 24MB + 64MB of RAM.
> >>
> >> CC: linuxppc-dev@lists.ozlabs.org
> >> CC: linux-kernel@vger.kernel.org
> >> CC: x86@kernel.org
> >> CC: linux-ia64@vger.kernel.org
> >> Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
> >> ---
> >>  include/linux/swiotlb.h |    2 ++
> >>  lib/swiotlb.c           |   20 ++++++++++++++++++++
> >>  2 files changed, 22 insertions(+), 0 deletions(-)
> > 
> > Please fix the powerpc swiotlb initialization instead.
> > 
> > Calling swiotlb_init() before parsing kernel parameters sounds
> > wrong. Any reasons why you can't fix it?
> > 
> 
> I think that this would be better asked by a PowerPC maintainer. Ben?
> 
> If this is really a problem the swiotlb late init may be a solution too in this particular case.

Hmm, why swiotlb_late_init_with_default_size()?

Why can't you initialize swiotlb in mem_init() like this (only compile
tested)? Any time before freeing bootmem works for swiotlb.


diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index b152de3..8f58986 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -39,7 +39,6 @@
 #include <asm/serial.h>
 #include <asm/udbg.h>
 #include <asm/mmu_context.h>
-#include <asm/swiotlb.h>
 
 #include "setup.h"
 
@@ -343,11 +342,6 @@ void __init setup_arch(char **cmdline_p)
 		ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
-#ifdef CONFIG_SWIOTLB
-	if (ppc_swiotlb_enable)
-		swiotlb_init(1);
-#endif
-
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 6354739..9143891 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -61,7 +61,6 @@
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 #include <asm/kexec.h>
-#include <asm/swiotlb.h>
 #include <asm/mmu_context.h>
 
 #include "setup.h"
@@ -541,11 +540,6 @@ void __init setup_arch(char **cmdline_p)
 	if (ppc_md.setup_arch)
 		ppc_md.setup_arch();
 
-#ifdef CONFIG_SWIOTLB
-	if (ppc_swiotlb_enable)
-		swiotlb_init(1);
-#endif
-
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 311224c..448f972 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -48,6 +48,7 @@
 #include <asm/sparsemem.h>
 #include <asm/vdso.h>
 #include <asm/fixmap.h>
+#include <asm/swiotlb.h>
 
 #include "mmu_decl.h"
 
@@ -320,6 +321,11 @@ void __init mem_init(void)
 	struct page *page;
 	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
 
+#ifdef CONFIG_SWIOTLB
+	if (ppc_swiotlb_enable)
+		swiotlb_init(1);
+#endif
+
 	num_physpages = lmb.memory.size >> PAGE_SHIFT;
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 

^ permalink raw reply related

* Re: [PATCH] irq: move some interrupt arch_* functions into struct irq_chip.
From: Eric W. Biederman @ 2010-03-16  9:18 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Jeremy Fitzhardinge, x86@kernel.org, linux-kernel@vger.kernel.org,
	linuxppc-dev@ozlabs.org, Ingo Molnar, Paul Mackerras,
	H. Peter Anvin, Thomas Gleixner, Yinghai Lu
In-Reply-To: <1268729412.8652.4254.camel@localhost.localdomain>

Ian Campbell <Ian.Campbell@citrix.com> writes:

> On Sat, 2010-03-13 at 00:29 +0000, Eric W. Biederman wrote: 
>> [...]
>> > after that xen could use
>> > irq_to_desc_alloc_node_f(irq, node, xen_init_chip_data);
>> >
>> > as need...
>> >
>> > at last we don't need to call x86_init_chip_data everywhere.
>
> This was one of the things I was considering. It seems like one of the
> easiest solutions to make work correctly with the current locking in
> e.g. irq_to_desc_alloc_node since the callback would always happen under
> the lock taken in that function.
>
>> So trying to evaluate races.  The worse case for this particular piece
>> of code appears to be create_irq_nr.  As this is the only place where
>> we are setting up irqs and possibly repurposing the structure.
>
> Yes, create_irq_nr was one of the functions I was struggling to solve
> cleanly. There is a similar construct in the Xen code as well.
>
> Part of the problem I'm having is the combination of lookup and allocate
> in irq_to_desc_alloc_node but also the kind of "implicit" repurposing is
> tricky to deal with. (by implicit I just mean that I can't find where
> the previous user explicitly says they are finished with it, if you see
> what I mean)
>
> What do you think of adding an explicit free operation for the irq_desc
> structs? (does one already exist? I couldn't find it). This would go
> along with some tracking of allocation state, trivial in the sparse case
> where you can treat a NULL node in the radix tree as unallocated, I
> guess a flag would suffice in the static array non-sparse case?

We have free_one_irq_desc used in the numa irq migration code.
We have dynamic_irq_cleanup.

I don't expect it would be fundamentally hard to put all of the pieces
together.

> Going further could we split the alloc and lookup functions into
> separate operations instead of combining them in irq_to_desc_alloc_node?
> We already have irq_to_desc for the lookup portion so this would largely
> involve changes to the semantics of irq_to_desc_alloc_node, perhaps
> returning ERR_PTR(-EBUSY) if the node was already allocated.
>
> Having a variant which found a free IRQ rather than operating on a
> specific requested IRQ could also be useful for create_irq_nr as well as
> find_unbound_irq on the Xen side. I'm not convinced irq_alloc_virt on
> powerpc isn't implementing broadly the same concept as well, although it
> seems to work very differently from the other two.
>
>>   Today
>> we figure out if an irq has been assigned by looking at irq_cfg->vector,
>> and if it is non-zero the irq has been assigned.
>
> Which is tricky to move into generic code hence my suggestions of
> explicitly freeing the irq_desc and tracking the allocation status in
> the generic code. 

Agreed.  Getting an allocation assist into the generic code sounds
nlike something for the next round of patches after your current one.
At least for msi irqs, hi irqs and other irqs that are totally software
constructs this makes a lot of sense.

We really need to get to the point on x86 where sparse irq has no penalties
and stop making it an option.  Otherwise it gets a bit tricky to rely
on sparse irq for an allocation helper.

I need to go look up my old patchset.  I did something different with
create_irq(), that I think was cleaner and it may be worth resurrecting.
At the very least I generalized the msi case and the ht irq case into
using the same pointer in struct irq_desc.

>> The logic in x86_init_chip_data is correct we only assign desc->chip_data
>> if the generic layers are above it.  However we need a lock to ensure that
>> two paths don't race in that comparison and that assignment.  There is
>> no lock in x86_init_chip_data.  Which unfortunately means as it stands
>> this patchset is buggy.
>
> Yes, unfortunately I think you are right. The callback idea fixes this.
> I'll respin with that.

Thanks.

Eric

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox