* [V2 1/5] powerpc: dts: klondike: Add AHB, APB bus; remove OPB bus
From: Tanmay Inamdar @ 2012-04-09 7:20 UTC (permalink / raw)
To: benh, jwboyer, grant.likely, linuxppc-dev, linux-kernel,
devicetree-discuss
Cc: Tanmay Inamdar
Add entries in klondike device tree for AHB and APB bus and remove entry for
non-existent OPB bus inherited from legacy code.
Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
---
:100644 100644 8c94290... 4ff2852... M arch/powerpc/boot/dts/klondike.dts
arch/powerpc/boot/dts/klondike.dts | 167 ++++++++++++++++++-----------------
1 files changed, 86 insertions(+), 81 deletions(-)
diff --git a/arch/powerpc/boot/dts/klondike.dts b/arch/powerpc/boot/dts/klondike.dts
index 8c94290..4ff2852 100644
--- a/arch/powerpc/boot/dts/klondike.dts
+++ b/arch/powerpc/boot/dts/klondike.dts
@@ -132,96 +132,101 @@
/*RXDE*/ 0x3 0x4>;
};
- POB0: opb {
- compatible = "ibm,opb";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges = <0x20000000 0x20000000 0x30000000
- 0x50000000 0x50000000 0x10000000
- 0x60000000 0x60000000 0x10000000
- 0xFE000000 0xFE000000 0x00010000>;
- dcr-reg = <0x100 0x020>;
- clock-frequency = <300000000>; /* Filled in by U-Boot */
+ RGMII0: emac-rgmii@400a2000 {
+ compatible = "ibm,rgmii";
+ reg = <0x400a2000 0x00000010>;
+ has-mdio;
+ };
- RGMII0: emac-rgmii@400a2000 {
- compatible = "ibm,rgmii";
- reg = <0x400a2000 0x00000010>;
- has-mdio;
- };
+ TAH0: emac-tah@400a3000 {
+ compatible = "ibm,tah";
+ reg = <0x400a3000 0x100>;
+ };
- TAH0: emac-tah@400a3000 {
- compatible = "ibm,tah";
- reg = <0x400a3000 0x100>;
- };
+ TAH1: emac-tah@400a4000 {
+ compatible = "ibm,tah";
+ reg = <0x400a4000 0x100>;
+ };
- TAH1: emac-tah@400a4000 {
- compatible = "ibm,tah";
- reg = <0x400a4000 0x100>;
- };
+ EMAC0: ethernet@400a0000 {
+ compatible = "ibm,emac4", "ibm-emac4sync";
+ interrupt-parent = <&EMAC0>;
+ interrupts = <0x0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC0 0x13 0x4>;
+ reg = <0x400a0000 0x00000100>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0x0>;
+ mal-rx-channel = <0x0>;
+ cell-index = <0>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ phy-mode = "rgmii";
+ phy-address = <0x2>;
+ turbo = "no";
+ phy-map = <0x00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <0>;
+ tah-device = <&TAH0>;
+ tah-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
- EMAC0: ethernet@400a0000 {
- compatible = "ibm,emac4", "ibm-emac4sync";
- interrupt-parent = <&EMAC0>;
- interrupts = <0x0>;
- #interrupt-cells = <1>;
- #address-cells = <0>;
- #size-cells = <0>;
- interrupt-map = </*Status*/ 0x0 &UIC0 0x13 0x4>;
- reg = <0x400a0000 0x00000100>;
- local-mac-address = [000000000000]; /* Filled in by U-Boot */
- mal-device = <&MAL0>;
- mal-tx-channel = <0x0>;
- mal-rx-channel = <0x0>;
- cell-index = <0>;
- max-frame-size = <9000>;
- rx-fifo-size = <4096>;
- tx-fifo-size = <2048>;
- phy-mode = "rgmii";
- phy-address = <0x2>;
- turbo = "no";
- phy-map = <0x00000000>;
- rgmii-device = <&RGMII0>;
- rgmii-channel = <0>;
- tah-device = <&TAH0>;
- tah-channel = <0>;
- has-inverted-stacr-oc;
- has-new-stacr-staopc;
- };
+ EMAC1: ethernet@400a1000 {
+ compatible = "ibm,emac4", "ibm-emac4sync";
+ status = "disabled";
+ interrupt-parent = <&EMAC1>;
+ interrupts = <0x0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC0 0x14 0x4>;
+ reg = <0x400a1000 0x00000100>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <1>;
+ mal-rx-channel = <8>;
+ cell-index = <1>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ phy-mode = "rgmii";
+ phy-address = <0x3>;
+ turbo = "no";
+ phy-map = <0x00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <1>;
+ tah-device = <&TAH1>;
+ tah-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ mdio-device = <&EMAC0>;
+ };
- EMAC1: ethernet@400a1000 {
- compatible = "ibm,emac4", "ibm-emac4sync";
- status = "disabled";
- interrupt-parent = <&EMAC1>;
- interrupts = <0x0>;
- #interrupt-cells = <1>;
- #address-cells = <0>;
- #size-cells = <0>;
- interrupt-map = </*Status*/ 0x0 &UIC0 0x14 0x4>;
- reg = <0x400a1000 0x00000100>;
- local-mac-address = [000000000000]; /* Filled in by U-Boot */
- mal-device = <&MAL0>;
- mal-tx-channel = <1>;
- mal-rx-channel = <8>;
- cell-index = <1>;
- max-frame-size = <9000>;
- rx-fifo-size = <4096>;
- tx-fifo-size = <2048>;
- phy-mode = "rgmii";
- phy-address = <0x3>;
- turbo = "no";
- phy-map = <0x00000000>;
- rgmii-device = <&RGMII0>;
- rgmii-channel = <1>;
- tah-device = <&TAH1>;
- tah-channel = <0>;
- has-inverted-stacr-oc;
- has-new-stacr-staopc;
- mdio-device = <&EMAC0>;
+ AHB: ahb {
+ compatible = "apm,ahb";
+ dcr-reg = <0xc 0x2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ APB: apb {
+ compatible = "apm,apb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>;
};
};
};
chosen {
- linux,stdout-path = "/plb/opb/serial@50001000";
+ linux,stdout-path = "/plb/ahb/apb/serial@50001000";
};
};
--
1.6.1.rc3
^ permalink raw reply related
* [PATCH] driver/mtd: IFC NAND: Add support of ONFI NAND flash
From: Prabhakar Kushwaha @ 2012-04-09 5:25 UTC (permalink / raw)
To: linuxppc-dev, linux-mtd; +Cc: scottwood, Prabhakar Kushwaha, dedekind1
- Fix NAND_CMD_READID command for ONFI detect.
- Add NAND_CMD_PARAM command to read the ONFI parameter page.
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
Acked-by: Scott Wood <scottwood@freescale.com>
---
Based upon git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Branch master
drivers/mtd/nand/fsl_ifc_nand.c | 22 ++++++++++++++++------
1 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index c30ac7b..4e7f31e 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -375,21 +375,31 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
return;
- /* READID must read all 8 possible bytes */
case NAND_CMD_READID:
+ case NAND_CMD_PARAM: {
+ int timing = IFC_FIR_OP_RB;
+ if (command == NAND_CMD_PARAM)
+ timing = IFC_FIR_OP_RBCD;
+
out_be32(&ifc->ifc_nand.nand_fir0,
(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
- (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+ (timing << IFC_NAND_FIR0_OP2_SHIFT));
out_be32(&ifc->ifc_nand.nand_fcr0,
- NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
- /* 8 bytes for manuf, device and exts */
- out_be32(&ifc->ifc_nand.nand_fbcr, 8);
- ifc_nand_ctrl->read_bytes = 8;
+ command << IFC_NAND_FCR0_CMD0_SHIFT);
+ out_be32(&ifc->ifc_nand.row3, column);
+
+ /*
+ * although currently it's 8 bytes for READID, we always read
+ * the maximum 256 bytes(for PARAM)
+ */
+ out_be32(&ifc->ifc_nand.nand_fbcr, 256);
+ ifc_nand_ctrl->read_bytes = 256;
set_addr(mtd, 0, 0, 0);
fsl_ifc_run_command(mtd);
return;
+ }
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1:
--
1.7.5.4
^ permalink raw reply related
* Re: [PATCH 2/2] powerpc/44x: Add PCI MSI node for APM821xx SoC and Bluestone board in DTS
From: Mai La @ 2012-04-09 4:27 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Josh Boyer, Matt Porter,
Tirumala R Marri, Grant Likely, Michael Neuling, Kumar Gala,
Anton Blanchard, linuxppc-dev, linux-kernel
In-Reply-To: <1330505263-3718-1-git-send-email-mla@apm.com>
[-- Attachment #1: Type: text/plain, Size: 1904 bytes --]
This patch is along with patch [1/2, v4] powerpc/44x: Fix PCI MSI support
for Maui APM821xx SoC and Bluestone board. Do you have any comment for this
patch?
Thank you!
On Wed, Feb 29, 2012 at 3:47 PM, Mai La <mla@apm.com> wrote:
>
> Signed-off-by: Mai La <mla@apm.com>
> ---
> arch/powerpc/boot/dts/bluestone.dts | 24 ++++++++++++++++++++++++
> 1 files changed, 24 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/boot/dts/bluestone.dts
> b/arch/powerpc/boot/dts/bluestone.dts
> index 2a56a0d..8ea6325 100644
> --- a/arch/powerpc/boot/dts/bluestone.dts
> +++ b/arch/powerpc/boot/dts/bluestone.dts
> @@ -250,5 +250,29 @@
> };
> };
>
> + MSI: ppc4xx-msi@C10000000 {
> + compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
> + reg = < 0xC 0x10000000 0x100
> + 0xC 0x10000000 0x100>;
> + sdr-base = <0x36C>;
> + msi-data = <0x00004440>;
> + msi-mask = <0x0000ffe0>;
> + interrupts =<0 1 2 3 4 5 6 7>;
> + interrupt-parent = <&MSI>;
> + #interrupt-cells = <1>;
> + #address-cells = <0>;
> + #size-cells = <0>;
> + msi-available-ranges = <0x0 0x100>;
> + interrupt-map = <
> + 0 &UIC3 0x18 1
> + 1 &UIC3 0x19 1
> + 2 &UIC3 0x1A 1
> + 3 &UIC3 0x1B 1
> + 4 &UIC3 0x1C 1
> + 5 &UIC3 0x1D 1
> + 6 &UIC3 0x1E 1
> + 7 &UIC3 0x1F 1
> + >;
> + };
> };
> };
> --
> 1.7.3.4
>
>
[-- Attachment #2: Type: text/html, Size: 2505 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] [v4] powerpc/44x: Fix PCI MSI support for Maui APM821xx SoC and Bluestone board
From: Mai La @ 2012-04-09 4:23 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Josh Boyer, Matt Porter,
Tirumala R Marri, Grant Likely, Michael Neuling, Kumar Gala,
Anton Blanchard, linuxppc-dev, linux-kernel
In-Reply-To: <1332129548-20379-1-git-send-email-mla@apm.com>
[-- Attachment #1: Type: text/plain, Size: 6558 bytes --]
Do you have any further comment for this patch?
On Mon, Mar 19, 2012 at 10:59 AM, Mai La <mla@apm.com> wrote:
> This patch consists of:
> - Enable PCI MSI as default for Bluestone board
> - Change definition of number of MSI interrupts as it depends on SoC
> - Fix returning ENODEV as finding MSI node
> - Fix MSI physical high and low address
> - Keep MSI data logically
>
> Signed-off-by: Mai La <mla@apm.com>
>
> ---
> v4:
> Per Josh Boyer's comment:
> * Declare msi_irqs as static
> * Handle error if allocation of MSI vitual interrupts fails
> * Return ENODEV if counting MSI interrupts fails
> v3:
> * Use upper_32_bits() / lower_32_bits() consistently as Wolfgang Denk
> recomments
> v2:
> * Change definition of number of MSI interrupt from config to count
> interrupts in device tree
>
> ---
> arch/powerpc/platforms/44x/Kconfig | 2 +
> arch/powerpc/sysdev/ppc4xx_msi.c | 42
> ++++++++++++++++++++++++------------
> 2 files changed, 30 insertions(+), 14 deletions(-)
>
> diff --git a/arch/powerpc/platforms/44x/Kconfig
> b/arch/powerpc/platforms/44x/Kconfig
> index fcf6bf2..9f04ce3 100644
> --- a/arch/powerpc/platforms/44x/Kconfig
> +++ b/arch/powerpc/platforms/44x/Kconfig
> @@ -23,6 +23,8 @@ config BLUESTONE
> default n
> select PPC44x_SIMPLE
> select APM821xx
> + select PCI_MSI
> + select PPC4xx_MSI
> select IBM_EMAC_RGMII
> help
> This option enables support for the APM APM821xx Evaluation board.
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c
> b/arch/powerpc/sysdev/ppc4xx_msi.c
> index 1c2d7af..cc17f59 100644
> --- a/arch/powerpc/sysdev/ppc4xx_msi.c
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.c
> @@ -28,10 +28,11 @@
> #include <linux/of_platform.h>
> #include <linux/interrupt.h>
> #include <linux/export.h>
> +#include <linux/kernel.h>
> #include <asm/prom.h>
> #include <asm/hw_irq.h>
> #include <asm/ppc-pci.h>
> -#include <boot/dcr.h>
> +#include <asm/dcr.h>
> #include <asm/dcr-regs.h>
> #include <asm/msi_bitmap.h>
>
> @@ -43,13 +44,14 @@
> #define PEIH_FLUSH0 0x30
> #define PEIH_FLUSH1 0x38
> #define PEIH_CNTRST 0x48
> -#define NR_MSI_IRQS 4
> +
> +static int msi_irqs;
>
> struct ppc4xx_msi {
> u32 msi_addr_lo;
> u32 msi_addr_hi;
> void __iomem *msi_regs;
> - int msi_virqs[NR_MSI_IRQS];
> + int *msi_virqs;
> struct msi_bitmap bitmap;
> struct device_node *msi_dev;
> };
> @@ -61,7 +63,7 @@ static int ppc4xx_msi_init_allocator(struct
> platform_device *dev,
> {
> int err;
>
> - err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> + err = msi_bitmap_alloc(&msi_data->bitmap, msi_irqs,
> dev->dev.of_node);
> if (err)
> return err;
> @@ -83,6 +85,11 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev,
> int nvec, int type)
> struct msi_desc *entry;
> struct ppc4xx_msi *msi_data = &ppc4xx_msi;
>
> + msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int),
> + GFP_KERNEL);
> + if (!msi_data->msi_virqs)
> + return -ENOMEM;
> +
> list_for_each_entry(entry, &dev->msi_list, list) {
> int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
> if (int_no >= 0)
> @@ -150,12 +157,11 @@ static int ppc4xx_setup_pcieh_hw(struct
> platform_device *dev,
> if (!sdr_addr)
> return -1;
>
> - SDR0_WRITE(sdr_addr, (u64)res.start >> 32); /*HIGH addr */
> - SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
> -
> + mtdcri(SDR0, *sdr_addr, upper_32_bits(res.start)); /*HIGH
> addr */
> + mtdcri(SDR0, *sdr_addr + 1, lower_32_bits(res.start)); /* Low
> addr */
>
> msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
> - if (msi->msi_dev)
> + if (!msi->msi_dev)
> return -ENODEV;
>
> msi->msi_regs = of_iomap(msi->msi_dev, 0);
> @@ -167,9 +173,12 @@ static int ppc4xx_setup_pcieh_hw(struct
> platform_device *dev,
> (u32) (msi->msi_regs + PEIH_TERMADH), (u32)
> (msi->msi_regs));
>
> msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
> - msi->msi_addr_hi = 0x0;
> - msi->msi_addr_lo = (u32) msi_phys;
> - dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n",
> msi->msi_addr_lo);
> + if (!msi_virt)
> + return -ENOMEM;
> + msi->msi_addr_hi = (u32)(msi_phys >> 32);
> + msi->msi_addr_lo = (u32)(msi_phys & 0xffffffff);
> + dev_dbg(&dev->dev, "PCIE-MSI: msi address high 0x%x, low 0x%x\n",
> + msi->msi_addr_hi, msi->msi_addr_lo);
>
> /* Progam the Interrupt handler Termination addr registers */
> out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
> @@ -185,6 +194,8 @@ static int ppc4xx_setup_pcieh_hw(struct
> platform_device *dev,
> out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
> out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
>
> + dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
> +
> return 0;
> }
>
> @@ -194,7 +205,7 @@ static int ppc4xx_of_msi_remove(struct platform_device
> *dev)
> int i;
> int virq;
>
> - for (i = 0; i < NR_MSI_IRQS; i++) {
> + for (i = 0; i < msi_irqs; i++) {
> virq = msi->msi_virqs[i];
> if (virq != NO_IRQ)
> irq_dispose_mapping(virq);
> @@ -215,8 +226,6 @@ static int __devinit ppc4xx_msi_probe(struct
> platform_device *dev)
> struct resource res;
> int err = 0;
>
> - msi = &ppc4xx_msi;/*keep the msi data for further use*/
> -
> dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
>
> msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
> @@ -234,6 +243,10 @@ static int __devinit ppc4xx_msi_probe(struct
> platform_device *dev)
> goto error_out;
> }
>
> + msi_irqs = of_irq_count(dev->dev.of_node);
> + if (!msi_irqs)
> + return -ENODEV;
> +
> if (ppc4xx_setup_pcieh_hw(dev, res, msi))
> goto error_out;
>
> @@ -242,6 +255,7 @@ static int __devinit ppc4xx_msi_probe(struct
> platform_device *dev)
> dev_err(&dev->dev, "Error allocating MSI bitmap\n");
> goto error_out;
> }
> + ppc4xx_msi = *msi;
>
> ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
> ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
> --
> 1.7.3.4
>
>
[-- Attachment #2: Type: text/html, Size: 7755 bytes --]
^ permalink raw reply
* [PATCH v2] KVM: PPC: Use clockevent multiplier and shifter for decrementer
From: Bharat Bhushan @ 2012-04-09 4:33 UTC (permalink / raw)
To: linuxppc-dev, kvm-ppc, kvm; +Cc: Bharat Bhushan
Time for which the hrtimer is started for decrementer emulation is calculated using tb_ticks_per_usec. While hrtimer uses the clockevent for DEC reprogramming (if needed) and which calculate timebase ticks using the multiplier and shifter mechanism implemented within clockevent layer. It was observed that this conversion (timebase->time->timebase) are not correct because the mechanism are not consistent. In our setup it adds 2% jitter.
With this patch clockevent multiplier and shifter mechanism are used when starting hrtimer for decrementer emulation. Now the jitter is < 0.5%.
Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
---
v2:
- decrementer_clockevent is made non-static rather than a seprate API to get mult/shift
arch/powerpc/include/asm/time.h | 1 +
arch/powerpc/kernel/time.c | 2 +-
arch/powerpc/kvm/emulate.c | 5 +++--
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 7eb10fb..b3c7959 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -28,6 +28,7 @@
extern unsigned long tb_ticks_per_jiffy;
extern unsigned long tb_ticks_per_usec;
extern unsigned long tb_ticks_per_sec;
+extern struct clock_event_device decrementer_clockevent;
struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 567dd7c..e237225 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -105,7 +105,7 @@ static int decrementer_set_next_event(unsigned long evt,
static void decrementer_set_mode(enum clock_event_mode mode,
struct clock_event_device *dev);
-static struct clock_event_device decrementer_clockevent = {
+struct clock_event_device decrementer_clockevent = {
.name = "decrementer",
.rating = 200,
.irq = 0,
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index afc9154..c8b5206 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kvm_host.h>
+#include <linux/clockchips.h>
#include <asm/reg.h>
#include <asm/time.h>
@@ -104,8 +105,8 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
*/
dec_time = vcpu->arch.dec;
- dec_time *= 1000;
- do_div(dec_time, tb_ticks_per_usec);
+ dec_time = dec_time << decrementer_clockevent.shift;
+ do_div(dec_time, decrementer_clockevent.mult);
dec_nsec = do_div(dec_time, NSEC_PER_SEC);
hrtimer_start(&vcpu->arch.dec_timer,
ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL);
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH 1/1] [v3] Add support 2 SATA ports for Maui and change filename from sata_dwc_460ex.c to sata_dwc_4xx.c
From: Sergei Shtylyov @ 2012-04-08 19:35 UTC (permalink / raw)
To: Thang Q. Nguyen
Cc: Phong Vo, devicetree-discuss, linuxppc-dev, Rob Herring,
linux-kernel, linux-ide, Paul Mackerras, Jeff Garzik
In-Reply-To: <1333690265-27857-1-git-send-email-tqnguyen@apm.com>
Hello.
On 06-04-2012 9:31, Thang Q. Nguyen wrote:
> Signed-off-by: Thang Q. Nguyen<tqnguyen@apm.com>
[...]
> diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_4xx.c
> similarity index 73%
> rename from drivers/ata/sata_dwc_460ex.c
> rename to drivers/ata/sata_dwc_4xx.c
> index 69f7cde..07e9b36 100644
> --- a/drivers/ata/sata_dwc_460ex.c
> +++ b/drivers/ata/sata_dwc_4xx.c
[...]
> @@ -268,22 +276,25 @@ enum {
> << 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;
> + u8 *scr_base;
Why not 'void __iomem *scr_base'? You have to cast to it anyway everytime.
And 'u8 *' is just not the right type.
> + int dma_channel; /* DWC SATA DMA channel */
> + int hostID;
> };
хюююъ
> +/* This is used for easier trace back when having DMA channel */
> +static struct sata_dwc_device *dwc_dev_list[DMA_NUM_CHANS];
I don't quite understand: isn't this dual channel device? But you declare
a device per DMA channel...
> +/*
> + * As we have only one DMA controller, this will be set static and global
> + * for easier to access
"to" not needed here.
> @@ -372,15 +381,15 @@ static const char *get_dma_dir_descript(int dma_dir)
> }
> }
>
> -static void sata_dwc_tf_dump(struct ata_taskfile *tf)
> +static void sata_dwc_tf_dump(struct device *dwc_dev, struct ata_taskfile *tf)
> {
> - dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:"
> + dev_vdbg(dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:"
Space missing after colon, BTW.
> "0x%lx device: %x\n", tf->command,
> get_prot_descript(tf->protocol), tf->flags, tf->device);
[...]
> /*
> * Function: dma_request_channel
BTW, it would be good if you changed the function comments to the
kernel-doc format (in another patch).
> - * arguments: None
> + * arguments: ap
> * 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)
> +static int dma_request_channel(struct ata_port *ap)
> {
> - int i;
> + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
>
[...]
> + /* Check if the channel is not currently in use */
> + if (!(in_le32(&(sata_dma_regs->dma_chan_en.low)) &\
\ not needed. () with & not needed.
> + DMA_CHANNEL(hsdev->dma_channel)))
> + return hsdev->dma_channel;
> +
> + dev_err(ap->dev, "%s Channel %d is currently in use\n", __func__,
> + hsdev->dma_channel);
> return -1;
> }
>
> /*
> + * Check if the selected DMA channel is currently enabled.
> + */
> +static int sata_dwc_dma_chk_en(int ch)
> +{
> + u32 dma_chan_reg;
Empty line here please.
> + /* Read the DMA channel register */
> + dma_chan_reg = in_le32(&(sata_dma_regs->dma_chan_en.low));
() with & not needed.
> +/*
> + * Handle DMA transfer complete interrupt. This checks and passes the
> + * processing to the appropriate ATA port.
> + */
> +static irqreturn_t dma_dwc_handler(int irq, void *hsdev_instance)
> +{
> + u32 tfr_reg, err_reg;
> + int chan;
> +
> + tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
> + err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
() with & not needed.
> @@ -471,41 +517,25 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
> spin_lock_irqsave(&host->lock, flags);
> ap = host->ports[port];
> hsdevp = HSDEVP_FROM_AP(ap);
> - tag = ap->link.active_tag;
>
> - tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\
> + if (ap->link.active_tag != ATA_TAG_POISON)
> + tag = ap->link.active_tag;
> +
> + tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr\
\ not needed. () with & not needed. And the line is too short to break it
anyway.
> .low));
> - err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\
> + err_reg = in_le32(&(sata_dma_regs->interrupt_status.error\
Same coments.
> + out_le32(&(sata_dma_regs->interrupt_clear.tfr.low),
() with & not needed.
> @@ -516,11 +546,16 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
> err_reg);
>
> /* Clear the interrupt. */
> - out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
> + out_le32(&(sata_dma_regs->interrupt_clear\
\ not needed. () with & not needed. And the line is too short to break it
anyway.
> .error.low),
[...]
> @@ -629,14 +667,22 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
> * Set DMA addresses and lower half of control register
> * based on direction.
> */
> + if (hsdevp->hsdev->hostID == APM_821XX_SATA) {
> + sms_val = 1+hsdevp->hsdev->dma_channel;
Spaces around + please.
> + dms_val = 0;
> + } else {
> + sms_val = 0;
> + dms_val = 1+hsdevp->hsdev->dma_channel;
Same here.
> @@ -714,70 +766,49 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
> 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)) |
> + out_le32(&(sata_dma_regs->dma_chan_en.low),
> + in_le32(&(sata_dma_regs->dma_chan_en.low)) |
() with & not needed.
> 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)
> +
Empty line not needed...
> +static int dma_dwc_xfer_setup(struct ata_port *ap, dma_addr_t dma_lli)
[...]
> - out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high),
> + out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high),
() with & not needed.
> + DMA_CFG_HW_HS_SRC(dma_ch) | DMA_CFG_HW_HS_DEST(dma_ch) | \
> DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
> - out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low), 0);
> +
> + out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low),
() with & not needed.
> + DMA_CFG_HW_CH_PRIOR(dma_ch));
>
> /* Program the address of the linked list */
> - out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low),
> + if (hsdev->hostID == APM_460EX_SATA) {
> + out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
() with & not needed.
> DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
Please indent this like more to the right.
> + } else {
> + out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
() with & not needed.
> + DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER1));
> + }
>
> /* Program the CTL register with src enable / dst enable */
> - out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].ctl.low),
> + out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low),
() with & not needed.
> @@ -789,24 +820,18 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
[...]
> /* Enabe DMA */
Enable.
> - out_le32(&(host_pvt.sata_dma_regs->dma_cfg.low), DMA_EN);
> + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN);
() with & not needed.
> @@ -838,23 +863,27 @@ static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
> return 0;
> }
>
> -static u32 core_scr_read(unsigned int scr)
> +static u32 core_scr_read(struct ata_port *ap, unsigned int scr)
> {
> - return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\
> - (scr * 4));
> + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
> +
> + return in_le32((void __iomem *)hsdev->scr_base + (scr * 4));
() around * not needed.
> }
>
> -static void core_scr_write(unsigned int scr, u32 val)
> +
> +static void core_scr_write(struct ata_port *ap, unsigned int scr, u32 val)
> {
> - out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4),
> - val);
> + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
> +
> + out_le32((void __iomem *)hsdev->scr_base + (scr * 4), val);
Same here.
> @@ -869,7 +898,6 @@ static u32 qcmd_tag_to_mask(u8 tag)
> return 0x00000001<< (tag& 0x1f);
> }
>
> -/* See ahci.c */
Don't think this is a legal change in this patch...
> static void sata_dwc_error_intr(struct ata_port *ap,
> struct sata_dwc_device *hsdev, uint intpr)
> {
> @@ -883,24 +911,23 @@ static void sata_dwc_error_intr(struct ata_port *ap,
>
> ata_ehi_clear_desc(ehi);
>
> - serror = core_scr_read(SCR_ERROR);
> + serror = core_scr_read(ap, SCR_ERROR);
> status = ap->ops->sff_check_status(ap);
>
> - err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error.\
> + err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.\
\ not needed. () with & not needed. And the line is too short to be broken.
> low));
> tag = ap->link.active_tag;
>
> dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x "
> - "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n",
> - __func__, serror, intpr, status, host_pvt.dma_interrupt_count,
> - hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg);
> + " pending=%d dma_err_status=0x%08x\n",
Space not needed before "pending".
> @@ -930,14 +957,14 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
> struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host);
> struct ata_port *ap;
> struct ata_queued_cmd *qc;
> - unsigned long flags;
> u8 status, tag;
> - int handled, num_processed, port = 0;
> - uint intpr, sactive, sactive2, tag_mask;
> + int handled, port = 0;
> + int num_lli;
> + uint intpr, sactive, tag_mask;
> struct sata_dwc_device_port *hsdevp;
> - host_pvt.sata_dwc_sactive_issued = 0;
> + u32 mask;
>
> - spin_lock_irqsave(&host->lock, flags);
> + spin_lock(&host->lock);
Is this change related?
> + if (qc) {
> + hsdevp->sactive_issued |= mask;
> + /* Prevent to issue more commands */
> + qc->ap->link.active_tag = tag;
> + qc->dev->link->sactive |= (1 << qc->tag);
() not needed around <<.
> + num_lli = map_sg_to_lli(ap, qc->sg, qc->n_elem, \
> + hsdevp->llit[tag], hsdevp->llit_dma[tag], \
> + (void *__iomem)(&hsdev->sata_dwc_regs->dmadr), \
You don't need \ to break the lines in C, unless this is in macro definition.
> @@ -1012,28 +1051,12 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
> dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
> __func__, get_prot_descript(qc->tf.protocol));
> DRVSTILLBUSY:
> + /* Do complete action for the current QC */
> if (ata_is_dma(qc->tf.protocol)) {
[...]
> + sata_dwc_qc_complete(ap, qc, 1);
> + } else if ((ata_is_pio(qc->tf.protocol)) ||
> + (ata_is_nodata(qc->tf.protocol))) {
() not needed around the operands of ||.
> @@ -1049,23 +1072,18 @@ DRVSTILLBUSY:
[...]
> - if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \
> - (host_pvt.sata_dwc_sactive_issued)) {
> + if ((tag_mask | hsdevp->sactive_issued) != \
> + hsdevp->sactive_issued) {
> dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x "
> - "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask"
> - "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued,
> + "sactive_issued=0x%08x tag_mask"
There's no need to break the string literal here anymore.
> + "=0x%08x\n", sactive, hsdevp->sactive_issued,
> tag_mask);
> }
>
> @@ -1073,70 +1091,21 @@ DRVSTILLBUSY:
> status = ap->ops->sff_check_status(ap);
> dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
>
> - tag = 0;
> - num_processed = 0;
> - while (tag_mask) {
> - num_processed++;
> - while (!(tag_mask& 0x00000001)) {
> - tag++;
> - tag_mask<<= 1;
> - }
> -
> - tag_mask&= (~0x00000001);
> - qc = ata_qc_from_tag(ap, tag);
> -
> - /* To be picked up by completion functions */
> - qc->ap->link.active_tag = tag;
> - hsdevp->cmd_issued[tag] = 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);
> + for (tag = 0; tag< 32; tag++) {
> + if (tag_mask& qcmd_tag_to_mask(tag)) {
> + qc = ata_qc_from_tag(ap, tag);
> + if (!qc) {
> + dev_info(ap->dev, "error: Tag %d is set but " \
> + "not available\n", tag);
> + continue;
> + }
> sata_dwc_qc_complete(ap, qc, 1);
> - handled = 1;
> - goto DONE;
> }
> -
> - /* Process completed command */
> - dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__,
> - get_prot_descript(qc->tf.protocol));
> - if (ata_is_dma(qc->tf.protocol)) {
> - host_pvt.dma_interrupt_count++;
> - if (hsdevp->dma_pending[tag] == \
> - SATA_DWC_DMA_PENDING_NONE)
> - dev_warn(ap->dev, "%s: DMA not pending?\n",
> - __func__);
> - if ((host_pvt.dma_interrupt_count % 2) == 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 (read 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 = core_scr_read(SCR_ACTIVE);
> - if (sactive2 != sactive) {
> - dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2"
> - "=0x%x\n", sactive, sactive2);
You're changing the algorithm of handling command here. Is it necessary to
support 2 ports?
> @@ -1167,44 +1136,6 @@ static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
> }
> }
>
> -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 = HSDEVP_FROM_AP(ap);
> - struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
> - u8 tag = 0;
> -
> - tag = ap->link.active_tag;
> - qc = ata_qc_from_tag(ap, tag);
> - if (!qc) {
> - dev_err(ap->dev, "failed to get qc");
> - return;
> - }
> -
> -#ifdef DEBUG_NCQ
> - if (tag > 0) {
> - dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s "
> - "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command,
> - get_dma_dir_descript(qc->dma_dir),
> - get_prot_descript(qc->tf.protocol),
> - in_le32(&(hsdev->sata_dwc_regs->dmacr)));
> - }
> -#endif
> -
> - if (ata_is_dma(qc->tf.protocol)) {
> - if (hsdevp->dma_pending[tag] == 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] = SATA_DWC_DMA_PENDING_NONE;
> - sata_dwc_qc_complete(ap, qc, check_status);
> - ap->link.active_tag = ATA_TAG_POISON;
> - } else {
> - sata_dwc_qc_complete(ap, qc, check_status);
> - }
> -}
Is this change related to dual port support?
> @@ -1213,24 +1144,39 @@ static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
> u32 mask = 0x0;
> u8 tag = qc->tag;
> struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
> - host_pvt.sata_dwc_sactive_queued = 0;
> + int i;
> +
> dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status);
>
> - if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX)
> - dev_err(ap->dev, "TX DMA PENDING\n");
> - else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX)
> - dev_err(ap->dev, "RX DMA PENDING\n");
> + /* Check main status, clearing INTRQ */
> + status = ap->ops->sff_check_status(ap);
> +
> + if (check_status) {
> + /* Make sure SATA port is not in BUSY state */
> + i = 0;
> + while (status & ATA_BUSY) {
> + if (++i > 10)
> + break;
> + status = ap->ops->sff_check_altstatus(ap);
> + };
> +
> + if (unlikely(status & ATA_BUSY))
> + dev_err(ap->dev, "QC complete cmd=0x%02x STATUS BUSY "
> + "(0x%02x) [%d]\n", qc->tf.command, status, i);
> + }
Is this related to dual port support?
> @@ -1437,28 +1377,37 @@ static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
> struct ata_port *ap = qc->ap;
> struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
> int dir = qc->dma_dir;
> - dma_chan = hsdevp->dma_chan[tag];
>
> - if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) {
> + /* Configure DMA before starting data transfer */
> + dma_chan = dma_dwc_xfer_setup(ap, hsdevp->llit_dma[tag]);
> + if (unlikely(dma_chan < 0)) {
> + dev_err(ap->dev, "%s: dma channel unavailable\n", __func__);
> + /* Offending this QC as no channel available for transfer */
> + qc->err_mask |= AC_ERR_TIMEOUT;
Hm, is this good error code?
> + return;
> + }
> +
> + /* Check if DMA should be started */
> + hsdevp->dma_chan[tag] = dma_chan;
> + if (hsdevp->sactive_queued & qcmd_tag_to_mask(tag)) {
> start_dma = 1;
> if (dir == DMA_TO_DEVICE)
> hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX;
> else
> hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX;
[...]
> @@ -1490,6 +1440,49 @@ static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
> sata_dwc_bmdma_start_by_tag(qc, tag);
> }
>
> +static void sata_dwc_bmdma_stop(struct ata_queued_cmd *qc)
> +{
> + struct ata_port *ap = qc->ap;
> + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
> + int dma_ch, enabled;
> +
> + dma_ch = hsdev->dma_channel;
> + enabled = sata_dwc_dma_chk_en(dma_ch);
> +
> + if (enabled) {
> + dev_dbg(ap->dev,
> + "%s terminate DMA on channel=%d (mask=0x%08x) ...",
> + __func__, dma_ch, DMA_DISABLE_CHAN(dma_ch));
> + /* Disable the selected channel */
> + out_le32(&(sata_dma_regs->dma_chan_en.low),
() with & not needed.
> + DMA_DISABLE_CHAN(dma_ch));
> +
> + /* Wait for the channel is disabled */
> + do {
> + enabled = sata_dwc_dma_chk_en(dma_ch);
> + ndelay(1000);
> + } while (enabled);
> + dev_dbg(ap->dev, "done\n");
> + }
> +}
> +
Wasn't this function necessary before dual port support?
> +static u8 sata_dwc_bmdma_status(struct ata_port *ap)
> +{
> + u32 status = 0;
> + u32 tfr_reg, err_reg;
> + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
> +
> + /* Check DMA register for status */
> + tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
> + err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
> +
> + if (unlikely(err_reg & DMA_CHANNEL(hsdev->dma_channel)))
> + status = ATA_DMA_ERR;
> + else if (tfr_reg & DMA_CHANNEL(hsdev->dma_channel))
> + status = ATA_DMA_INTR;
> + return status;
> +}
> +
Is the above really related to dual port support? Wasn't it necessary before?
> @@ -1500,24 +1493,22 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
> {
> struct scatterlist *sg = qc->sg;
> struct ata_port *ap = qc->ap;
> - int dma_chan;
> + int num_lli;
> struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
> struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
>
> + if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
() not neecessary around ==.
> + return;
Wasn't this check necessary before dual port support?
> dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n",
> __func__, ap->port_no, get_dma_dir_descript(qc->dma_dir),
> qc->n_elem);
>
> - dma_chan = 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__, dma_chan);
> - return;
> + if (!ata_is_ncq(qc->tf.protocol)) {
> + num_lli = map_sg_to_lli(qc->ap, sg, qc->n_elem,
> + hsdevp->llit[tag], hsdevp->llit_dma[tag],
> + (void *__iomem)(&hsdev->sata_dwc_regs->dmadr),
> + qc->dma_dir);
> }
And what if the protocol is NCQ?
> - hsdevp->dma_chan[tag] = dma_chan;
> }
>
> static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
> @@ -1541,19 +1532,18 @@ static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
> sata_dwc_qc_prep_by_tag(qc, tag);
>
> if (ata_is_ncq(qc->tf.protocol)) {
> - sactive = core_scr_read(SCR_ACTIVE);
> + /* Update SActive register for new command */
> + sactive = core_scr_read(qc->ap, SCR_ACTIVE);
> sactive |= (0x00000001<< tag);
BTW, () not needed here. You can also use BIT() macro.
> - core_scr_write(SCR_ACTIVE, sactive);
> -
> - dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x "
> - "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive,
> - sactive);
> + core_scr_write(qc->ap, SCR_ACTIVE, sactive);
> + qc->dev->link->sactive |= 0x00000001<< tag;
>
> ap->ops->sff_tf_load(ap,&qc->tf);
> - sata_dwc_exec_command_by_tag(ap,&qc->tf, qc->tag,
> - SATA_DWC_CMD_ISSUED_PEND);
> + sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag);
> } else {
> - ata_sff_qc_issue(qc);
> + /* As ata_sff_qc_issue is no longer handle DMA transfer,
> + * change to use ata_bmdma_qc_issue instead */
The preferred style of multi-line comments is this:
/*
* bla
* bla
*/
> + ata_bmdma_qc_issue(qc);
This is a bug fix, so should be in a prior patch.
> }
> return 0;
> }
> @@ -1582,7 +1572,12 @@ static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
> static void sata_dwc_error_handler(struct ata_port *ap)
> {
> ap->link.flags |= ATA_LFLAG_NO_HRST;
> - ata_sff_error_handler(ap);
> + ata_bmdma_error_handler(ap);
Same about this. I've already noted this on Friday.
> +}
> +
> +u8 sata_dwc_check_altstatus(struct ata_port *ap)
> +{
> + return ioread8(ap->ioaddr.altstatus_addr);
This is the same as the default implementation, why you need to redefine it?
> @@ -1638,13 +1637,38 @@ static int sata_dwc_probe(struct platform_device *ofdev)
> struct ata_host *host;
> struct ata_port_info pi = sata_dwc_port_info[0];
> const struct ata_port_info *ppi[] = {&pi, NULL };
> + const unsigned int *dma_chan;
> +
> + /* Check if device is declared in device tree */
> + if (!of_device_is_available(ofdev->dev.of_node)) {
> + printk(KERN_INFO "%s: Port disabled via device-tree\n",
> + ofdev->dev.of_node->full_name);
> + return 0;
> + }
This check is not related to dual port support I think.
>
> /* Allocate DWC SATA device */
> hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
Consider switching to the managed device interface (devm_kzalloc() and
friends).
> if (hsdev == NULL) {
> dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
> err = -ENOMEM;
> - goto error;
> + goto error_out_5;
> + }
[...]
> + dma_chan = of_get_property(ofdev->dev.of_node, "dma-channel", NULL);
I think you should use of_property_read_u32() instead.
> @@ -1653,7 +1677,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
> dev_err(&ofdev->dev, "ioremap failed for SATA register"
> " address\n");
> err = -ENODEV;
> - goto error_kmalloc;
> + goto error_out_4;
> }
> hsdev->reg_base = base;
> dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
> @@ -1666,7 +1690,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
> if (!host) {
> dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
> err = -ENOMEM;
> - goto error_iomap;
> + goto error_out_4;
Are you sure it's not 'error_out_3' at this point?
> @@ -1688,23 +1712,30 @@ static int sata_dwc_probe(struct platform_device *ofdev)
> if (irq == NO_IRQ) {
You should get rid of NO_IRQ.
> - /* Initialize AHB DMAC */
> - dma_dwc_init(hsdev, irq);
> + /* Init glovbal dev list */
s/glovbal/global/
WBR, Sergei
^ permalink raw reply
* kernel3.2.13 cannot boot on my mpc8260 board using u-boot2011.12
From: jerry_dw @ 2012-04-08 12:56 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 6874 bytes --]
Hi:
My board is a custom MPC8260 board, with 4MB flash,128MB SDRAM.
I modified pq2fads.dts and pq2fads_defconfig,
then compile the kernel.The kernel halt after displaying "Booting using OF flat tree.".
Serial Console:
U-Boot 2011.12 (Mar 30 2012 - 15:57:39)
MPC8260 Reset Status: External Soft, External Hard
MPC8260 Clock Configuration
- Bus-to-Core Mult 4.5x, VCO Div 2, 60x Bus Freq 22-65 , Core Freq 100-300
- dfbrg 1, corecnf 0x17, busdf 5, cpmdf 1, plldf 0, pllmf 2, pcidf 3
- vco_out 399999996, scc_clk 99999999, brg_clk 24999999
- cpu_clk 299999997, cpm_clk 199999998, bus_clk 66666666
CPU: MPC8260 (HiP4 Rev 14, Mask B.1 4K25A) at 300 MHz
Board: SJ3208 TDM to EtherNet
SDRAM: 128 MiB
Top of RAM usable for U-Boot at: 08000000
Reserving 261k for U-Boot at: 07fbe000
Reserving 256k for malloc() at: 07f7e000
Reserving 76 Bytes for Board Info at: 07f7dfb4
Reserving 108 Bytes for Global Data at: 07f7df48
Stack Pointer at: 07f7df28
New Stack Pointer is: 07f7df28
Now running in RAM - U-Boot at: 07fbe000
FLASH: flash_protect ON: from 0x20000000 to 0x2003BFFF
protect on 0
protect on 1
protect on 2
protect on 3
protect on 4
protect on 5
protect on 6
protect on 7
protect on 8
flash_protect ON: from 0x20060000 to 0x2007FFFF
protect on 10
4 MiB
*** Warning - bad CRC, using default environment
Destroy Hash Table: 07ffcf04 table = (null)
Create Hash Table: N=91
INSERT: table 07ffcf04, filled 1/97 rv 07f7e148 ==> name="bootargs" value="console=ttyCPM0,9600 root=/dev/ram0"
INSERT: table 07ffcf04, filled 2/97 rv 07f7e2bc ==> name="bootcmd" value="bootm 0x20080000 0x20240000"
INSERT: table 07ffcf04, filled 3/97 rv 07f7e2ec ==> name="bootdelay" value="5"
INSERT: table 07ffcf04, filled 4/97 rv 07f7e19c ==> name="baudrate" value="9600"
INSERT: table 07ffcf04, filled 5/97 rv 07f7e574 ==> name="ethaddr" value="00:10:EC:D0:30:88"
INSERT: table 07ffcf04, filled 6/97 rv 07f7e178 ==> name="ipaddr" value="12.13.38.221"
INSERT: table 07ffcf04, filled 7/97 rv 07f7e550 ==> name="serverip" value="12.13.38.222"
INSERT: table 07ffcf04, filled 8/97 rv 07f7e4d8 ==> name="gatewayip" value="12.13.38.254"
INSERT: table 07ffcf04, filled 9/97 rv 07f7e34c ==> name="netmask" value="255.255.255.0"
INSERT: free(data = 07f7e008)
INSERT: done
In: serial
Out: serial
Err: serial
U-Boot relocated to 07fbe000
Net: FCC1
Reset Ethernet PHY
### main_loop entered: bootdelay=5
### main_loop: bootcmd="bootm 0x20080000 0x20240000"
Hit any key to stop autoboot: 0
=> bootm 0x20080000 0x20240000 0x203ff000
## Current stack ends at 0x07f7dd10
* kernel: cmdline image address = 0x20080000
## Booting kernel from Legacy Image at 20080000 ...
Image Name: Linux-3.2.13.Jerry_Test_V1.1
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1527637 Bytes = 1.5 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
kernel data at 0x20080040, len = 0x00174f55 (1527637)
* ramdisk: cmdline image address = 0x20240000
## Loading init Ramdisk from Legacy Image at 20240000 ...
Image Name: SJ3208_Ramdisk_01
Image Type: PowerPC Linux RAMDisk Image (gzip compressed)
Data Size: 1730966 Bytes = 1.7 MiB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
ramdisk start = 0x20240040, ramdisk end = 0x203e69d6
* fdt: cmdline image address = 0x203ff000
## Checking for 'FDT'/'FDT Image' at 203ff000
* fdt: raw FDT blob
## Flattened Device Tree blob at 203ff000
Booting using the fdt blob at 0x203ff000
of_flat_tree at 0x203ff000 size 0x00000fbb
Uncompressing Kernel Image ... OK
kernel loaded at 0x00000000, end = 0x0030fda0
## initrd_high = 0xffffffff, copy_to_ram = 1
Loading Ramdisk to 07dd6000, end 07f7c996 ... OK
ramdisk load start = 0x07dd6000, ramdisk load end = 0x07f7c996
## device tree at 203ff000 ... 203fffba (len=16315 [0x3FBB])
Loading Device Tree to 003fc000, end 003fffba ... OK
Updating property '/soc@f0000000/cpm@119c0/ethernet@11320/mac-address' = 00 10 ec d0 30 88
Updating property '/soc@f0000000/cpm@119c0/ethernet@11320/local-mac-address' = 00 10 ec d0 30 88
Updating property 'clock-frequency' = 01 7d 78 3f
Updating property 'bus-frequency' = 03 f9 40 aa
Updating property 'timebase-frequency' = 00 fe 50 2a
Updating property 'clock-frequency' = 11 e1 a2 fd
## Transferring control to Linux (at address 00000000) ...
Booting using OF flat tree...
And Log_buf as follow:
20120331:log_buffer as follow
<6>Using Freescale PQ2FADS machine description.
<3>Cannot reserve gpages without hugetlb enabled.
<5>Linux version 3.2.13.Jerry_1.0_Test (jerry@jerry-desktop) (gcc version 4.2.2) #1 Fri Mar 30 1 1:07:35 CST 2012.
<4>Found initrd at 0xc7dd6000:0xc7f7c996.
<4>Machine check in kernel mode..
<4>Caused by (from SRR1=41030): Transfer error ack signal.
<4>Oops: Machine check, sig: 7 [#1].
<4>Freescale PQ2FADS.
<4>NIP: c00175c0 LR: c0328a9c CTR:00002710.
<4>REGS: c035bed0 TRAP 0200 Not tainted (3.2.13.Jerry_1.0_Test).
<4>MSR: 00041030 <ME,IR,DR> CR: 22022024 XER: 20000000.
<4>TASK =c0349478[0] 'swapper' THREAD: c035a000.
<4>GPR00: 00002710 c035bf80 c0349478 80010000 00000000 c037cefc f00095a90000a000 .
<4>GPR08: 00000008 fdfd19c0 00000000 c0360000 c036339c 02040000 00000000 00000000 .
<4>GPR16: 07ff0bac 07fe9728 00000000 00000000 00000000 00000000 00000000 00000000 .
<4>GPR24: 00000000 00000000 40000000 07ffcf88 c0360000 c03613ec c035e020 00001032 .
<4>NIP [c00175c0] cpm_command+0x4c/0xb0.
<4>LR [c0328a9c] pq2fads_setup_arch+0x3c/0x260.
<4>Call Trace:.
<4>[c035bf80] [c03613ec] ppc_md+0x0/0xd8 (unreliable).
<4>[c035bf90] [c0328a9c] pq2fads_setup_arch+0x3c/0x260.
<4>[c035bfb0] [c0324e58] setup_arch+0x150/0x18c.
<4>[c035bfc0] [c0320864] start_kernel+0x84/0x2e0.
<4>[c035bff0] [00003438] 0x3438.
<4>Instruction dump:.
<4>3d60c036 64630001 7c632378 812b00f4 7c0004ac 90690000 38002710 7c0903a6 .
<4>48000008 4240003c 812b00f4 7c0004ac.<80090000> 0c000000 4c00012c 74090001 .
<4>---[end trace 31fd0ba7d8756001 ]---.
<0>Kernel panic - not syncing: Attempted to kill the idle task!.
<4>Call Trace:.
<4>[c035bdb0] [c0007f08] show_stack+0x4c/0x16c (unreliable).
<4>[c035bdf0] [c001e714] panic+0xa8/0x1f4.
<4>[c035be40] [c00227a8] do_exit+0x5a4/0x658.
<4>[c035be80] [c000ba98] kerne l_bad_stack+0x0/0x4c.
<4>[c035bea0] [c000bcc0] machine_check_exception+0xe4/0x170
<4>[c035bec0] [c000f334] ret_from_except_full+0x0/0x4c.
<4>--- Exception: 200 at cpm_command+0x4c/0xb0.
<4> LR = pq2fads_setup_arch+0x3c/0x260
<4>[c035bf80] [c03613ec] ppc_md+0x0/0xd8 (unreliable).
<4>[c035bf90] [c0328a9c] pq2fads_setup_arch+0x3c/0x260.
<4>[c035bfb0] [c0324e58] setup_arch+0x150/0x18c.
<4>[c035bfc0] [c0320864] start_kernel+0x84/0x2e0.
<4>[c035bff0] [00003438] 0x3438.
<0>Rebooting in 180 seconds......
I have no idea about this,
u-boot,Flat device tree ,kernel,Ramdisk ,Thatwas wrong??
Best regards.
Jerry
[-- Attachment #2: Type: text/html, Size: 8844 bytes --]
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Andreas Schwab @ 2012-04-07 12:27 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Russell King - ARM Linux, devicetree-discuss, linux-kernel,
Rob Herring, Milton Miller, Thomas Gleixner, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <1333755470.3040.38.camel@pasglop>
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> It's arguable that this irq_set_irq_type(,NONE) shouln't be there but
> still ... it's been around for ever and things worked :-) So something
> -else- is causing the problem and I'd like to understand what exactly.
AFAICS before a09b659cd68c10ec6a30cb91ebd2c327fcd5bfe5
irq_set_irq_type(,NONE) was actually a no-op.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Grant Likely @ 2012-04-07 1:29 UTC (permalink / raw)
To: Thomas Gleixner, Andreas Schwab
Cc: devicetree-discuss, linux-kernel, Milton Miller, Rob Herring,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1204061315040.2542@ionos>
On Fri, 6 Apr 2012 13:17:04 +0200 (CEST), Thomas Gleixner <tglx@linutronix.de> wrote:
> On Fri, 6 Apr 2012, Andreas Schwab wrote:
>
> > Grant Likely <grant.likely@secretlab.ca> writes:
> >
> > > Can you attach console output logs for each of configs above and also
> > > with NR_IRQS=128? That might give me some clues as to which specific
> > > code is causing the issues.
> >
> > It really looks like the issue starts when irq_expand_nr_irqs is called
> > the first time to make nr_irqs bigger than NR_IRQS.
>
> And it looks like the irqdomain code is the real culprit.
>
> void irq_set_virq_count(unsigned int count)
> {
> pr_debug("irq: Trying to set virq count to %d\n", count);
>
> BUG_ON(count < NUM_ISA_INTERRUPTS);
> if (count < NR_IRQS)
> irq_virq_count = count;
> }
>
> That looks simply wrong.....
>
> s/NR_IRQS/nr_irqs/ should do the trick.
Yeah, that code is wrong and I'll fix it, but the only purpose of that
code is to support the direct mapping on hardware that has limit on
the largest irq number that it can handle. That shouldn't be the
problem here.
g.
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Benjamin Herrenschmidt @ 2012-04-06 23:37 UTC (permalink / raw)
To: Andreas Schwab
Cc: Russell King - ARM Linux, devicetree-discuss, linux-kernel,
Rob Herring, Milton Miller, Thomas Gleixner, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <m24nsx9iz1.fsf@igel.home>
On Fri, 2012-04-06 at 13:51 +0200, Andreas Schwab wrote:
> Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
>
> > Ok. Doesn't matter anyway, this shouldn't be the problem in this
> > specific case. IE. we shouldn't be setting that interrupt to NONE.
>
> After removinge the call to irq_set_irq_type in mpic_host_map the irq
> problem disappears.
>
> Instead of the irq_set_irq_type(,NONE) calls from mpic_host_map I see
> corresponding irq_set_irq_type(,LEVEL_LOW) calls now.
It's arguable that this irq_set_irq_type(,NONE) shouln't be there but
still ... it's been around for ever and things worked :-) So something
-else- is causing the problem and I'd like to understand what exactly.
(When I say arguable, I do mean it. There are some reasons to keep it
even if we agree that it's not "setting a default" but marking the
interrupt as somewhat disabled as Russell wants, that's fine with me, an
MPIC external interrupt should -always- have a proper type set before
being used).
First we need to fix that business with NR_IRQS/nr_irqs everywhere, then
if the problem persists, check why we aren't calling the proper
irq_set_irq_type() after the mapping is established (we should be).
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH] Use clockevent multiplier and shifter for decrementer
From: Scott Wood @ 2012-04-06 19:10 UTC (permalink / raw)
To: Bharat Bhushan; +Cc: Bharat Bhushan, linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <1333522311-1390-1-git-send-email-bharat.bhushan@freescale.com>
On 04/04/2012 01:51 AM, Bharat Bhushan wrote:
> Time for which the hrtimer is started for decrementer emulation is
> calculated using tb_ticks_per_usec. While hrtimer uses the clockevent
> for DEC reprogramming (if needed) and which calculate timebase ticks
> using the multiplier and shifter mechanism implemented within
> clockevent layer. It was observed that this conversion
> (timebase->time->timebase) are not correct because the mechanism are
> not consistent. In our setup it adds 2% jitter.
>
> With this patch clockevent multiplier and shifter mechanism are used
> when starting hrtimer for decrementer emulation. Now the jitter is <
> 0.5%.
>
> Signed-off-by: Bharat Bhushan<bharat.bhushan@freescale.com>
> ---
> arch/powerpc/include/asm/time.h | 2 ++
> arch/powerpc/kernel/time.c | 6 ++++++
> arch/powerpc/kvm/emulate.c | 5 +++--
> 3 files changed, 11 insertions(+), 2 deletions(-)
Changes to arch/powerpc outside arch/powerpc/kvm need to
Cc: linuxppc-dev@lists.ozlabs.org
> diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
> index 7eb10fb..6d631b2 100644
> --- a/arch/powerpc/include/asm/time.h
> +++ b/arch/powerpc/include/asm/time.h
> @@ -202,6 +202,8 @@ extern u64 mulhdu(u64, u64);
> extern void div128_by_32(u64 dividend_high, u64 dividend_low,
> unsigned divisor, struct div_result *dr);
>
> +extern void get_clockevent_mult(u64 *multi, u64 *shift);
> +
> /* Used to store Processor Utilization register (purr) values */
>
> struct cpu_usage {
> diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
> index 567dd7c..d229edd 100644
> --- a/arch/powerpc/kernel/time.c
> +++ b/arch/powerpc/kernel/time.c
> @@ -910,6 +910,12 @@ static void __init init_decrementer_clockevent(void)
> register_decrementer_clockevent(cpu);
> }
>
> +void get_clockevent_mult(u64 *multi, u64 *shift)
> +{
> + *multi = decrementer_clockevent.mult;
> + *shift = decrementer_clockevent.shift;
> +}
Maybe just make decrmenter_clockevent non-static?
> diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
> index afc9154..4bfcaa1 100644
> --- a/arch/powerpc/kvm/emulate.c
> +++ b/arch/powerpc/kvm/emulate.c
> @@ -76,6 +76,7 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
> {
> unsigned long dec_nsec;
> unsigned long long dec_time;
> + u64 mult, shift;
>
> pr_debug("mtDEC: %x\n", vcpu->arch.dec);
> hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
> @@ -103,9 +104,9 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
> * host ticks.
> */
>
> + get_clockevent_mult(&mult,&shift);
> dec_time = vcpu->arch.dec;
> - dec_time *= 1000;
> - do_div(dec_time, tb_ticks_per_usec);
> + dec_time = (dec_time<< shift) / mult;
> dec_nsec = do_div(dec_time, NSEC_PER_SEC);
> hrtimer_start(&vcpu->arch.dec_timer,
> ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL);
-Scott
^ permalink raw reply
* Re: [PATCH 1/1] [v3] Add support 2 SATA ports for Maui and change filename from sata_dwc_460ex.c to sata_dwc_4xx.c
From: Sergei Shtylyov @ 2012-04-06 12:10 UTC (permalink / raw)
To: Thang Q. Nguyen
Cc: Phong Vo, devicetree-discuss, linuxppc-dev, Rob Herring,
linux-kernel, linux-ide, Paul Mackerras, Jeff Garzik
In-Reply-To: <1333690265-27857-1-git-send-email-tqnguyen@apm.com>
Hello.
On 06-04-2012 9:31, Thang Q. Nguyen wrote:
> Signed-off-by: Thang Q. Nguyen<tqnguyen@apm.com>
> ---
> Changes for v2:
> - Use git rename feature to change the driver to the newname and for
> easier review.
> Changes for v3:
> - Remove materials not related to 2 SATA ports support. They will
> be added in another patches.
> drivers/ata/Makefile | 2 +-
> drivers/ata/{sata_dwc_460ex.c => sata_dwc_4xx.c} | 820 +++++++++++-----------
> 2 files changed, 430 insertions(+), 392 deletions(-)
> rename drivers/ata/{sata_dwc_460ex.c => sata_dwc_4xx.c} (73%)
> diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_4xx.c
> similarity index 73%
> rename from drivers/ata/sata_dwc_460ex.c
> rename to drivers/ata/sata_dwc_4xx.c
> index 69f7cde..07e9b36 100644
> --- a/drivers/ata/sata_dwc_460ex.c
> +++ b/drivers/ata/sata_dwc_4xx.c
[...]
> @@ -16,6 +14,15 @@
> * 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.
> + *
> + * CHANGES:
> + * - Version 1.4:
> + * + Change filename from sata_dwc_460ex.c to sata_dwc_4xx.c
> + * + This driver supports more than one SATA port. Each SATA port has its
> + * own private attribute. Move sata_dwc_host_priv structure to
> + * sata_dwc_device and sata_dwc_device_port structures.
> + * + Change to use ata_bmdma_qc_issue and ata_bmdma_error_handler because
> + * the ata_sff_qc_issue and ata_sff_error_handler no longer support DMA.
This modification looks like a bug fix, and so should be separated and
posted before the dual-port patch.
I'll try to do more deltailed review on the weekend.
MBR, Sergei
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Andreas Schwab @ 2012-04-06 11:51 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Russell King - ARM Linux, devicetree-discuss, linux-kernel,
Rob Herring, Milton Miller, Thomas Gleixner, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <1333409927.30734.62.camel@pasglop>
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> Ok. Doesn't matter anyway, this shouldn't be the problem in this
> specific case. IE. we shouldn't be setting that interrupt to NONE.
After removinge the call to irq_set_irq_type in mpic_host_map the irq
problem disappears.
Instead of the irq_set_irq_type(,NONE) calls from mpic_host_map I see
corresponding irq_set_irq_type(,LEVEL_LOW) calls now.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Thomas Gleixner @ 2012-04-06 11:28 UTC (permalink / raw)
To: Andreas Schwab
Cc: devicetree-discuss, linux-kernel, Milton Miller, Rob Herring,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <m2bon59k68.fsf@igel.home>
On Fri, 6 Apr 2012, Andreas Schwab wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
>
> > And it looks like the irqdomain code is the real culprit.
> >
> > void irq_set_virq_count(unsigned int count)
> > {
> > pr_debug("irq: Trying to set virq count to %d\n", count);
> >
> > BUG_ON(count < NUM_ISA_INTERRUPTS);
> > if (count < NR_IRQS)
> > irq_virq_count = count;
> > }
> >
> > That looks simply wrong.....
>
> There is a single use of irq_set_virq_count, which is only relevant to
> the PS3.
Though irq_virq_count is statically initialized to NR_IRQS and it's
used in the code more than once.
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Andreas Schwab @ 2012-04-06 11:25 UTC (permalink / raw)
To: Thomas Gleixner
Cc: devicetree-discuss, linux-kernel, Milton Miller, Rob Herring,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1204061315040.2542@ionos>
Thomas Gleixner <tglx@linutronix.de> writes:
> And it looks like the irqdomain code is the real culprit.
>
> void irq_set_virq_count(unsigned int count)
> {
> pr_debug("irq: Trying to set virq count to %d\n", count);
>
> BUG_ON(count < NUM_ISA_INTERRUPTS);
> if (count < NR_IRQS)
> irq_virq_count = count;
> }
>
> That looks simply wrong.....
There is a single use of irq_set_virq_count, which is only relevant to
the PS3.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Thomas Gleixner @ 2012-04-06 11:17 UTC (permalink / raw)
To: Andreas Schwab
Cc: devicetree-discuss, linux-kernel, Milton Miller, Rob Herring,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <m2r4w1akz4.fsf@igel.home>
On Fri, 6 Apr 2012, Andreas Schwab wrote:
> Grant Likely <grant.likely@secretlab.ca> writes:
>
> > Can you attach console output logs for each of configs above and also
> > with NR_IRQS=128? That might give me some clues as to which specific
> > code is causing the issues.
>
> It really looks like the issue starts when irq_expand_nr_irqs is called
> the first time to make nr_irqs bigger than NR_IRQS.
And it looks like the irqdomain code is the real culprit.
void irq_set_virq_count(unsigned int count)
{
pr_debug("irq: Trying to set virq count to %d\n", count);
BUG_ON(count < NUM_ISA_INTERRUPTS);
if (count < NR_IRQS)
irq_virq_count = count;
}
That looks simply wrong.....
s/NR_IRQS/nr_irqs/ should do the trick.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Thomas Gleixner @ 2012-04-06 11:12 UTC (permalink / raw)
To: Andreas Schwab
Cc: devicetree-discuss, linux-kernel, Milton Miller, Rob Herring,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <m21uo2v4cw.fsf@igel.home>
On Thu, 5 Apr 2012, Andreas Schwab wrote:
> Grant Likely <grant.likely@secretlab.ca> writes:
>
> > I bet it is NR_IRQS related. You have SPARSE_IRQ enabled, which means
> > the maximum number of irq_descs is IRQ_BITMAP_BITS (NR_IRQS + 8192).
>
> The actual definition uses NR_IRQS + 8196. Guess that's a typo. (Does
> it really make sense to add NR_IRQS here?)
>
> > diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> > index cf417e51..9edf499 100644
> > --- a/arch/powerpc/include/asm/irq.h
> > +++ b/arch/powerpc/include/asm/irq.h
> > @@ -20,7 +20,7 @@
> >
> > /* Define a way to iterate across irqs. */
> > #define for_each_irq(i) \
> > - for ((i) = 0; (i) < NR_IRQS; ++(i))
> > + for ((i) = 0; (i) < nr_irqs; ++(i))
>
> There are exactly two uses of for_each_irq, one is related to cpu
> hotplug, the other to kexec, so that cannot make any difference.
Though that wants to be fixed nevertheless.
Thanks,
tglx
^ permalink raw reply
* [PATCH 1/1] [v3] Add support 2 SATA ports for Maui and change filename from sata_dwc_460ex.c to sata_dwc_4xx.c
From: Thang Q. Nguyen @ 2012-04-06 5:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Jeff Garzik, Grant Likely,
Rob Herring
Cc: Phong Vo, devicetree-discuss, linux-kernel, linux-ide,
Thang Q. Nguyen, linuxppc-dev
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 49323 bytes --]
Signed-off-by: Thang Q. Nguyen <tqnguyen@apm.com>
---
Changes for v2:
- Use git rename feature to change the driver to the newname and for
easier review.
Changes for v3:
- Remove materials not related to 2 SATA ports support. They will
be added in another patches.
drivers/ata/Makefile | 2 +-
drivers/ata/{sata_dwc_460ex.c => sata_dwc_4xx.c} | 820 +++++++++++-----------
2 files changed, 430 insertions(+), 392 deletions(-)
rename drivers/ata/{sata_dwc_460ex.c => sata_dwc_4xx.c} (73%)
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6ece5b7..d225c0c 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
-obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
+obj-$(CONFIG_SATA_DWC) += sata_dwc_4xx.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_4xx.c
similarity index 73%
rename from drivers/ata/sata_dwc_460ex.c
rename to drivers/ata/sata_dwc_4xx.c
index 69f7cde..07e9b36 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_4xx.c
@@ -1,6 +1,4 @@
/*
- * drivers/ata/sata_dwc_460ex.c
- *
* Synopsys DesignWare Cores (DWC) SATA host driver
*
* Author: Mark Miesfeld <mmiesfeld@amcc.com>
@@ -16,6 +14,15 @@
* 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.
+ *
+ * CHANGES:
+ * - Version 1.4:
+ * + Change filename from sata_dwc_460ex.c to sata_dwc_4xx.c
+ * + This driver supports more than one SATA port. Each SATA port has its
+ * own private attribute. Move sata_dwc_host_priv structure to
+ * sata_dwc_device and sata_dwc_device_port structures.
+ * + Change to use ata_bmdma_qc_issue and ata_bmdma_error_handler because
+ * the ata_sff_qc_issue and ata_sff_error_handler no longer support DMA.
*/
#ifdef CONFIG_SATA_DWC_DEBUG
@@ -44,10 +51,10 @@
#undef DRV_NAME
#undef DRV_VERSION
#define DRV_NAME "sata-dwc"
-#define DRV_VERSION "1.3"
+#define DRV_VERSION "1.4"
/* SATA DMA driver Globals */
-#define DMA_NUM_CHANS 1
+#define DMA_NUM_CHANS 2
#define DMA_NUM_CHAN_REGS 8
/* SATA DMA Register definitions */
@@ -158,6 +165,7 @@ enum {
/* 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_CFG_HW_CH_PRIOR(int_num) (((int_num) & 0xF) << 5)
#define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master))
/*
@@ -268,22 +276,25 @@ enum {
<< 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;
+ u8 *scr_base;
+ int dma_channel; /* DWC SATA DMA channel */
+ int hostID;
};
#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 LLI table */
dma_addr_t llit_dma[SATA_DWC_QCMD_MAX];
u32 dma_chan[SATA_DWC_QCMD_MAX];
int dma_pending[SATA_DWC_QCMD_MAX];
+ u32 sactive_issued;
+ u32 sactive_queued;
};
/*
@@ -300,41 +311,39 @@ struct sata_dwc_device_port {
#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *)\
(hsdevp)->hsdev)
+/* Host Controller ID */
enum {
- SATA_DWC_CMD_ISSUED_NOT = 0,
- SATA_DWC_CMD_ISSUED_PEND = 1,
- SATA_DWC_CMD_ISSUED_EXEC = 2,
- SATA_DWC_CMD_ISSUED_NODATA = 3,
+ APM_460EX_SATA = 0,
+ APM_821XX_SATA = 1,
+};
+enum {
SATA_DWC_DMA_PENDING_NONE = 0,
SATA_DWC_DMA_PENDING_TX = 1,
SATA_DWC_DMA_PENDING_RX = 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;
+/* This is used for easier trace back when having DMA channel */
+static struct sata_dwc_device *dwc_dev_list[DMA_NUM_CHANS];
+
+/*
+ * As we have only one DMA controller, this will be set static and global
+ * for easier to access
+ */
+static struct ahb_dma_regs *sata_dma_regs;
+
/*
* 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 int dma_dwc_xfer_setup(struct ata_port *ap, dma_addr_t dma_lli);
static void dma_dwc_xfer_start(int dma_ch);
+static irqreturn_t dma_dwc_interrupt(int irq, struct sata_dwc_device *hsdev);
static const char *get_prot_descript(u8 protocol)
{
@@ -372,15 +381,15 @@ static const char *get_dma_dir_descript(int dma_dir)
}
}
-static void sata_dwc_tf_dump(struct ata_taskfile *tf)
+static void sata_dwc_tf_dump(struct device *dwc_dev, struct ata_taskfile *tf)
{
- dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:"
+ dev_vdbg(dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:"
"0x%lx device: %x\n", tf->command,
get_prot_descript(tf->protocol), tf->flags, tf->device);
- dev_vdbg(host_pvt.dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x "
+ dev_vdbg(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 "
+ dev_vdbg(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);
@@ -416,52 +425,89 @@ static int get_burst_length_encode(int datalength)
static void clear_chan_interrupts(int c)
{
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.tfr.low),
+ out_le32(&sata_dma_regs->interrupt_clear.tfr.low,
DMA_CHANNEL(c));
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.block.low),
+ out_le32(&sata_dma_regs->interrupt_clear.block.low,
DMA_CHANNEL(c));
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.srctran.low),
+ out_le32(&sata_dma_regs->interrupt_clear.srctran.low,
DMA_CHANNEL(c));
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.dsttran.low),
+ out_le32(&sata_dma_regs->interrupt_clear.dsttran.low,
DMA_CHANNEL(c));
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.error.low),
+ out_le32(&sata_dma_regs->interrupt_clear.error.low,
DMA_CHANNEL(c));
}
/*
* Function: dma_request_channel
- * arguments: None
+ * arguments: ap
* 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)
+static int dma_request_channel(struct ata_port *ap)
{
- int i;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
- for (i = 0; i < DMA_NUM_CHANS; i++) {
- if (!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) &\
- DMA_CHANNEL(i)))
- return i;
- }
- 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)));
+ /* Check if the channel is not currently in use */
+ if (!(in_le32(&(sata_dma_regs->dma_chan_en.low)) &\
+ DMA_CHANNEL(hsdev->dma_channel)))
+ return hsdev->dma_channel;
+
+ dev_err(ap->dev, "%s Channel %d is currently in use\n", __func__,
+ hsdev->dma_channel);
return -1;
}
/*
+ * Check if the selected DMA channel is currently enabled.
+ */
+static int sata_dwc_dma_chk_en(int ch)
+{
+ u32 dma_chan_reg;
+ /* Read the DMA channel register */
+ dma_chan_reg = in_le32(&(sata_dma_regs->dma_chan_en.low));
+ /* Check if it is currently enabled */
+ if (dma_chan_reg & DMA_CHANNEL(ch))
+ return 1;
+ return 0;
+}
+
+/*
+ * Handle DMA transfer complete interrupt. This checks and passes the
+ * processing to the appropriate ATA port.
+ */
+static irqreturn_t dma_dwc_handler(int irq, void *hsdev_instance)
+{
+ u32 tfr_reg, err_reg;
+ int chan;
+
+ tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ /* Check for end-of-transfer interrupt. */
+ if (tfr_reg & DMA_CHANNEL(chan))
+ dma_dwc_interrupt(0, dwc_dev_list[chan]);
+
+ /* Check for error interrupt. */
+ if (err_reg & DMA_CHANNEL(chan))
+ dma_dwc_interrupt(0, dwc_dev_list[chan]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
* 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)
+static irqreturn_t dma_dwc_interrupt(int irq, struct sata_dwc_device *hsdev)
{
int chan;
u32 tfr_reg, err_reg;
unsigned long flags;
- struct sata_dwc_device *hsdev =
- (struct sata_dwc_device *)hsdev_instance;
struct ata_host *host = (struct ata_host *)hsdev->host;
struct ata_port *ap;
struct sata_dwc_device_port *hsdevp;
@@ -471,41 +517,25 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
spin_lock_irqsave(&host->lock, flags);
ap = host->ports[port];
hsdevp = HSDEVP_FROM_AP(ap);
- tag = ap->link.active_tag;
- tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\
+ if (ap->link.active_tag != ATA_TAG_POISON)
+ tag = ap->link.active_tag;
+
+ tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr\
.low));
- err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error\
.low));
-
dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n",
tfr_reg, err_reg, hsdevp->dma_pending[tag], port);
- for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
- /* Check for end-of-transfer interrupt. */
+ chan = hsdev->dma_channel;
+ if (chan >= 0) {
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())
- */
- host_pvt.dma_interrupt_count++;
+ /* Clear DMA config after transfer complete */
sata_dwc_clear_dmacr(hsdevp, tag);
- if (hsdevp->dma_pending[tag] ==
- SATA_DWC_DMA_PENDING_NONE) {
- dev_err(ap->dev, "DMA not pending eot=0x%08x "
- "err=0x%08x tag=0x%02x pending=%d\n",
- tfr_reg, err_reg, tag,
- hsdevp->dma_pending[tag]);
- }
-
- if ((host_pvt.dma_interrupt_count % 2) == 0)
- sata_dwc_dma_xfer_complete(ap, 1);
-
/* Clear the interrupt */
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
- .tfr.low),
+ out_le32(&(sata_dma_regs->interrupt_clear.tfr.low),
DMA_CHANNEL(chan));
}
@@ -516,11 +546,16 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
err_reg);
/* Clear the interrupt. */
- out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
+ out_le32(&(sata_dma_regs->interrupt_clear\
.error.low),
DMA_CHANNEL(chan));
}
}
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE;
+
+ if (hsdevp->sactive_queued == 0)
+ ap->link.active_tag = ATA_TAG_POISON;
+
spin_unlock_irqrestore(&host->lock, flags);
return IRQ_HANDLED;
}
@@ -534,21 +569,21 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq)
{
int retval = 0;
- int chan;
- for (chan = 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 error interrupt */
+ out_le32(&sata_dma_regs->interrupt_mask.error.low,
+ in_le32(&sata_dma_regs->interrupt_mask.error.low) |
+ DMA_ENABLE_CHAN(hsdev->dma_channel));
- /* Unmask end-of-transfer interrupt */
- out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.tfr.low,
- DMA_ENABLE_CHAN(chan));
- }
+ /* Unmask end-of-transfer interrupt */
+ out_le32(&sata_dma_regs->interrupt_mask.tfr.low,
+ in_le32(&sata_dma_regs->interrupt_mask.tfr.low) |
+ DMA_ENABLE_CHAN(hsdev->dma_channel));
- retval = request_irq(irq, dma_dwc_interrupt, 0, "SATA DMA", hsdev);
+ retval = request_irq(irq, dma_dwc_handler, IRQF_SHARED, "SATA DMA",
+ hsdev);
if (retval) {
- dev_err(host_pvt.dwc_dev, "%s: could not get IRQ %d\n",
+ dev_err(hsdev->dev, "%s: could not get IRQ %d\n",\
__func__, irq);
return -ENODEV;
}
@@ -567,16 +602,19 @@ static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq)
* 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,
+static int map_sg_to_lli(struct ata_port *ap, struct scatterlist *sg,
+ int num_elems, struct lli *lli, dma_addr_t dma_lli,
void __iomem *dmadr_addr, int dir)
{
+ struct device *dwc_dev = ap->dev;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
int i, idx = 0;
int fis_len = 0;
dma_addr_t next_llp;
int bl;
+ u32 sms_val, dms_val;
- dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x"
+ dev_dbg(dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x"
" dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
(u32)dmadr_addr);
@@ -589,13 +627,13 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
addr = (u32) sg_dma_address(sg);
sg_len = sg_dma_len(sg);
- dev_dbg(host_pvt.dwc_dev, "%s: elem=%d sg_addr=0x%x sg_len"
+ dev_dbg(dwc_dev, "%s: elem=%d sg_addr=0x%x sg_len"
"=%d\n", __func__, i, addr, sg_len);
while (sg_len) {
if (idx >= SATA_DWC_DMAC_LLI_NUM) {
/* The LLI table is not large enough. */
- dev_err(host_pvt.dwc_dev, "LLI table overrun "
+ dev_err(dwc_dev, "LLI table overrun "
"(idx=%d)\n", idx);
break;
}
@@ -614,7 +652,7 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
* the host controller.
*/
if (fis_len + len > 8192) {
- dev_dbg(host_pvt.dwc_dev, "SPLITTING: fis_len="
+ dev_dbg(dwc_dev, "SPLITTING: fis_len="
"%d(0x%x) len=%d(0x%x)\n", fis_len,
fis_len, len, len);
len = 8192 - fis_len;
@@ -629,14 +667,22 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
* Set DMA addresses and lower half of control register
* based on direction.
*/
+ if (hsdevp->hsdev->hostID == APM_821XX_SATA) {
+ sms_val = 1+hsdevp->hsdev->dma_channel;
+ dms_val = 0;
+ } else {
+ sms_val = 0;
+ dms_val = 1+hsdevp->hsdev->dma_channel;
+ }
+
if (dir == DMA_FROM_DEVICE) {
lli[idx].dar = cpu_to_le32(addr);
lli[idx].sar = cpu_to_le32((u32)dmadr_addr);
lli[idx].ctl.low = cpu_to_le32(
DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
- DMA_CTL_SMS(0) |
- DMA_CTL_DMS(1) |
+ DMA_CTL_SMS(sms_val) |
+ DMA_CTL_DMS(dms_val) |
DMA_CTL_SRC_MSIZE(bl) |
DMA_CTL_DST_MSIZE(bl) |
DMA_CTL_SINC_NOCHANGE |
@@ -651,8 +697,8 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
lli[idx].ctl.low = cpu_to_le32(
DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
- DMA_CTL_SMS(1) |
- DMA_CTL_DMS(0) |
+ DMA_CTL_SMS(dms_val) |
+ DMA_CTL_DMS(sms_val) |
DMA_CTL_SRC_MSIZE(bl) |
DMA_CTL_DST_MSIZE(bl) |
DMA_CTL_DINC_NOCHANGE |
@@ -663,7 +709,7 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
DMA_CTL_LLP_DSTEN);
}
- dev_dbg(host_pvt.dwc_dev, "%s setting ctl.high len: "
+ dev_dbg(dwc_dev, "%s setting ctl.high len: "
"0x%08x val: 0x%08x\n", __func__,
len, DMA_CTL_BLK_TS(len / 4));
@@ -678,7 +724,13 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
lli)));
/* The last 2 bits encode the list master select. */
- next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2);
+ if (hsdevp->hsdev->hostID == APM_460EX_SATA) {
+ next_llp = DMA_LLP_LMS(next_llp,
+ DMA_LLP_AHBMASTER2);
+ } else {
+ next_llp = DMA_LLP_LMS(next_llp,
+ DMA_LLP_AHBMASTER1);
+ }
lli[idx].llp = cpu_to_le32(next_llp);
idx++;
@@ -714,70 +766,49 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
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)) |
+ out_le32(&(sata_dma_regs->dma_chan_en.low),
+ in_le32(&(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)
+
+static int dma_dwc_xfer_setup(struct ata_port *ap, dma_addr_t dma_lli)
{
int dma_ch;
- int num_lli;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
/* Acquire DMA channel */
- dma_ch = dma_request_channel();
+ dma_ch = dma_request_channel(ap);
if (dma_ch == -1) {
- dev_err(host_pvt.dwc_dev, "%s: dma channel unavailable\n",
- __func__);
+ dev_err(ap->dev, "%s: dma channel unavailable\n", __func__);
return -EAGAIN;
}
- /* Convert SG list to linked list of items (LLIs) for AHB DMA */
- num_lli = 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_chan_interrupts(dma_ch);
/* Program the CFG register. */
- out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high),
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high),
+ DMA_CFG_HW_HS_SRC(dma_ch) | DMA_CFG_HW_HS_DEST(dma_ch) | \
DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
- out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low), 0);
+
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low),
+ DMA_CFG_HW_CH_PRIOR(dma_ch));
/* Program the address of the linked list */
- out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low),
+ if (hsdev->hostID == APM_460EX_SATA) {
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
+ } else {
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
+ DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER1));
+ }
/* Program the CTL register with src enable / dst enable */
- out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].ctl.low),
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low),
DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN);
return dma_ch;
}
/*
- * 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);
- host_pvt.sata_dma_regs = NULL;
- }
-
- if (hsdev->irq_dma) {
- free_irq(hsdev->irq_dma, hsdev);
- hsdev->irq_dma = 0;
- }
-}
-
-/*
* Function: dma_dwc_init
* arguments: hsdev
* returns status
@@ -789,24 +820,18 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
err = 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;
+ dev_err(hsdev->dev, "%s: dma_request_interrupts returns %d\n",
+ __func__, err);
+ return err;
}
/* Enabe DMA */
- out_le32(&(host_pvt.sata_dma_regs->dma_cfg.low), DMA_EN);
+ out_le32(&(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=0x%p\n", host_pvt.\
- sata_dma_regs);
+ dev_notice(hsdev->dev, "DMA initialized\n");
+ dev_dbg(hsdev->dev, "SATA DMA registers=0x%p\n", 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)
@@ -818,7 +843,7 @@ static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
}
*val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
- dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=0x%08x\n",
__func__, link->ap->print_id, scr, *val);
return 0;
@@ -838,23 +863,27 @@ static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
return 0;
}
-static u32 core_scr_read(unsigned int scr)
+static u32 core_scr_read(struct ata_port *ap, unsigned int scr)
{
- return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\
- (scr * 4));
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ return in_le32((void __iomem *)hsdev->scr_base + (scr * 4));
}
-static void core_scr_write(unsigned int scr, u32 val)
+
+static void core_scr_write(struct ata_port *ap, unsigned int scr, u32 val)
{
- out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4),
- val);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ out_le32((void __iomem *)hsdev->scr_base + (scr * 4), val);
}
-static void clear_serror(void)
+static void clear_serror(struct ata_port *ap)
{
- u32 val;
- val = core_scr_read(SCR_ERROR);
- core_scr_write(SCR_ERROR, val);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ out_le32((void __iomem *)hsdev->scr_base + 4,
+ in_le32((void __iomem *)hsdev->scr_base + 4));
}
@@ -869,7 +898,6 @@ static 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)
{
@@ -883,24 +911,23 @@ static void sata_dwc_error_intr(struct ata_port *ap,
ata_ehi_clear_desc(ehi);
- serror = core_scr_read(SCR_ERROR);
+ serror = core_scr_read(ap, SCR_ERROR);
status = ap->ops->sff_check_status(ap);
- err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error.\
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.\
low));
tag = ap->link.active_tag;
dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x "
- "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n",
- __func__, serror, intpr, status, host_pvt.dma_interrupt_count,
- hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg);
+ " pending=%d dma_err_status=0x%08x\n",
+ __func__, serror, intpr, status, hsdevp->dma_pending[tag],
+ err_reg);
/* Clear error register and interrupt bit */
- clear_serror();
+ clear_serror(ap);
clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR);
/* This is the only error happening now. TODO check for exact error */
-
err_mask |= AC_ERR_HOST_BUS;
action |= ATA_EH_RESET;
@@ -919,7 +946,7 @@ static void sata_dwc_error_intr(struct ata_port *ap,
/*
* Function : sata_dwc_isr
- * arguments : irq, void *dev_instance, struct pt_regs *regs
+ * arguments : irq, void *dev_instance
* Return value : irqreturn_t - status of IRQ
* This Interrupt handler called via port ops registered function.
* .irq_handler = sata_dwc_isr
@@ -930,14 +957,14 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host);
struct ata_port *ap;
struct ata_queued_cmd *qc;
- unsigned long flags;
u8 status, tag;
- int handled, num_processed, port = 0;
- uint intpr, sactive, sactive2, tag_mask;
+ int handled, port = 0;
+ int num_lli;
+ uint intpr, sactive, tag_mask;
struct sata_dwc_device_port *hsdevp;
- host_pvt.sata_dwc_sactive_issued = 0;
+ u32 mask;
- spin_lock_irqsave(&host->lock, flags);
+ spin_lock(&host->lock);
/* Read the interrupt register */
intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
@@ -960,29 +987,44 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr));
+ mask = qcmd_tag_to_mask(tag);
dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag);
- if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND)
+ if ((hsdevp->sactive_queued & mask) == 0)
dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag);
- host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag);
-
qc = 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 = tag;
- sata_dwc_bmdma_start_by_tag(qc, tag);
+ if (qc) {
+ hsdevp->sactive_issued |= mask;
+ /* Prevent to issue more commands */
+ qc->ap->link.active_tag = tag;
+ qc->dev->link->sactive |= (1 << qc->tag);
+ num_lli = map_sg_to_lli(ap, qc->sg, qc->n_elem, \
+ hsdevp->llit[tag], hsdevp->llit_dma[tag], \
+ (void *__iomem)(&hsdev->sata_dwc_regs->dmadr), \
+ qc->dma_dir);
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+ wmb();
+ qc->ap->hsm_task_state = HSM_ST_LAST;
+ } else {
+ hsdevp->sactive_issued &= ~mask;
+ dev_warn(ap->dev, "No QC available for tag %d (intpr="
+ "0x%08x, qc_allocated=0x%08x)\n", tag, intpr,
+ ap->qc_allocated);
+ }
handled = 1;
goto DONE;
}
- sactive = core_scr_read(SCR_ACTIVE);
- tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive;
+ sactive = core_scr_read(ap, SCR_ACTIVE);
+ tag_mask = (hsdevp->sactive_issued | sactive) ^ sactive;
/* If no sactive issued and tag_mask is zero then this is not NCQ */
- if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) {
+ if (hsdevp->sactive_issued == 0 && tag_mask == 0) {
if (ap->link.active_tag == ATA_TAG_POISON)
tag = 0;
else
@@ -999,9 +1041,6 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
}
status = ap->ops->sff_check_status(ap);
- qc->ap->link.active_tag = tag;
- hsdevp->cmd_issued[tag] = 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);
@@ -1012,28 +1051,12 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
__func__, get_prot_descript(qc->tf.protocol));
DRVSTILLBUSY:
+ /* Do complete action for the current QC */
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.
- */
- host_pvt.dma_interrupt_count++;
- if (hsdevp->dma_pending[tag] == \
- SATA_DWC_DMA_PENDING_NONE) {
- dev_err(ap->dev, "%s: DMA not pending "
- "intpr=0x%08x status=0x%08x pending"
- "=%d\n", __func__, intpr, status,
- hsdevp->dma_pending[tag]);
- }
-
- if ((host_pvt.dma_interrupt_count % 2) == 0)
- sata_dwc_dma_xfer_complete(ap, 1);
- } else if (ata_is_pio(qc->tf.protocol)) {
+ sata_dwc_qc_complete(ap, qc, 1);
+ } else if ((ata_is_pio(qc->tf.protocol)) ||
+ (ata_is_nodata(qc->tf.protocol))) {
ata_sff_hsm_move(ap, qc, status, 0);
- handled = 1;
- goto DONE;
} else {
if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
goto DRVSTILLBUSY;
@@ -1049,23 +1072,18 @@ DRVSTILLBUSY:
* as completion for more than one operation when commands are queued
* (NCQ). We need to process each completed command.
*/
-
- /* process completed commands */
- sactive = core_scr_read(SCR_ACTIVE);
- tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive;
-
- if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \
+ if (sactive != 0 || hsdevp->sactive_issued > 1 || \
tag_mask > 1) {
dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x"
"tag_mask=0x%08x\n", __func__, sactive,
- host_pvt.sata_dwc_sactive_issued, tag_mask);
+ hsdevp->sactive_issued, tag_mask);
}
- if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \
- (host_pvt.sata_dwc_sactive_issued)) {
+ if ((tag_mask | hsdevp->sactive_issued) != \
+ hsdevp->sactive_issued) {
dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x "
- "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask"
- "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued,
+ "sactive_issued=0x%08x tag_mask"
+ "=0x%08x\n", sactive, hsdevp->sactive_issued,
tag_mask);
}
@@ -1073,70 +1091,21 @@ DRVSTILLBUSY:
status = ap->ops->sff_check_status(ap);
dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
- tag = 0;
- num_processed = 0;
- while (tag_mask) {
- num_processed++;
- while (!(tag_mask & 0x00000001)) {
- tag++;
- tag_mask <<= 1;
- }
-
- tag_mask &= (~0x00000001);
- qc = ata_qc_from_tag(ap, tag);
-
- /* To be picked up by completion functions */
- qc->ap->link.active_tag = tag;
- hsdevp->cmd_issued[tag] = 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);
+ for (tag = 0; tag < 32; tag++) {
+ if (tag_mask & qcmd_tag_to_mask(tag)) {
+ qc = ata_qc_from_tag(ap, tag);
+ if (!qc) {
+ dev_info(ap->dev, "error: Tag %d is set but " \
+ "not available\n", tag);
+ continue;
+ }
sata_dwc_qc_complete(ap, qc, 1);
- handled = 1;
- goto DONE;
}
-
- /* Process completed command */
- dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__,
- get_prot_descript(qc->tf.protocol));
- if (ata_is_dma(qc->tf.protocol)) {
- host_pvt.dma_interrupt_count++;
- if (hsdevp->dma_pending[tag] == \
- SATA_DWC_DMA_PENDING_NONE)
- dev_warn(ap->dev, "%s: DMA not pending?\n",
- __func__);
- if ((host_pvt.dma_interrupt_count % 2) == 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 (read 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 = core_scr_read(SCR_ACTIVE);
- if (sactive2 != sactive) {
- dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2"
- "=0x%x\n", sactive, sactive2);
}
handled = 1;
DONE:
- spin_unlock_irqrestore(&host->lock, flags);
+ spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
}
@@ -1157,7 +1126,7 @@ static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
* 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"
+ dev_err(hsdev->dev, "%s DMA protocol RX and"
"TX DMA not pending tag=0x%02x pending=%d"
" dmacr: 0x%08x\n", __func__, tag,
hsdevp->dma_pending[tag],
@@ -1167,44 +1136,6 @@ static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
}
}
-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 = HSDEVP_FROM_AP(ap);
- struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
- u8 tag = 0;
-
- tag = ap->link.active_tag;
- qc = ata_qc_from_tag(ap, tag);
- if (!qc) {
- dev_err(ap->dev, "failed to get qc");
- return;
- }
-
-#ifdef DEBUG_NCQ
- if (tag > 0) {
- dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s "
- "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command,
- get_dma_dir_descript(qc->dma_dir),
- get_prot_descript(qc->tf.protocol),
- in_le32(&(hsdev->sata_dwc_regs->dmacr)));
- }
-#endif
-
- if (ata_is_dma(qc->tf.protocol)) {
- if (hsdevp->dma_pending[tag] == 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] = SATA_DWC_DMA_PENDING_NONE;
- sata_dwc_qc_complete(ap, qc, check_status);
- ap->link.active_tag = 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)
@@ -1213,24 +1144,39 @@ static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
u32 mask = 0x0;
u8 tag = qc->tag;
struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
- host_pvt.sata_dwc_sactive_queued = 0;
+ int i;
+
dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status);
- if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX)
- dev_err(ap->dev, "TX DMA PENDING\n");
- else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX)
- dev_err(ap->dev, "RX DMA PENDING\n");
+ /* Check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+
+ if (check_status) {
+ /* Make sure SATA port is not in BUSY state */
+ i = 0;
+ while (status & ATA_BUSY) {
+ if (++i > 10)
+ break;
+ status = ap->ops->sff_check_altstatus(ap);
+ };
+
+ if (unlikely(status & ATA_BUSY))
+ dev_err(ap->dev, "QC complete cmd=0x%02x STATUS BUSY "
+ "(0x%02x) [%d]\n", qc->tf.command, status, i);
+ }
dev_dbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u:"
" protocol=%d\n", qc->tf.command, status, ap->print_id,
qc->tf.protocol);
/* clear active bit */
mask = (~(qcmd_tag_to_mask(tag)));
- host_pvt.sata_dwc_sactive_queued = (host_pvt.sata_dwc_sactive_queued) \
- & mask;
- host_pvt.sata_dwc_sactive_issued = (host_pvt.sata_dwc_sactive_issued) \
- & mask;
+ hsdevp->sactive_issued &= ~mask;
+
ata_qc_complete(qc);
+
+ if (hsdevp->sactive_queued == 0)
+ ap->link.active_tag = ATA_TAG_POISON;
+
return 0;
}
@@ -1248,7 +1194,7 @@ static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
*/
out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS);
- dev_dbg(host_pvt.dwc_dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n",
+ dev_dbg(hsdev->dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n",
__func__, in_le32(&hsdev->sata_dwc_regs->intmr),
in_le32(&hsdev->sata_dwc_regs->errmr));
}
@@ -1310,9 +1256,6 @@ static int sata_dwc_port_start(struct ata_port *ap)
}
hsdevp->hsdev = hsdev;
- for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
- hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
-
ap->bmdma_prd = 0; /* set these so libata doesn't use them */
ap->bmdma_prd_dma = 0;
@@ -1329,7 +1272,7 @@ static int sata_dwc_port_start(struct ata_port *ap)
dev_err(ap->dev, "%s: dma_alloc_coherent failed\n",
__func__);
err = -ENOMEM;
- goto CLEANUP_ALLOC;
+ goto CLEANUP;
}
}
@@ -1347,15 +1290,16 @@ static int sata_dwc_port_start(struct ata_port *ap)
}
/* Clear any error bits before libata starts issuing commands */
- clear_serror();
+ clear_serror(ap);
ap->private_data = hsdevp;
dev_dbg(ap->dev, "%s: done\n", __func__);
return 0;
-CLEANUP_ALLOC:
- kfree(hsdevp);
CLEANUP:
- dev_dbg(ap->dev, "%s: fail. ap->id = %d\n", __func__, ap->print_id);
+ sata_dwc_port_stop(ap);
+ kfree(hsdevp);
+ dev_dbg(ap->dev, "%s: fail\n", __func__);
+
return err;
}
@@ -1382,14 +1326,14 @@ static void sata_dwc_port_stop(struct ata_port *ap)
/*
* Function : sata_dwc_exec_command_by_tag
- * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued
+ * arguments : ata_port *ap, ata_taskfile *tf, u8 tag
* 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)
+ u8 tag)
{
unsigned long flags;
struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
@@ -1398,7 +1342,7 @@ static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
ata_get_cmd_descript(tf->command), tag);
spin_lock_irqsave(&ap->host->lock, flags);
- hsdevp->cmd_issued[tag] = cmd_issued;
+ hsdevp->sactive_queued |= qcmd_tag_to_mask(tag);
spin_unlock_irqrestore(&ap->host->lock, flags);
/*
* Clear SError before executing a new command.
@@ -1406,15 +1350,10 @@ static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
* managed SError register for the disk needs to be done before the
* task file is loaded.
*/
- clear_serror();
+ clear_serror(ap);
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)
{
@@ -1426,7 +1365,8 @@ static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc)
} else {
tag = 0;
}
- sata_dwc_bmdma_setup_by_tag(qc, tag);
+
+ sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag);
}
static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
@@ -1437,28 +1377,37 @@ static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
struct ata_port *ap = qc->ap;
struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
int dir = qc->dma_dir;
- dma_chan = hsdevp->dma_chan[tag];
- if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) {
+ /* Configure DMA before starting data transfer */
+ dma_chan = dma_dwc_xfer_setup(ap, hsdevp->llit_dma[tag]);
+ if (unlikely(dma_chan < 0)) {
+ dev_err(ap->dev, "%s: dma channel unavailable\n", __func__);
+ /* Offending this QC as no channel available for transfer */
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ return;
+ }
+
+ /* Check if DMA should be started */
+ hsdevp->dma_chan[tag] = dma_chan;
+ if (hsdevp->sactive_queued & qcmd_tag_to_mask(tag)) {
start_dma = 1;
if (dir == DMA_TO_DEVICE)
hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX;
else
hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX;
} else {
- dev_err(ap->dev, "%s: Command not pending cmd_issued=%d "
- "(tag=%d) DMA NOT started\n", __func__,
- hsdevp->cmd_issued[tag], tag);
+ dev_err(ap->dev, "%s: No pending cmd at tag %d\n",
+ __func__, tag);
start_dma = 0;
}
dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s "
"start_dma? %x\n", __func__, qc, tag, qc->tf.command,
get_dma_dir_descript(qc->dma_dir), start_dma);
- sata_dwc_tf_dump(&(qc->tf));
+ sata_dwc_tf_dump(hsdev->dev, &qc->tf);
if (start_dma) {
- reg = core_scr_read(SCR_ERROR);
+ reg = core_scr_read(qc->ap, SCR_ERROR);
if (reg & SATA_DWC_SERROR_ERR_BITS) {
dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n",
__func__, reg);
@@ -1473,6 +1422,7 @@ static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
/* Enable AHB DMA transfer on the specified channel */
dma_dwc_xfer_start(dma_chan);
+ hsdevp->sactive_queued &= ~qcmd_tag_to_mask(tag);
}
}
@@ -1490,6 +1440,49 @@ static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
sata_dwc_bmdma_start_by_tag(qc, tag);
}
+static void sata_dwc_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ int dma_ch, enabled;
+
+ dma_ch = hsdev->dma_channel;
+ enabled = sata_dwc_dma_chk_en(dma_ch);
+
+ if (enabled) {
+ dev_dbg(ap->dev,
+ "%s terminate DMA on channel=%d (mask=0x%08x) ...",
+ __func__, dma_ch, DMA_DISABLE_CHAN(dma_ch));
+ /* Disable the selected channel */
+ out_le32(&(sata_dma_regs->dma_chan_en.low),
+ DMA_DISABLE_CHAN(dma_ch));
+
+ /* Wait for the channel is disabled */
+ do {
+ enabled = sata_dwc_dma_chk_en(dma_ch);
+ ndelay(1000);
+ } while (enabled);
+ dev_dbg(ap->dev, "done\n");
+ }
+}
+
+static u8 sata_dwc_bmdma_status(struct ata_port *ap)
+{
+ u32 status = 0;
+ u32 tfr_reg, err_reg;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ /* Check DMA register for status */
+ tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
+
+ if (unlikely(err_reg & DMA_CHANNEL(hsdev->dma_channel)))
+ status = ATA_DMA_ERR;
+ else if (tfr_reg & DMA_CHANNEL(hsdev->dma_channel))
+ status = ATA_DMA_INTR;
+ return status;
+}
+
/*
* Function : sata_dwc_qc_prep_by_tag
* arguments : ata_queued_cmd *qc, u8 tag
@@ -1500,24 +1493,22 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
{
struct scatterlist *sg = qc->sg;
struct ata_port *ap = qc->ap;
- int dma_chan;
+ int num_lli;
struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
+ return;
dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n",
__func__, ap->port_no, get_dma_dir_descript(qc->dma_dir),
qc->n_elem);
- dma_chan = 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__, dma_chan);
- return;
+ if (!ata_is_ncq(qc->tf.protocol)) {
+ num_lli = map_sg_to_lli(qc->ap, sg, qc->n_elem,
+ hsdevp->llit[tag], hsdevp->llit_dma[tag],
+ (void *__iomem)(&hsdev->sata_dwc_regs->dmadr),
+ qc->dma_dir);
}
- hsdevp->dma_chan[tag] = dma_chan;
}
static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
@@ -1541,19 +1532,18 @@ static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
sata_dwc_qc_prep_by_tag(qc, tag);
if (ata_is_ncq(qc->tf.protocol)) {
- sactive = core_scr_read(SCR_ACTIVE);
+ /* Update SActive register for new command */
+ sactive = core_scr_read(qc->ap, SCR_ACTIVE);
sactive |= (0x00000001 << tag);
- core_scr_write(SCR_ACTIVE, sactive);
-
- dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x "
- "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive,
- sactive);
+ core_scr_write(qc->ap, SCR_ACTIVE, sactive);
+ qc->dev->link->sactive |= 0x00000001 << tag;
ap->ops->sff_tf_load(ap, &qc->tf);
- sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag,
- SATA_DWC_CMD_ISSUED_PEND);
+ sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag);
} else {
- ata_sff_qc_issue(qc);
+ /* As ata_sff_qc_issue is no longer handle DMA transfer,
+ * change to use ata_bmdma_qc_issue instead */
+ ata_bmdma_qc_issue(qc);
}
return 0;
}
@@ -1582,7 +1572,12 @@ static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
static void sata_dwc_error_handler(struct ata_port *ap)
{
ap->link.flags |= ATA_LFLAG_NO_HRST;
- ata_sff_error_handler(ap);
+ ata_bmdma_error_handler(ap);
+}
+
+u8 sata_dwc_check_altstatus(struct ata_port *ap)
+{
+ return ioread8(ap->ioaddr.altstatus_addr);
}
/*
@@ -1616,6 +1611,10 @@ static struct ata_port_operations sata_dwc_ops = {
.bmdma_setup = sata_dwc_bmdma_setup,
.bmdma_start = sata_dwc_bmdma_start,
+ .bmdma_stop = sata_dwc_bmdma_stop,
+ .bmdma_status = sata_dwc_bmdma_status,
+
+ .sff_check_altstatus = sata_dwc_check_altstatus,
};
static const struct ata_port_info sata_dwc_port_info[] = {
@@ -1638,13 +1637,38 @@ static int sata_dwc_probe(struct platform_device *ofdev)
struct ata_host *host;
struct ata_port_info pi = sata_dwc_port_info[0];
const struct ata_port_info *ppi[] = { &pi, NULL };
+ const unsigned int *dma_chan;
+
+ /* Check if device is declared in device tree */
+ if (!of_device_is_available(ofdev->dev.of_node)) {
+ printk(KERN_INFO "%s: Port disabled via device-tree\n",
+ ofdev->dev.of_node->full_name);
+ return 0;
+ }
/* Allocate DWC SATA device */
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
if (hsdev == NULL) {
dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
err = -ENOMEM;
- goto error;
+ goto error_out_5;
+ }
+
+ /* Identify host controller using compatible attribute */
+ if (of_device_is_compatible(ofdev->dev.of_node, "amcc,sata-apm821xx")) {
+ printk(KERN_INFO "SATA is compatible for sata-821xx\n");
+ hsdev->hostID = APM_821XX_SATA;
+ } else {
+ printk(KERN_INFO "SATA is compatible for sata-460ex\n");
+ hsdev->hostID = APM_460EX_SATA;
+ }
+
+ dma_chan = of_get_property(ofdev->dev.of_node, "dma-channel", NULL);
+ if (dma_chan) {
+ dev_notice(&ofdev->dev, "Getting DMA channel %d\n", *dma_chan);
+ hsdev->dma_channel = *dma_chan;
+ } else {
+ hsdev->dma_channel = 0;
}
/* Ioremap SATA registers */
@@ -1653,7 +1677,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
dev_err(&ofdev->dev, "ioremap failed for SATA register"
" address\n");
err = -ENODEV;
- goto error_kmalloc;
+ goto error_out_4;
}
hsdev->reg_base = base;
dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
@@ -1666,7 +1690,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
if (!host) {
dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
err = -ENOMEM;
- goto error_iomap;
+ goto error_out_4;
}
host->private_data = hsdev;
@@ -1674,7 +1698,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
/* Setup port */
host->ports[0]->ioaddr.cmd_addr = base;
host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
- host_pvt.scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET;
+ hsdev->scr_base = (u8 *)(base + SATA_DWC_SCR_OFFSET);
sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base);
/* Read the ID and Version Registers */
@@ -1688,23 +1712,30 @@ static int sata_dwc_probe(struct platform_device *ofdev)
if (irq == NO_IRQ) {
dev_err(&ofdev->dev, "no SATA DMA irq\n");
err = -ENODEV;
- goto error_out;
- }
-
- /* Get physical SATA DMA register base address */
- host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1);
- if (!(host_pvt.sata_dma_regs)) {
- dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
- " address\n");
- err = -ENODEV;
- goto error_out;
+ goto error_out_3;
}
/* Save dev for later use in dev_xxx() routines */
- host_pvt.dwc_dev = &ofdev->dev;
+ hsdev->dev = &ofdev->dev;
- /* Initialize AHB DMAC */
- dma_dwc_init(hsdev, irq);
+ /* Init glovbal dev list */
+ dwc_dev_list[hsdev->dma_channel] = hsdev;
+
+ /* Get physical SATA DMA register base address */
+ if (sata_dma_regs == NULL) {
+ sata_dma_regs = of_iomap(ofdev->dev.of_node, 1);
+ if (sata_dma_regs == NULL) {
+ dev_err(&ofdev->dev,
+ "ioremap failed for AHBDMA register address\n");
+ err = -ENODEV;
+ goto error_out_2;
+ }
+
+ /* Initialize AHB DMAC */
+ rc = dma_dwc_init(hsdev, irq);
+ if (rc != 0)
+ goto error_out_1;
+ }
/* Enable SATA Interrupts */
sata_dwc_enable_interrupts(hsdev);
@@ -1714,7 +1745,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
if (irq == NO_IRQ) {
dev_err(&ofdev->dev, "no SATA DMA irq\n");
err = -ENODEV;
- goto error_out;
+ goto error_out_1;
}
/*
@@ -1730,15 +1761,19 @@ static int sata_dwc_probe(struct platform_device *ofdev)
dev_set_drvdata(&ofdev->dev, host);
return 0;
-error_out:
- /* Free SATA DMA resources */
- dma_dwc_exit(hsdev);
+error_out_1:
+ iounmap(sata_dma_regs);
-error_iomap:
+error_out_2:
+ free_irq(hsdev->irq_dma, hsdev);
+
+error_out_3:
iounmap(base);
-error_kmalloc:
+
+error_out_4:
kfree(hsdev);
-error:
+
+error_out_5:
return err;
}
@@ -1752,8 +1787,10 @@ static int sata_dwc_remove(struct platform_device *ofdev)
dev_set_drvdata(dev, NULL);
/* Free SATA DMA resources */
- dma_dwc_exit(hsdev);
+ iounmap(sata_dma_regs);
+ free_irq(hsdev->irq_dma, hsdev);
+ /* Free internal resources */
iounmap(hsdev->reg_base);
kfree(hsdev);
kfree(host);
@@ -1763,6 +1800,7 @@ static int sata_dwc_remove(struct platform_device *ofdev)
static const struct of_device_id sata_dwc_match[] = {
{ .compatible = "amcc,sata-460ex", },
+ { .compatible = "amcc,sata-apm821xx", },
{}
};
MODULE_DEVICE_TABLE(of, sata_dwc_match);
--
1.7.3.4
CONFIDENTIALITY NOTICE: This e-mail message, including any attachments,
is for the sole use of the intended recipient(s) and contains information
that is confidential and proprietary to AppliedMicro Corporation or its subsidiaries.
It is to be used solely for the purpose of furthering the parties' business relationship.
All unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by reply e-mail
and destroy all copies of the original message.
^ permalink raw reply related
* RE: [RFC] powerpc/fsl-pci: Document the "fsl,has-isa" property for Freescale PCI
From: Jia Hongtao-B38951 @ 2012-04-06 3:04 UTC (permalink / raw)
To: Kumar Gala
Cc: devicetree-discuss@lists.ozlabs.org,
linuxppc-dev@lists.ozlabs.org, Li Yang-R58472
In-Reply-To: <E3DD739D-1EC3-4BCA-AE26-1EAE7A086A1E@kernel.crashing.org>
> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Wednesday, April 04, 2012 9:09 PM
> To: Jia Hongtao-B38951
> Cc: linuxppc-dev@lists.ozlabs.org; Li Yang-R58472; devicetree-
> discuss@lists.ozlabs.org
> Subject: Re: [RFC] powerpc/fsl-pci: Document the "fsl,has-isa" property
> for Freescale PCI
>=20
>=20
> On Apr 1, 2012, at 1:56 AM, Jia Hongtao wrote:
>=20
> > If PCI is primary bus we should set isa_io/mem_base when parsing PCI
> bridge
> > resources from device tree. The previous way to check the primary bus
> based
> > on a hard-coded address named primary_phb_addr. Now we add a property
> named
> > "fsl,has-isa" into device tree. In kernel we use this property to find
> out
> > the bus is primary or not. This way is more flexible.
> >
> > Signed-off-by: Jia Hongtao <B38951@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > .../devicetree/bindings/powerpc/fsl/pci.txt | 36
> ++++++++++++++++++++
> > 1 files changed, 36 insertions(+), 0 deletions(-)
> > create mode 100644
> Documentation/devicetree/bindings/powerpc/fsl/pci.txt
>=20
> This isn't freescale specific, its linux specific. If anything the
> property should be linux,has-isa.
>=20
> But in general I dont think this is a good idea. In truth one could
> search the device tree for:
>=20
> device_type =3D "isa";
>=20
> to try and set this dynamically.
>=20
> - k
>=20
Yes, it's not Freescale specific, but it's only used by Freescale now in
the kernel. This is why I named the property as "fsl,has-isa".
To indicate PCI bus is primary we have three ways to go and we now like
the 2nd solution:
1. As this patch said, we add a property to device tree manually.
2. Set this property dynamically in uboot when scanning PCI bridge.
Actually we have already done this. The problem is users should update
uboot and kernel together or it's not work. To support old uboot we decide
to add this property into device tree too temporarily. We will remove it
from device tree at an appropriate future.
3. Just as you said we could search the device tree by device_type =3D "isa=
".
There are two problems here:
* There is no OF API for searching just in PCI node now. That means
we can't easily find whether there is "isa" bridge or not under
this PCI controller while scanning it.
* Boards MPC8541CDS and MPC8555CDS has no "isa" node in device tree
but has ISA bridge under PCI controller.
- Jia Hongtao
^ permalink raw reply
* Re: [PATCH 03/12] powerpc: Rework runlatch code
From: Andreas Schwab @ 2012-04-05 23:05 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1333663961.3040.34.camel@pasglop>
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> Have you verified that you can "fix" it with reverting just the above
> patch ?
Yes.
(Currently running 3.4-rc1 with fe1952f reverted and irq_set_irq_type
removed from mpic_host_map.)
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH 03/12] powerpc: Rework runlatch code
From: Benjamin Herrenschmidt @ 2012-04-05 22:12 UTC (permalink / raw)
To: Andreas Schwab; +Cc: linuxppc-dev
In-Reply-To: <m2vcldamh2.fsf@igel.home>
On Thu, 2012-04-05 at 23:38 +0200, Andreas Schwab wrote:
> Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
>
> > This moves the inlines into system.h and changes the runlatch
> > code to use the thread local flags (non-atomic) rather than
> > the TIF flags (atomic) to keep track of the latch state.
> >
> > The code to turn it back on in an asynchronous interrupt is
> > now simplified and partially inlined.
>
> This breaks the X server in that it no longer receives SIGIO signals.
Interesting. I have not observed that on my machine here, however I have
seen on my dual G5 (and not on the quad) some occasional loss of
interrupts for seconds which might be related.
Have you verified that you can "fix" it with reverting just the above
patch ? I would have more easily blamed the rest of my series than this
specific one... Anyways, I'll have a closer look but it might have to
wait for tuesday.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH v5 06/27] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead
From: Andreas Schwab @ 2012-04-05 22:10 UTC (permalink / raw)
To: Grant Likely
Cc: devicetree-discuss, linux-kernel, Milton Miller, Rob Herring,
Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20120404154020.40C513E09D5@localhost>
Grant Likely <grant.likely@secretlab.ca> writes:
> Can you attach console output logs for each of configs above and also
> with NR_IRQS=128? That might give me some clues as to which specific
> code is causing the issues.
It really looks like the issue starts when irq_expand_nr_irqs is called
the first time to make nr_irqs bigger than NR_IRQS.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: [PATCH 03/12] powerpc: Rework runlatch code
From: Andreas Schwab @ 2012-04-05 21:38 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1330680922-6894-4-git-send-email-benh__48089.0872575857$1330681158$gmane$org@kernel.crashing.org>
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> This moves the inlines into system.h and changes the runlatch
> code to use the thread local flags (non-atomic) rather than
> the TIF flags (atomic) to keep track of the latch state.
>
> The code to turn it back on in an asynchronous interrupt is
> now simplified and partially inlined.
This breaks the X server in that it no longer receives SIGIO signals.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply
* Re: kilauea compilation breaks with v3.3 kernel and ELDK 4.2
From: Wolfgang Denk @ 2012-04-05 17:44 UTC (permalink / raw)
To: Stephen Rothwell; +Cc: linuxppc-dev, robert.karl.berger, Frank Svendsbøe
In-Reply-To: <20120405100228.9ca940aa4739e81540bb2a6f@canb.auug.org.au>
Dear Stephen Rothwell,
In message <20120405100228.9ca940aa4739e81540bb2a6f@canb.auug.org.au> you wrote:
>
> > ELDK 4.2 is based on gcc version 4.2.2 / binutils version 2.17.50.0.12
> > 20070128. This is obviously to old for this code. I do not see an
> > actual problem with that - nobody can expect that we support old tol
> > chain versions forever.
>
> The requirements are documented in Documentation/Changes where we say we
> need gcc 3.2 and binutils 2.12. Not that that is very relevant to this
> discussion. ;-)
Indeed. I doubt you can build any working PPC kernel with these old
tools.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
"Consistency requires you to be as ignorant today as you were a year
ago." - Bernard Berenson
^ permalink raw reply
* [PATCH 3/4 v2] powerpc: Better scheduling of CR save code in system call path
From: Anton Blanchard @ 2012-04-05 13:44 UTC (permalink / raw)
To: benh, paulus; +Cc: linuxppc-dev
In-Reply-To: <20120405142557.398f14d2@kryten>
At the moment system call entry looks like:
crclr so
...
mfcr r9
...
std r9,_CCR(r1)
commit bd19c8994a82 ([POWERPC] system call micro optimisation) put
some space between the crclr and mfcr in order to avoid a stall.
There is still a stall seen between the mfcr and std. We can avoid
the crclr by doing it in a GPR with rlwinm which gives us more room
to better schedule the sequence.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
v2:
Milton pointed out that rlwinm copies the low 32bits into the top
32bits and this might confuse ptracers. We tossed around a few ideas
but his suggestion of using rldimi sounds good to me.
Index: linux-build/arch/powerpc/kernel/entry_64.S
===================================================================
--- linux-build.orig/arch/powerpc/kernel/entry_64.S 2012-04-05 14:03:05.123678148 +1000
+++ linux-build/arch/powerpc/kernel/entry_64.S 2012-04-05 23:38:09.182681076 +1000
@@ -63,15 +63,9 @@ system_call_common:
std r0,GPR0(r1)
std r10,GPR1(r1)
ACCOUNT_CPU_USER_ENTRY(r10, r11)
- /*
- * This "crclr so" clears CR0.SO, which is the error indication on
- * return from this system call. There must be no cmp instruction
- * between it and the "mfcr r9" below, otherwise if XER.SO is set,
- * CR0.SO will get set, causing all system calls to appear to fail.
- */
- crclr so
std r2,GPR2(r1)
std r3,GPR3(r1)
+ mfcr r2
std r4,GPR4(r1)
std r5,GPR5(r1)
std r6,GPR6(r1)
@@ -84,15 +78,19 @@ system_call_common:
std r11,GPR12(r1)
std r11,_XER(r1)
std r9,GPR13(r1)
- mfcr r9
mflr r10
+ /*
+ * This clears CR0.SO (bit 28), which is the error indication on
+ * return from this system call.
+ */
+ rldimi r2,r11,28,(63-28)
li r11,0xc01
- std r9,_CCR(r1)
std r10,_LINK(r1)
std r11,_TRAP(r1)
mfctr r10
std r10,_CTR(r1)
std r3,ORIG_GPR3(r1)
+ std r2,_CCR(r1)
ld r2,PACATOC(r13)
addi r9,r1,STACK_FRAME_OVERHEAD
ld r11,exception_marker@toc(r2)
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox