From 515d9b2c03943ca904cd135e1b1d9ddd168c1b27 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 12 Aug 2014 18:22:27 +0200 Subject: [PATCH 01/22] ata: remove deprecated struct ahci_platform_data The last user of the deprecated struct ahci_platform_data has been cleaned up recently (SPEAr1340 got a proper PHY driver). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/ahci_platform.c | 18 +----------------- drivers/ata/libahci_platform.c | 23 ----------------------- include/linux/ahci_platform.h | 13 ------------- 3 files changed, 1 insertion(+), 53 deletions(-) diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index f61ddb9146d6..06f1d59fa678 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -32,7 +32,6 @@ static const struct ata_port_info ahci_port_info = { static int ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_host_priv *hpriv; int rc; @@ -44,29 +43,14 @@ static int ahci_probe(struct platform_device *pdev) if (rc) return rc; - /* - * Some platforms might need to prepare for mmio region access, - * which could be done in the following init call. So, the mmio - * region shouldn't be accessed before init (if provided) has - * returned successfully. - */ - if (pdata && pdata->init) { - rc = pdata->init(dev, hpriv->mmio); - if (rc) - goto disable_resources; - } - if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info); if (rc) - goto pdata_exit; + goto disable_resources; return 0; -pdata_exit: - if (pdata && pdata->exit) - pdata->exit(dev); disable_resources: ahci_platform_disable_resources(hpriv); return rc; diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 5b92c290e6c6..c0510de8a4c9 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -502,13 +502,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_init_host); static void ahci_host_stop(struct ata_host *host) { - struct device *dev = host->dev; - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_host_priv *hpriv = host->private_data; - if (pdata && pdata->exit) - pdata->exit(dev); - ahci_platform_disable_resources(hpriv); } @@ -592,7 +587,6 @@ EXPORT_SYMBOL_GPL(ahci_platform_resume_host); */ int ahci_platform_suspend(struct device *dev) { - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; int rc; @@ -601,19 +595,9 @@ int ahci_platform_suspend(struct device *dev) if (rc) return rc; - if (pdata && pdata->suspend) { - rc = pdata->suspend(dev); - if (rc) - goto resume_host; - } - ahci_platform_disable_resources(hpriv); return 0; - -resume_host: - ahci_platform_resume_host(dev); - return rc; } EXPORT_SYMBOL_GPL(ahci_platform_suspend); @@ -629,7 +613,6 @@ EXPORT_SYMBOL_GPL(ahci_platform_suspend); */ int ahci_platform_resume(struct device *dev) { - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; int rc; @@ -638,12 +621,6 @@ int ahci_platform_resume(struct device *dev) if (rc) return rc; - if (pdata && pdata->resume) { - rc = pdata->resume(dev); - if (rc) - goto disable_resources; - } - rc = ahci_platform_resume_host(dev); if (rc) goto disable_resources; diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h index 09a947e8bc87..642d6ae4030c 100644 --- a/include/linux/ahci_platform.h +++ b/include/linux/ahci_platform.h @@ -22,19 +22,6 @@ struct ata_port_info; struct ahci_host_priv; struct platform_device; -/* - * Note ahci_platform_data is deprecated, it is only kept around for use - * by the old da850 and spear13xx ahci code. - * New drivers should instead declare their own platform_driver struct, and - * use ahci_platform* functions in their own probe, suspend and resume methods. - */ -struct ahci_platform_data { - int (*init)(struct device *dev, void __iomem *addr); - void (*exit)(struct device *dev); - int (*suspend)(struct device *dev); - int (*resume)(struct device *dev); -}; - int ahci_platform_enable_clks(struct ahci_host_priv *hpriv); void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); From 4f37b504768c952b64bc9469a2d579c7597590f2 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 19 Aug 2014 10:51:04 +0400 Subject: [PATCH 02/22] libata: Use dev_name() for request_irq() to distinguish devices Use dev_name() instead of driver name for request_irq(). This will help to distinguish between multiple identical devices. Before: CPU0 5: 34425 clps711x-intc 5 pata_of_platform 6: 6778 clps711x-intc 6 pata_of_platform After: CPU0 5: 2182 clps711x-intc 5 20000000.ide 6: 11024 clps711x-intc 6 20100000.ide Signed-off-by: Alexander Shiyan Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dbdc5d32343f..782d126cf191 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6227,7 +6227,7 @@ int ata_host_activate(struct ata_host *host, int irq, } rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, - dev_driver_string(host->dev), host); + dev_name(host->dev), host); if (rc) return rc; From ca99140a63b7326ee9a38f64c326317f2c63b594 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 23 Aug 2014 14:46:10 +0400 Subject: [PATCH 03/22] pata_of_platform: Remove "electra-ide" quirk "electra-ide" is not used anywhere in the kernel and could be represented in devicetree in a normal way. This patch removes specific quirk for "electra-ide". Signed-off-by: Alexander Shiyan Signed-off-by: Tejun Heo --- drivers/ata/pata_of_platform.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index a7e95a54c782..6af1c9b9a464 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -35,20 +35,11 @@ static int pata_of_platform_probe(struct platform_device *ofdev) return -EINVAL; } - if (of_device_is_compatible(dn, "electra-ide")) { - /* Altstatus is really at offset 0x3f6 from the primary window - * on electra-ide. Adjust ctl_res and io_res accordingly. - */ - ctl_res = io_res; - ctl_res.start = ctl_res.start+0x3f6; - io_res.end = ctl_res.start-1; - } else { - ret = of_address_to_resource(dn, 1, &ctl_res); - if (ret) { - dev_err(&ofdev->dev, "can't get CTL address from " - "device tree\n"); - return -EINVAL; - } + ret = of_address_to_resource(dn, 1, &ctl_res); + if (ret) { + dev_err(&ofdev->dev, "can't get CTL address from " + "device tree\n"); + return -EINVAL; } irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0); @@ -79,8 +70,7 @@ static int pata_of_platform_probe(struct platform_device *ofdev) static struct of_device_id pata_of_platform_match[] = { { .compatible = "ata-generic", }, - { .compatible = "electra-ide", }, - {}, + { }, }; MODULE_DEVICE_TABLE(of, pata_of_platform_match); From 53f3cc46336b9e514c98556b4a009a69ed808d3b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 23 Aug 2014 14:45:47 +0400 Subject: [PATCH 04/22] pata_platform: Remove useless irq_flags field IRQ flags can be obtained from resource structure, there are no need to use additional field in the platform_data to store these values. This patch removes this field and convert existing users of this driver to use IRQ flags from the resources. Signed-off-by: Alexander Shiyan Signed-off-by: Tejun Heo --- arch/blackfin/mach-bf537/boards/cm_bf537e.c | 3 +-- arch/blackfin/mach-bf537/boards/cm_bf537u.c | 3 +-- arch/blackfin/mach-bf537/boards/stamp.c | 3 +-- arch/blackfin/mach-bf537/boards/tcm_bf537.c | 3 +-- arch/blackfin/mach-bf561/boards/cm_bf561.c | 3 +-- drivers/ata/pata_of_platform.c | 2 -- drivers/ata/pata_platform.c | 4 +--- include/linux/ata_platform.h | 5 ----- 8 files changed, 6 insertions(+), 20 deletions(-) diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537e.c b/arch/blackfin/mach-bf537/boards/cm_bf537e.c index 1e7290ef3525..1e1014df5e9e 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537e.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537e.c @@ -733,7 +733,6 @@ static struct platform_device bfin_mac_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -750,7 +749,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537u.c b/arch/blackfin/mach-bf537/boards/cm_bf537u.c index c7495dc74690..d056db9e5592 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537u.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537u.c @@ -587,7 +587,6 @@ static struct platform_device bfin_mac_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -604,7 +603,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index de19b8a56007..88a19fc9844d 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -2462,7 +2462,6 @@ static struct platform_device bfin_sport0_device = { #define PATA_INT IRQ_PF5 static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 1, - .irq_flags = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -2479,7 +2478,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; #elif defined(CF_IDE_NAND_CARD_USE_CF_IN_COMMON_MEMORY_MODE) diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c index 6b988ad653d8..ed309c9a62b6 100644 --- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c +++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c @@ -589,7 +589,6 @@ static struct platform_device bfin_mac_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -606,7 +605,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c index e862f7823e68..c6db52ba3a06 100644 --- a/arch/blackfin/mach-bf561/boards/cm_bf561.c +++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -354,7 +354,6 @@ static struct platform_device bfin_sir0_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -371,7 +370,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 6af1c9b9a464..64965398914a 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -43,8 +43,6 @@ static int pata_of_platform_probe(struct platform_device *ofdev) } irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0); - if (irq_res) - irq_res->flags = 0; prop = of_get_property(dn, "reg-shift", NULL); if (prop) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index a5579b55e332..f8cff3e247c5 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -118,7 +118,7 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res, */ if (irq_res && irq_res->start > 0) { irq = irq_res->start; - irq_flags = irq_res->flags; + irq_flags = irq_res->flags & IRQF_TRIGGER_MASK; } /* @@ -213,8 +213,6 @@ static int pata_platform_probe(struct platform_device *pdev) * And the IRQ */ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq_res) - irq_res->flags = pp_info ? pp_info->irq_flags : 0; return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res, pp_info ? pp_info->ioport_shift : 0, diff --git a/include/linux/ata_platform.h b/include/linux/ata_platform.h index b9fde17f767c..5c618a084225 100644 --- a/include/linux/ata_platform.h +++ b/include/linux/ata_platform.h @@ -8,11 +8,6 @@ struct pata_platform_info { * spacing used by ata_std_ports(). */ unsigned int ioport_shift; - /* - * Indicate platform specific irq types and initial - * IRQ flags when call request_irq() - */ - unsigned int irq_flags; }; extern int __pata_platform_probe(struct device *dev, From 6bb86fefa086faba7b60bb452300b76a47cde1a5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 30 Aug 2014 16:39:09 -0300 Subject: [PATCH 05/22] libahci_platform: Staticize ahci_platform_able_phys() ahci_platform_enable_phys() and ahci_platform_disable_phys() are currently exported, but they are not used anywhere else other than libahci_platform.c. So make them static and do not export them to fix the following sparse warnings: drivers/ata/libahci_platform.c:52:5: warning: symbol 'ahci_platform_enable_phys' was not declared. Should it be static? drivers/ata/libahci_platform.c:88:6: warning: symbol 'ahci_platform_disable_phys' was not declared. Should it be static? Signed-off-by: Fabio Estevam Signed-off-by: Tejun Heo --- drivers/ata/libahci_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index c0510de8a4c9..c7f787e9939b 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -49,7 +49,7 @@ static struct scsi_host_template ahci_platform_sht = { * RETURNS: * 0 on success otherwise a negative error code */ -int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) +static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) { int rc, i; @@ -77,7 +77,6 @@ disable_phys: } return rc; } -EXPORT_SYMBOL_GPL(ahci_platform_enable_phys); /** * ahci_platform_disable_phys - Disable PHYs @@ -85,7 +84,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_phys); * * This function disables all PHYs found in hpriv->phys. */ -void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) +static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) { int i; @@ -97,7 +96,6 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) phy_exit(hpriv->phys[i]); } } -EXPORT_SYMBOL_GPL(ahci_platform_disable_phys); /** * ahci_platform_enable_clks - Enable platform clocks From 1bd06867f7f168273c80ba10ce4025a97be98305 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 31 Aug 2014 10:57:09 +0200 Subject: [PATCH 06/22] ahci: ahci_p5wdh_workaround - constify DMI table The DMI table does not need to be written to, make it r/o. Signed-off-by: Mathias Krause Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a29f8012fb08..c880699a7d0b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -780,7 +780,7 @@ static void ahci_pci_print_info(struct ata_host *host) */ static void ahci_p5wdh_workaround(struct ata_host *host) { - static struct dmi_system_id sysids[] = { + static const struct dmi_system_id sysids[] = { { .ident = "P5W DH Deluxe", .matches = { From ee309f382985cbb29d85965a2de96bc715260463 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 22 Sep 2014 15:09:45 -0500 Subject: [PATCH 07/22] ahci-platform: Bump max number of clocks to 5 Qualcomm IPQ806x SoCs with SATA controllers need 5 clocks to be enabled. Signed-off-by: Kumar Gala Reviewed-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/ahci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 59ae0ee00149..90156ff1e9cb 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -53,7 +53,7 @@ enum { AHCI_MAX_PORTS = 32, - AHCI_MAX_CLKS = 4, + AHCI_MAX_CLKS = 5, AHCI_MAX_SG = 168, /* hardware max is 64K */ AHCI_DMA_BOUNDARY = 0xffffffff, AHCI_MAX_CMDS = 32, From 8494294b66dbb4d7996dd944575eebd4ac2a126b Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 22 Sep 2014 15:09:46 -0500 Subject: [PATCH 08/22] ata: qcom: Add device tree bindings information Add device tree binding for Qualcomm AHCI SATA controller and specifically the sata controller on the IPQ806x family of SoCs. We can utilize the "generic-ahci" platform driver with the addition of the sata phy to enable SATA support on Qualcomm SoCs with AHCI controllers. Signed-off-by: Kumar Gala Reviewed-by: Hans de Goede Signed-off-by: Tejun Heo --- .../devicetree/bindings/ata/qcom-sata.txt | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/qcom-sata.txt diff --git a/Documentation/devicetree/bindings/ata/qcom-sata.txt b/Documentation/devicetree/bindings/ata/qcom-sata.txt new file mode 100644 index 000000000000..094de91cd9fd --- /dev/null +++ b/Documentation/devicetree/bindings/ata/qcom-sata.txt @@ -0,0 +1,48 @@ +* Qualcomm AHCI SATA Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA controller should have its own node. + +Required properties: +- compatible : compatible list, must contain "generic-ahci" +- interrupts : +- reg : +- phys : Must contain exactly one entry as specified + in phy-bindings.txt +- phy-names : Must be "sata-phy" + +Required properties for "qcom,ipq806x-ahci" compatible: +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Shall be: + "slave_iface" - Fabric port AHB clock for SATA + "iface" - AHB clock + "core" - core clock + "rxoob" - RX out-of-band clock + "pmalive" - Power Module Alive clock +- assigned-clocks : Shall be: + SATA_RXOOB_CLK + SATA_PMALIVE_CLK +- assigned-clock-rates : Shall be: + 100Mhz (100000000) for SATA_RXOOB_CLK + 100Mhz (100000000) for SATA_PMALIVE_CLK + +Example: + sata@29000000 { + compatible = "qcom,ipq806x-ahci", "generic-ahci"; + reg = <0x29000000 0x180>; + + interrupts = <0 209 0x0>; + + clocks = <&gcc SFAB_SATA_S_H_CLK>, + <&gcc SATA_H_CLK>, + <&gcc SATA_A_CLK>, + <&gcc SATA_RXOOB_CLK>, + <&gcc SATA_PMALIVE_CLK>; + clock-names = "slave_iface", "iface", "core", + "rxoob", "pmalive"; + assigned-clocks = <&gcc SATA_RXOOB_CLK>, <&gcc SATA_PMALIVE_CLK>; + assigned-clock-rates = <100000000>, <100000000>; + + phys = <&sata_phy>; + phy-names = "sata-phy"; + }; From d7bead1b8890c3e47a24db270fdb840ea728d8f0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 22 Sep 2014 09:52:18 -0700 Subject: [PATCH 09/22] libata: change ata__printk routines to return void The return value is not used by callers of these functions nor by uses of all macros so change the functions to return void. Signed-off-by: Joe Perches Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 35 +++++++++++++---------------------- include/linux/libata.h | 12 ++++++------ 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 782d126cf191..f785ae50a0ea 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6772,32 +6772,28 @@ const struct ata_port_info ata_dummy_port_info = { /* * Utility print functions */ -int ata_port_printk(const struct ata_port *ap, const char *level, - const char *fmt, ...) +void ata_port_printk(const struct ata_port *ap, const char *level, + const char *fmt, ...) { struct va_format vaf; va_list args; - int r; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - r = printk("%sata%u: %pV", level, ap->print_id, &vaf); + printk("%sata%u: %pV", level, ap->print_id, &vaf); va_end(args); - - return r; } EXPORT_SYMBOL(ata_port_printk); -int ata_link_printk(const struct ata_link *link, const char *level, - const char *fmt, ...) +void ata_link_printk(const struct ata_link *link, const char *level, + const char *fmt, ...) { struct va_format vaf; va_list args; - int r; va_start(args, fmt); @@ -6805,37 +6801,32 @@ int ata_link_printk(const struct ata_link *link, const char *level, vaf.va = &args; if (sata_pmp_attached(link->ap) || link->ap->slave_link) - r = printk("%sata%u.%02u: %pV", - level, link->ap->print_id, link->pmp, &vaf); + printk("%sata%u.%02u: %pV", + level, link->ap->print_id, link->pmp, &vaf); else - r = printk("%sata%u: %pV", - level, link->ap->print_id, &vaf); + printk("%sata%u: %pV", + level, link->ap->print_id, &vaf); va_end(args); - - return r; } EXPORT_SYMBOL(ata_link_printk); -int ata_dev_printk(const struct ata_device *dev, const char *level, +void ata_dev_printk(const struct ata_device *dev, const char *level, const char *fmt, ...) { struct va_format vaf; va_list args; - int r; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - r = printk("%sata%u.%02u: %pV", - level, dev->link->ap->print_id, dev->link->pmp + dev->devno, - &vaf); + printk("%sata%u.%02u: %pV", + level, dev->link->ap->print_id, dev->link->pmp + dev->devno, + &vaf); va_end(args); - - return r; } EXPORT_SYMBOL(ata_dev_printk); diff --git a/include/linux/libata.h b/include/linux/libata.h index 92abb497ab14..bd5fefeaf548 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1404,14 +1404,14 @@ static inline int sata_srst_pmp(struct ata_link *link) * printk helpers */ __printf(3, 4) -int ata_port_printk(const struct ata_port *ap, const char *level, - const char *fmt, ...); +void ata_port_printk(const struct ata_port *ap, const char *level, + const char *fmt, ...); __printf(3, 4) -int ata_link_printk(const struct ata_link *link, const char *level, - const char *fmt, ...); +void ata_link_printk(const struct ata_link *link, const char *level, + const char *fmt, ...); __printf(3, 4) -int ata_dev_printk(const struct ata_device *dev, const char *level, - const char *fmt, ...); +void ata_dev_printk(const struct ata_device *dev, const char *level, + const char *fmt, ...); #define ata_port_err(ap, fmt, ...) \ ata_port_printk(ap, KERN_ERR, fmt, ##__VA_ARGS__) From a77b6ee90dfc3798bdcbdca7a9284d7e8c006af7 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Mon, 22 Sep 2014 18:31:33 +0530 Subject: [PATCH 10/22] ahci_xgene: Fix the error print invalid resource for APM X-Gene SoC AHCI SATA Host Controller driver. This patch fixes the error print invalid resource for the APM X-Gene SoC AHCI SATA Host Controller driver. This print was due to the fact that the controller 3 don't have a mux resource. This didn't result in any errors but the print seems like meaningless. Signed-off-by: Loc Ho Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index bc281115490b..7822c8e7a948 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -406,7 +406,7 @@ static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx) u32 val; /* Check for optional MUX resource */ - if (IS_ERR(ctx->csr_mux)) + if (!ctx->csr_mux) return 0; val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG); @@ -456,7 +456,13 @@ static int xgene_ahci_probe(struct platform_device *pdev) /* Retrieve the optional IP mux resource */ res = platform_get_resource(pdev, IORESOURCE_MEM, 4); - ctx->csr_mux = devm_ioremap_resource(dev, res); + if (res) { + void __iomem *csr = devm_ioremap_resource(dev, res); + if (IS_ERR(csr)) + return PTR_ERR(csr); + + ctx->csr_mux = csr; + } dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, hpriv->mmio); From 6d8ca28fa688a9354bc9fbc935bdaeb3651b6677 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 27 Sep 2014 00:04:46 +0200 Subject: [PATCH 11/22] libata-sff: Fix controllers with no ctl port Currently, ata_sff_softreset is skipped for controllers with no ctl port. But that also skips ata_sff_dev_classify required for device detection. This means that libata is currently broken on controllers with no ctl port. No device connected: [ 1.872480] pata_isapnp 01:01.02: activated [ 1.889823] scsi2 : pata_isapnp [ 1.890109] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 6.888110] ata3.01: qc timeout (cmd 0xec) [ 6.888179] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 16.888085] ata3.01: qc timeout (cmd 0xec) [ 16.888147] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.888086] ata3.01: qc timeout (cmd 0xec) [ 46.888148] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 51.888100] ata3.00: qc timeout (cmd 0xec) [ 51.888160] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) [ 61.888079] ata3.00: qc timeout (cmd 0xec) [ 61.888141] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) [ 91.888089] ata3.00: qc timeout (cmd 0xec) [ 91.888152] ata3.00: failed to IDENTIFY (I/O error, err_mask=0x5) ATAPI device connected: [ 1.882061] pata_isapnp 01:01.02: activated [ 1.893430] scsi2 : pata_isapnp [ 1.893719] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 6.892107] ata3.01: qc timeout (cmd 0xec) [ 6.892171] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 16.892079] ata3.01: qc timeout (cmd 0xec) [ 16.892138] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.892079] ata3.01: qc timeout (cmd 0xec) [ 46.892138] ata3.01: failed to IDENTIFY (I/O error, err_mask=0x5) [ 46.908586] ata3.00: ATAPI: ACER CD-767E/O, V1.5X, max PIO2, CDB intr [ 46.924570] ata3.00: configured for PIO0 (device error ignored) [ 46.926295] scsi 2:0:0:0: CD-ROM ACER CD-767E/O 1.5X PQ: 0 ANSI: 5 [ 46.984519] sr0: scsi3-mmc drive: 6x/6x xa/form2 tray [ 46.984592] cdrom: Uniform CD-ROM driver Revision: 3.20 So don't skip ata_sff_softreset, just skip the reset part of ata_bus_softreset if the ctl port is not available. This makes IDE port on ES968 behave correctly: No device connected: [ 4.670888] pata_isapnp 01:01.02: activated [ 4.673207] scsi host2: pata_isapnp [ 4.673675] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 7.081840] Adding 2541652k swap on /dev/sda2. Priority:-1 extents:1 across:2541652k ATAPI device connected: [ 4.704362] pata_isapnp 01:01.02: activated [ 4.706620] scsi host2: pata_isapnp [ 4.706877] ata3: PATA max PIO0 cmd 0x1e8 ctl 0x0 irq 11 [ 4.872782] ata3.00: ATAPI: ACER CD-767E/O, V1.5X, max PIO2, CDB intr [ 4.888673] ata3.00: configured for PIO0 (device error ignored) [ 4.893984] scsi 2:0:0:0: CD-ROM ACER CD-767E/O 1.5X PQ: 0 ANSI: 5 [ 7.015578] Adding 2541652k swap on /dev/sda2. Priority:-1 extents:1 across:2541652k Signed-off-by: Ondrej Zary Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/libata-sff.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 1121153f1ecd..db90aa35cb71 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2008,13 +2008,15 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); - /* software reset. causes dev0 to be selected */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - iowrite8(ap->ctl, ioaddr->ctl_addr); - ap->last_ctl = ap->ctl; + if (ap->ioaddr.ctl_addr) { + /* software reset. causes dev0 to be selected */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl, ioaddr->ctl_addr); + ap->last_ctl = ap->ctl; + } /* wait the port to become ready */ return ata_sff_wait_after_reset(&ap->link, devmask, deadline); @@ -2215,10 +2217,6 @@ void ata_sff_error_handler(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); - /* ignore ata_sff_softreset if ctl isn't accessible */ - if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr) - softreset = NULL; - /* ignore built-in hardresets if SCR access is not available */ if ((hardreset == sata_std_hardreset || hardreset == sata_sff_hardreset) && !sata_scr_valid(&ap->link)) From c3ebd6a9b614ef1fbb5a44a3a33cd639ff4694bf Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 25 Sep 2014 15:13:21 +0200 Subject: [PATCH 12/22] AHCI: Cleanup checking of multiple MSIs/SLM modes Sharing Last Message (SLM) mode is currently checked in two functions: ahci_host_activate() and ahci_init_interrupts(). This update consolidates SLM mode check with activation of multiple MSIs mode. Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/ahci.c | 18 +++++++----------- drivers/ata/ahci.h | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c880699a7d0b..f68a995ec3fd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1211,6 +1211,9 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, goto single_msi; } + if (nvec > 1) + hpriv->flags |= AHCI_HFLAG_MULTI_MSI; + return nvec; single_msi: @@ -1227,7 +1230,6 @@ intx: * ahci_host_activate - start AHCI host, request IRQs and register it * @host: target ATA host * @irq: base IRQ number to request - * @n_msis: number of MSIs allocated for this host * @irq_handler: irq_handler used when requesting IRQs * @irq_flags: irq_flags used when requesting IRQs * @@ -1241,14 +1243,10 @@ intx: * RETURNS: * 0 on success, -errno otherwise. */ -int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis) +int ahci_host_activate(struct ata_host *host, int irq) { int i, rc; - /* Sharing Last Message among several ports is not supported */ - if (n_msis < host->n_ports) - return -EINVAL; - rc = ata_host_start(host); if (rc) return rc; @@ -1296,7 +1294,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct ata_host *host; - int n_ports, n_msis, i, rc; + int n_ports, i, rc; int ahci_pci_bar = AHCI_PCI_BAR_STANDARD; VPRINTK("ENTER\n"); @@ -1437,9 +1435,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); - n_msis = ahci_init_interrupts(pdev, n_ports, hpriv); - if (n_msis > 1) - hpriv->flags |= AHCI_HFLAG_MULTI_MSI; + ahci_init_interrupts(pdev, n_ports, hpriv); host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); if (!host) @@ -1492,7 +1488,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) - return ahci_host_activate(host, pdev->irq, n_msis); + return ahci_host_activate(host, pdev->irq); return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, &ahci_sht); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 90156ff1e9cb..a074c7301504 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -392,7 +392,7 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance); irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance); irqreturn_t ahci_thread_fn(int irq, void *dev_instance); void ahci_print_info(struct ata_host *host, const char *scc_s); -int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis); +int ahci_host_activate(struct ata_host *host, int irq); void ahci_error_handler(struct ata_port *ap); static inline void __iomem *__ahci_port_base(struct ata_host *host, From 36888e955c7c7ba8c66756fed60ac6e453fcbb5f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 4 Oct 2014 09:03:06 -0300 Subject: [PATCH 13/22] ata: pata_imx: Use the SIMPLE_DEV_PM_OPS() macro Using the SIMPLE_DEV_PM_OPS() macro can make the code shorter and cleaner. Signed-off-by: Fabio Estevam Signed-off-by: Tejun Heo --- drivers/ata/pata_imx.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index af424573c2ff..989ff5ac69ec 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -221,13 +221,10 @@ static int pata_imx_resume(struct device *dev) return 0; } - -static const struct dev_pm_ops pata_imx_pm_ops = { - .suspend = pata_imx_suspend, - .resume = pata_imx_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(pata_imx_pm_ops, pata_imx_suspend, pata_imx_resume); + static const struct of_device_id imx_pata_dt_ids[] = { { .compatible = "fsl,imx27-pata", @@ -244,9 +241,7 @@ static struct platform_driver pata_imx_driver = { .name = DRV_NAME, .of_match_table = imx_pata_dt_ids, .owner = THIS_MODULE, -#ifdef CONFIG_PM_SLEEP .pm = &pata_imx_pm_ops, -#endif }, }; From a6849b9fdbffd2492a848df942b39d23bd81ef27 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 29 Sep 2014 18:25:57 +0200 Subject: [PATCH 14/22] AHCI: Pass SCSI host template as arg to ahci_host_activate() This update is a prerequisite for consolidation of AHCI host activation code within ahci_host_activate() function. Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/ahci.c | 10 +++++----- drivers/ata/ahci.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f68a995ec3fd..fcda5b663030 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1230,8 +1230,7 @@ intx: * ahci_host_activate - start AHCI host, request IRQs and register it * @host: target ATA host * @irq: base IRQ number to request - * @irq_handler: irq_handler used when requesting IRQs - * @irq_flags: irq_flags used when requesting IRQs + * @sht: scsi_host_template to use when registering the host * * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1 * when multiple MSIs were allocated. That is one MSI per port, starting @@ -1243,7 +1242,8 @@ intx: * RETURNS: * 0 on success, -errno otherwise. */ -int ahci_host_activate(struct ata_host *host, int irq) +int ahci_host_activate(struct ata_host *host, int irq, + struct scsi_host_template *sht) { int i, rc; @@ -1271,7 +1271,7 @@ int ahci_host_activate(struct ata_host *host, int irq) for (i = 0; i < host->n_ports; i++) ata_port_desc(host->ports[i], "irq %d", irq + i); - rc = ata_host_register(host, &ahci_sht); + rc = ata_host_register(host, sht); if (rc) goto out_free_all_irqs; @@ -1488,7 +1488,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) - return ahci_host_activate(host, pdev->irq); + return ahci_host_activate(host, pdev->irq, &ahci_sht); return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, &ahci_sht); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index a074c7301504..31b4c44e3f71 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -392,7 +392,8 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance); irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance); irqreturn_t ahci_thread_fn(int irq, void *dev_instance); void ahci_print_info(struct ata_host *host, const char *scc_s); -int ahci_host_activate(struct ata_host *host, int irq); +int ahci_host_activate(struct ata_host *host, int irq, + struct scsi_host_template *sht); void ahci_error_handler(struct ata_port *ap); static inline void __iomem *__ahci_port_base(struct ata_host *host, From 1c62854f5f7321b3ee8c08d34d7c1e615608566d Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 29 Sep 2014 18:25:58 +0200 Subject: [PATCH 15/22] AHCI: Move ahci_host_activate() function to libahci.c This update is a prerequisite for consolidation of AHCI host activation code within ahci_host_activate() function. Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/ahci.c | 60 ------------------------------------------ drivers/ata/libahci.c | 61 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fcda5b663030..0b2160457046 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1226,66 +1226,6 @@ intx: return 0; } -/** - * ahci_host_activate - start AHCI host, request IRQs and register it - * @host: target ATA host - * @irq: base IRQ number to request - * @sht: scsi_host_template to use when registering the host - * - * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1 - * when multiple MSIs were allocated. That is one MSI per port, starting - * from @irq. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ahci_host_activate(struct ata_host *host, int irq, - struct scsi_host_template *sht) -{ - int i, rc; - - rc = ata_host_start(host); - if (rc) - return rc; - - for (i = 0; i < host->n_ports; i++) { - struct ahci_port_priv *pp = host->ports[i]->private_data; - - /* Do not receive interrupts sent by dummy ports */ - if (!pp) { - disable_irq(irq + i); - continue; - } - - rc = devm_request_threaded_irq(host->dev, irq + i, - ahci_hw_interrupt, - ahci_thread_fn, IRQF_SHARED, - pp->irq_desc, host->ports[i]); - if (rc) - goto out_free_irqs; - } - - for (i = 0; i < host->n_ports; i++) - ata_port_desc(host->ports[i], "irq %d", irq + i); - - rc = ata_host_register(host, sht); - if (rc) - goto out_free_all_irqs; - - return 0; - -out_free_all_irqs: - i = host->n_ports; -out_free_irqs: - for (i--; i >= 0; i--) - devm_free_irq(host->dev, irq + i, host->ports[i]); - - return rc; -} - static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int board_id = ent->driver_data; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index b784e9de426a..21bb427d9df4 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2472,6 +2472,67 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, } EXPORT_SYMBOL_GPL(ahci_set_em_messages); +/** + * ahci_host_activate - start AHCI host, request IRQs and register it + * @host: target ATA host + * @irq: base IRQ number to request + * @sht: scsi_host_template to use when registering the host + * + * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1 + * when multiple MSIs were allocated. That is one MSI per port, starting + * from @irq. + * + * LOCKING: + * Inherited from calling layer (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ahci_host_activate(struct ata_host *host, int irq, + struct scsi_host_template *sht) +{ + int i, rc; + + rc = ata_host_start(host); + if (rc) + return rc; + + for (i = 0; i < host->n_ports; i++) { + struct ahci_port_priv *pp = host->ports[i]->private_data; + + /* Do not receive interrupts sent by dummy ports */ + if (!pp) { + disable_irq(irq + i); + continue; + } + + rc = devm_request_threaded_irq(host->dev, irq + i, + ahci_hw_interrupt, + ahci_thread_fn, IRQF_SHARED, + pp->irq_desc, host->ports[i]); + if (rc) + goto out_free_irqs; + } + + for (i = 0; i < host->n_ports; i++) + ata_port_desc(host->ports[i], "irq %d", irq + i); + + rc = ata_host_register(host, sht); + if (rc) + goto out_free_all_irqs; + + return 0; + +out_free_all_irqs: + i = host->n_ports; +out_free_irqs: + for (i--; i >= 0; i--) + devm_free_irq(host->dev, irq + i, host->ports[i]); + + return rc; +} +EXPORT_SYMBOL_GPL(ahci_host_activate); + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Common AHCI SATA low-level routines"); MODULE_LICENSE("GPL"); From d1028e2f95b75acab4f1046acae1b1ca7d7b2577 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 29 Sep 2014 18:25:59 +0200 Subject: [PATCH 16/22] AHCI: Move host activation code into ahci_host_activate() Currently host activation done by calling either function ahci_host_activate() or ata_host_activate(). Consolidate the code by only calling ahci_host_activate() for all AHCI devices. Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/acard-ahci.c | 3 +- drivers/ata/ahci.c | 6 +--- drivers/ata/ahci.h | 3 -- drivers/ata/libahci.c | 59 ++++++++++++++++++++-------------- drivers/ata/libahci_platform.c | 3 +- drivers/ata/sata_highbank.c | 3 +- 6 files changed, 39 insertions(+), 38 deletions(-) diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 25d0ac32e721..c962886d7e71 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -498,8 +498,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id acard_ahci_pci_print_info(host); pci_set_master(pdev); - return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, - &acard_ahci_sht); + return ahci_host_activate(host, pdev->irq, &acard_ahci_sht); } module_pci_driver(acard_ahci_pci_driver); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0b2160457046..d0ac38bd2d51 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1427,11 +1427,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) - return ahci_host_activate(host, pdev->irq, &ahci_sht); - - return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, - &ahci_sht); + return ahci_host_activate(host, pdev->irq, &ahci_sht); } module_pci_driver(ahci_pci_driver); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 31b4c44e3f71..6a22055151f0 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -388,9 +388,6 @@ int ahci_port_resume(struct ata_port *ap); void ahci_set_em_messages(struct ahci_host_priv *hpriv, struct ata_port_info *pi); int ahci_reset_em(struct ata_host *host); -irqreturn_t ahci_interrupt(int irq, void *dev_instance); -irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance); -irqreturn_t ahci_thread_fn(int irq, void *dev_instance); void ahci_print_info(struct ata_host *host, const char *scc_s); int ahci_host_activate(struct ata_host *host, int irq, struct scsi_host_template *sht); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 21bb427d9df4..0080551f6e33 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1789,7 +1789,7 @@ static void ahci_port_intr(struct ata_port *ap) ahci_handle_port_interrupt(ap, port_mmio, status); } -irqreturn_t ahci_thread_fn(int irq, void *dev_instance) +static irqreturn_t ahci_thread_fn(int irq, void *dev_instance) { struct ata_port *ap = dev_instance; struct ahci_port_priv *pp = ap->private_data; @@ -1809,7 +1809,6 @@ irqreturn_t ahci_thread_fn(int irq, void *dev_instance) return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(ahci_thread_fn); static void ahci_hw_port_interrupt(struct ata_port *ap) { @@ -1823,7 +1822,7 @@ static void ahci_hw_port_interrupt(struct ata_port *ap) pp->intr_status |= status; } -irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) +static irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) { struct ata_port *ap_this = dev_instance; struct ahci_port_priv *pp = ap_this->private_data; @@ -1877,9 +1876,8 @@ irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) return IRQ_WAKE_THREAD; } -EXPORT_SYMBOL_GPL(ahci_hw_interrupt); -irqreturn_t ahci_interrupt(int irq, void *dev_instance) +static irqreturn_t ahci_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; struct ahci_host_priv *hpriv; @@ -1938,7 +1936,6 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance) return IRQ_RETVAL(handled); } -EXPORT_SYMBOL_GPL(ahci_interrupt); unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { @@ -2472,24 +2469,8 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, } EXPORT_SYMBOL_GPL(ahci_set_em_messages); -/** - * ahci_host_activate - start AHCI host, request IRQs and register it - * @host: target ATA host - * @irq: base IRQ number to request - * @sht: scsi_host_template to use when registering the host - * - * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1 - * when multiple MSIs were allocated. That is one MSI per port, starting - * from @irq. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ahci_host_activate(struct ata_host *host, int irq, - struct scsi_host_template *sht) +static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, + struct scsi_host_template *sht) { int i, rc; @@ -2531,6 +2512,36 @@ out_free_irqs: return rc; } + +/** + * ahci_host_activate - start AHCI host, request IRQs and register it + * @host: target ATA host + * @irq: base IRQ number to request + * @sht: scsi_host_template to use when registering the host + * + * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1 + * when multiple MSIs were allocated. That is one MSI per port, starting + * from @irq. + * + * LOCKING: + * Inherited from calling layer (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ahci_host_activate(struct ata_host *host, int irq, + struct scsi_host_template *sht) +{ + struct ahci_host_priv *hpriv = host->private_data; + int rc; + + if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) + rc = ahci_host_activate_multi_irqs(host, irq, sht); + else + rc = ata_host_activate(host, irq, ahci_interrupt, + IRQF_SHARED, sht); + return rc; +} EXPORT_SYMBOL_GPL(ahci_host_activate); MODULE_AUTHOR("Jeff Garzik"); diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index c7f787e9939b..0b03f9056692 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -493,8 +493,7 @@ int ahci_platform_init_host(struct platform_device *pdev, ahci_init_controller(host); ahci_print_info(host, "platform"); - return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, - &ahci_platform_sht); + return ahci_host_activate(host, irq, &ahci_platform_sht); } EXPORT_SYMBOL_GPL(ahci_platform_init_host); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index da3bc2709c63..ce2b99a1ed70 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -568,8 +568,7 @@ static int ahci_highbank_probe(struct platform_device *pdev) ahci_init_controller(host); ahci_print_info(host, "platform"); - rc = ata_host_activate(host, irq, ahci_interrupt, 0, - &ahci_highbank_platform_sht); + rc = ahci_host_activate(host, irq, &ahci_highbank_platform_sht); if (rc) goto err0; From 5ee1cfd975518bc9cdcd79e0b76552b5ae5c8c1e Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 29 Sep 2014 18:26:00 +0200 Subject: [PATCH 17/22] AHCI: Make few function names more descriptive Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/libahci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 0080551f6e33..48175e5bd001 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1789,7 +1789,7 @@ static void ahci_port_intr(struct ata_port *ap) ahci_handle_port_interrupt(ap, port_mmio, status); } -static irqreturn_t ahci_thread_fn(int irq, void *dev_instance) +static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) { struct ata_port *ap = dev_instance; struct ahci_port_priv *pp = ap->private_data; @@ -1810,7 +1810,7 @@ static irqreturn_t ahci_thread_fn(int irq, void *dev_instance) return IRQ_HANDLED; } -static void ahci_hw_port_interrupt(struct ata_port *ap) +static void ahci_update_intr_status(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); struct ahci_port_priv *pp = ap->private_data; @@ -1822,7 +1822,7 @@ static void ahci_hw_port_interrupt(struct ata_port *ap) pp->intr_status |= status; } -static irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) +static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) { struct ata_port *ap_this = dev_instance; struct ahci_port_priv *pp = ap_this->private_data; @@ -1858,7 +1858,7 @@ static irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) ap = host->ports[i]; if (ap) { - ahci_hw_port_interrupt(ap); + ahci_update_intr_status(ap); VPRINTK("port %u\n", i); } else { VPRINTK("port %u (no irq)\n", i); @@ -1877,7 +1877,7 @@ static irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance) return IRQ_WAKE_THREAD; } -static irqreturn_t ahci_interrupt(int irq, void *dev_instance) +static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) { struct ata_host *host = dev_instance; struct ahci_host_priv *hpriv; @@ -2488,8 +2488,8 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, } rc = devm_request_threaded_irq(host->dev, irq + i, - ahci_hw_interrupt, - ahci_thread_fn, IRQF_SHARED, + ahci_multi_irqs_intr, + ahci_port_thread_fn, IRQF_SHARED, pp->irq_desc, host->ports[i]); if (rc) goto out_free_irqs; @@ -2538,7 +2538,7 @@ int ahci_host_activate(struct ata_host *host, int irq, if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) rc = ahci_host_activate_multi_irqs(host, irq, sht); else - rc = ata_host_activate(host, irq, ahci_interrupt, + rc = ata_host_activate(host, irq, ahci_single_irq_intr, IRQF_SHARED, sht); return rc; } From 227dfb4dbf109596d76a9b842856c4ff68e4efb2 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 29 Sep 2014 18:26:01 +0200 Subject: [PATCH 18/22] AHCI: Do not read HOST_IRQ_STAT reg in multi-MSI mode As described in AHCI v1.0 specification chapter 10.6.2.2 "Multiple MSI Based Messages" generation of interrupts is not controlled through the HOST_IRQ_STAT register. Considering MMIO access is expensive remove unnecessary reading and writing of HOST_IRQ_STAT register. Further, serializing access to the host data is no longer needed and the interrupt service routine can avoid competing on the host lock. Signed-off-by: Alexander Gordeev Suggested-by: "Jiang, Dave" Signed-off-by: Tejun Heo Cc: "Jiang, Dave" Cc: linux-ide@vger.kernel.org --- drivers/ata/ahci.h | 2 +- drivers/ata/libahci.c | 67 ++++++------------------------------------- 2 files changed, 9 insertions(+), 60 deletions(-) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 6a22055151f0..40f0e34f17af 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -304,7 +304,7 @@ struct ahci_port_priv { unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_sdb:1; - u32 intr_status; /* interrupts to handle */ + atomic_t intr_status; /* interrupts to handle */ spinlock_t lock; /* protects parent ata_port */ u32 intr_mask; /* interrupts to enable */ bool fbs_supported; /* set iff FBS is supported */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 48175e5bd001..97683e45ab04 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1794,14 +1794,11 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) struct ata_port *ap = dev_instance; struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); - unsigned long flags; u32 status; - spin_lock_irqsave(&ap->host->lock, flags); - status = pp->intr_status; - if (status) - pp->intr_status = 0; - spin_unlock_irqrestore(&ap->host->lock, flags); + status = atomic_xchg(&pp->intr_status, 0); + if (!status) + return IRQ_NONE; spin_lock_bh(ap->lock); ahci_handle_port_interrupt(ap, port_mmio, status); @@ -1810,67 +1807,19 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) return IRQ_HANDLED; } -static void ahci_update_intr_status(struct ata_port *ap) +static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) { + struct ata_port *ap = dev_instance; void __iomem *port_mmio = ahci_port_base(ap); struct ahci_port_priv *pp = ap->private_data; u32 status; + VPRINTK("ENTER\n"); + status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); - pp->intr_status |= status; -} - -static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) -{ - struct ata_port *ap_this = dev_instance; - struct ahci_port_priv *pp = ap_this->private_data; - struct ata_host *host = ap_this->host; - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = hpriv->mmio; - unsigned int i; - u32 irq_stat, irq_masked; - - VPRINTK("ENTER\n"); - - spin_lock(&host->lock); - - irq_stat = readl(mmio + HOST_IRQ_STAT); - - if (!irq_stat) { - u32 status = pp->intr_status; - - spin_unlock(&host->lock); - - VPRINTK("EXIT\n"); - - return status ? IRQ_WAKE_THREAD : IRQ_NONE; - } - - irq_masked = irq_stat & hpriv->port_map; - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap; - - if (!(irq_masked & (1 << i))) - continue; - - ap = host->ports[i]; - if (ap) { - ahci_update_intr_status(ap); - VPRINTK("port %u\n", i); - } else { - VPRINTK("port %u (no irq)\n", i); - if (ata_ratelimit()) - dev_warn(host->dev, - "interrupt on disabled port %u\n", i); - } - } - - writel(irq_stat, mmio + HOST_IRQ_STAT); - - spin_unlock(&host->lock); + atomic_or(status, &pp->intr_status); VPRINTK("EXIT\n"); From 18dcf433f3ded61eb140a55e7048ec2fef79e723 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 6 Oct 2014 16:24:45 +0100 Subject: [PATCH 19/22] AHCI: Optimize single IRQ interrupt processing Split interrupt service routine into hardware context handler and threaded context handler. That allows to protect ports with individual locks rather than with a single host-wide lock and move port interrupts handling out of the hardware interrupt context. Testing was done by transferring 8GB on two hard drives in parallel using command 'dd if=/dev/sd{a,b} of=/dev/null'. With lock_stat statistics I measured access times to ata_host::lock spinlock (since interrupt handler code is fully embraced with this lock). The average lock's holdtime decreased eight times while average waittime decreased two times. Both before and after the change the transfer time is the same, while 'perf record -e cycles:k ...' shows 1%-4% CPU time spent in ahci_single_irq_intr() routine before the update and not even sampled/shown ahci_single_irq_intr() after the update. Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/libahci.c | 74 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 97683e45ab04..3ce3d23e4f97 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1778,15 +1778,16 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, } } -static void ahci_port_intr(struct ata_port *ap) +static void ahci_update_intr_status(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; u32 status; status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); - ahci_handle_port_interrupt(ap, port_mmio, status); + atomic_or(status, &pp->intr_status); } static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) @@ -1807,6 +1808,34 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) return IRQ_HANDLED; } +irqreturn_t ahci_thread_fn(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + struct ahci_host_priv *hpriv = host->private_data; + u32 irq_masked = hpriv->port_map; + unsigned int i; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap; + + if (!(irq_masked & (1 << i))) + continue; + + ap = host->ports[i]; + if (ap) { + ahci_port_thread_fn(irq, ap); + VPRINTK("port %u\n", i); + } else { + VPRINTK("port %u (no irq)\n", i); + if (ata_ratelimit()) + dev_warn(host->dev, + "interrupt on disabled port %u\n", i); + } + } + + return IRQ_HANDLED; +} + static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) { struct ata_port *ap = dev_instance; @@ -1856,7 +1885,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) ap = host->ports[i]; if (ap) { - ahci_port_intr(ap); + ahci_update_intr_status(ap); VPRINTK("port %u\n", i); } else { VPRINTK("port %u (no irq)\n", i); @@ -1883,7 +1912,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) VPRINTK("EXIT\n"); - return IRQ_RETVAL(handled); + return handled ? IRQ_WAKE_THREAD : IRQ_NONE; } unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) @@ -2295,13 +2324,8 @@ static int ahci_port_start(struct ata_port *ap) */ pp->intr_mask = DEF_PORT_IRQ; - /* - * Switch to per-port locking in case each port has its own MSI vector. - */ - if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) { - spin_lock_init(&pp->lock); - ap->lock = &pp->lock; - } + spin_lock_init(&pp->lock); + ap->lock = &pp->lock; ap->private_data = pp; @@ -2462,6 +2486,31 @@ out_free_irqs: return rc; } +static int ahci_host_activate_single_irq(struct ata_host *host, int irq, + struct scsi_host_template *sht) +{ + int i, rc; + + rc = ata_host_start(host); + if (rc) + return rc; + + rc = devm_request_threaded_irq(host->dev, irq, ahci_single_irq_intr, + ahci_thread_fn, IRQF_SHARED, + dev_driver_string(host->dev), host); + if (rc) + return rc; + + for (i = 0; i < host->n_ports; i++) + ata_port_desc(host->ports[i], "irq %d", irq); + + rc = ata_host_register(host, sht); + if (rc) + devm_free_irq(host->dev, irq, host); + + return rc; +} + /** * ahci_host_activate - start AHCI host, request IRQs and register it * @host: target ATA host @@ -2487,8 +2536,7 @@ int ahci_host_activate(struct ata_host *host, int irq, if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) rc = ahci_host_activate_multi_irqs(host, irq, sht); else - rc = ata_host_activate(host, irq, ahci_single_irq_intr, - IRQF_SHARED, sht); + rc = ahci_host_activate_single_irq(host, irq, sht); return rc; } EXPORT_SYMBOL_GPL(ahci_host_activate); From 33fb0d01ce60fe4c0c12c4f0c134c5cdb818ac5a Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 6 Oct 2014 16:26:35 +0100 Subject: [PATCH 20/22] AHCI: Do not acquire ata_host::lock from single IRQ handler There is no need to acquire ata_host::lock spinlock from hardware context single IRQ interrupt handler since the handler does not access host data that could be altered by concurrent processors. Signed-off-by: Alexander Gordeev Signed-off-by: Tejun Heo Cc: linux-ide@vger.kernel.org --- drivers/ata/libahci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 3ce3d23e4f97..5eb61c9e63da 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1875,8 +1875,6 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) irq_masked = irq_stat & hpriv->port_map; - spin_lock(&host->lock); - for (i = 0; i < host->n_ports; i++) { struct ata_port *ap; @@ -1908,8 +1906,6 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) */ writel(irq_stat, mmio + HOST_IRQ_STAT); - spin_unlock(&host->lock); - VPRINTK("EXIT\n"); return handled ? IRQ_WAKE_THREAD : IRQ_NONE; From 1c40279960bcd7d52dbdf1d466b20d24b99176c8 Mon Sep 17 00:00:00 2001 From: George Spelvin Date: Tue, 7 Oct 2014 07:26:38 -0400 Subject: [PATCH 21/22] libata: Un-break ATA blacklist lib/glob.c provides a new glob_match() function, with arguments in (pattern, string) order. It replaced a private function with arguments in (string, pattern) order, but I didn't swap the call site... The result was the entire ATA blacklist was effectively disabled. The lesson for today is "I f***ed up *how* badly *how* many months ago?", er, I mean "Nobody Tests RC Kernels On Legacy Hardware". This was not a subtle break, but it made it through an entire RC cycle unreported, presumably because all the people doing testing have full-featured hardware. (FWIW, the reason for the argument swap was because fnmatch() does it that way, and for a while implementing a full fnmatch() was being considered.) Fixes: 428ac5fc056e0 (libata: Use glob_match from lib/glob.c) Reported-by: Steven Honeyman Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=71371#c21 Signed-off-by: George Spelvin Cc: # 3.17 Tested-by: Steven Honeyman Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f785ae50a0ea..bea6d3745324 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4261,10 +4261,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (glob_match(model_num, ad->model_num)) { + if (glob_match(ad->model_num, model_num)) { if (ad->model_rev == NULL) return ad->horkage; - if (glob_match(model_rev, ad->model_rev)) + if (glob_match(ad->model_rev, model_rev)) return ad->horkage; } ad++; From 37017ac6849e772e67dd187ba2fbd056c4afa533 Mon Sep 17 00:00:00 2001 From: Scott Carter Date: Wed, 24 Sep 2014 18:13:09 -0700 Subject: [PATCH 22/22] pata_serverworks: disable 64-KB DMA transfers on Broadcom OSB4 IDE Controller The Broadcom OSB4 IDE Controller (vendor and device IDs: 1166:0211) does not support 64-KB DMA transfers. Whenever a 64-KB DMA transfer is attempted, the transfer fails and messages similar to the following are written to the console log: [ 2431.851125] sr 0:0:0:0: [sr0] Unhandled sense code [ 2431.851139] sr 0:0:0:0: [sr0] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [ 2431.851152] sr 0:0:0:0: [sr0] Sense Key : Hardware Error [current] [ 2431.851166] sr 0:0:0:0: [sr0] Add. Sense: Logical unit communication time-out [ 2431.851182] sr 0:0:0:0: [sr0] CDB: Read(10): 28 00 00 00 76 f4 00 00 40 00 [ 2431.851210] end_request: I/O error, dev sr0, sector 121808 When the libata and pata_serverworks modules are recompiled with ATA_DEBUG and ATA_VERBOSE_DEBUG defined in libata.h, the 64-KB transfer size in the scatter-gather list can be seen in the console log: [ 2664.897267] sr 9:0:0:0: [sr0] Send: [ 2664.897274] 0xf63d85e0 [ 2664.897283] sr 9:0:0:0: [sr0] CDB: [ 2664.897288] Read(10): 28 00 00 00 7f b4 00 00 40 00 [ 2664.897319] buffer = 0xf6d6fbc0, bufflen = 131072, queuecommand 0xf81b7700 [ 2664.897331] ata_scsi_dump_cdb: CDB (1:0,0,0) 28 00 00 00 7f b4 00 00 40 [ 2664.897338] ata_scsi_translate: ENTER [ 2664.897345] ata_sg_setup: ENTER, ata1 [ 2664.897356] ata_sg_setup: 3 sg elements mapped [ 2664.897364] ata_bmdma_fill_sg: PRD[0] = (0x66FD2000, 0xE000) [ 2664.897371] ata_bmdma_fill_sg: PRD[1] = (0x65000000, 0x10000) ------------------------------------------------------> ======= [ 2664.897378] ata_bmdma_fill_sg: PRD[2] = (0x66A10000, 0x2000) [ 2664.897386] ata1: ata_dev_select: ENTER, device 0, wait 1 [ 2664.897422] ata_sff_tf_load: feat 0x1 nsect 0x0 lba 0x0 0x0 0xFC [ 2664.897428] ata_sff_tf_load: device 0xA0 [ 2664.897448] ata_sff_exec_command: ata1: cmd 0xA0 [ 2664.897457] ata_scsi_translate: EXIT [ 2664.897462] leaving scsi_dispatch_cmnd() [ 2664.897497] Doing sr request, dev = sr0, block = 0 [ 2664.897507] sr0 : reading 64/256 512 byte blocks. [ 2664.897553] ata_sff_hsm_move: ata1: protocol 7 task_state 1 (dev_stat 0x58) [ 2664.897560] atapi_send_cdb: send cdb [ 2666.910058] ata_bmdma_port_intr: ata1: host_stat 0x64 [ 2666.910079] __ata_sff_port_intr: ata1: protocol 7 task_state 3 [ 2666.910093] ata_sff_hsm_move: ata1: protocol 7 task_state 3 (dev_stat 0x51) [ 2666.910101] ata_sff_hsm_move: ata1: protocol 7 task_state 4 (dev_stat 0x51) [ 2666.910129] sr 9:0:0:0: [sr0] Done: [ 2666.910136] 0xf63d85e0 TIMEOUT lspci shows that the driver used for the Broadcom OSB4 IDE Controller is pata_serverworks: 00:0f.1 IDE interface: Broadcom OSB4 IDE Controller (prog-if 8e [Master SecP SecO PriP]) Flags: bus master, medium devsel, latency 64 [virtual] Memory at 000001f0 (32-bit, non-prefetchable) [size=8] [virtual] Memory at 000003f0 (type 3, non-prefetchable) [size=1] I/O ports at 0170 [size=8] I/O ports at 0374 [size=4] I/O ports at 1440 [size=16] Kernel driver in use: pata_serverworks The pata_serverworks driver supports five distinct device IDs, one being the OSB4 and the other four belonging to the CSB series. The CSB series appears to support 64-KB DMA transfers, as tests on a machine with an SAI2 motherboard containing a Broadcom CSB5 IDE Controller (vendor and device IDs: 1166:0212) showed no problems with 64-KB DMA transfers. This problem was first discovered when attempting to install openSUSE from a DVD on a machine with an STL2 motherboard. Using the pata_serverworks module, older releases of openSUSE will not install at all due to the timeouts. Releases of openSUSE prior to 11.3 can be installed by disabling the pata_serverworks module using the brokenmodules boot parameter, which causes the serverworks module to be used instead. Recent releases of openSUSE (12.2 and later) include better error recovery and will install, though very slowly. On all openSUSE releases, the problem can be recreated on a machine containing a Broadcom OSB4 IDE Controller by mounting an install DVD and running a command similar to the following: find /mnt -type f -print | xargs cat > /dev/null The patch below corrects the problem. Similar to the other ATA drivers that do not support 64-KB DMA transfers, the patch changes the ata_port_operations qc_prep vector to point to a routine that breaks any 64-KB segment into two 32-KB segments and changes the scsi_host_template sg_tablesize element to reduce by half the number of scatter/gather elements allowed. These two changes affect only the OSB4. Signed-off-by: Scott Carter Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/pata_serverworks.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index fc5f31d4828e..57de02123c4c 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -251,12 +251,18 @@ static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev pci_write_config_byte(pdev, 0x54, ultra_cfg); } -static struct scsi_host_template serverworks_sht = { +static struct scsi_host_template serverworks_osb4_sht = { + ATA_BMDMA_SHT(DRV_NAME), + .sg_tablesize = LIBATA_DUMB_MAX_PRD, +}; + +static struct scsi_host_template serverworks_csb_sht = { ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations serverworks_osb4_port_ops = { .inherits = &ata_bmdma_port_ops, + .qc_prep = ata_bmdma_dumb_qc_prep, .cable_detect = serverworks_cable_detect, .mode_filter = serverworks_osb4_filter, .set_piomode = serverworks_set_piomode, @@ -265,6 +271,7 @@ static struct ata_port_operations serverworks_osb4_port_ops = { static struct ata_port_operations serverworks_csb_port_ops = { .inherits = &serverworks_osb4_port_ops, + .qc_prep = ata_bmdma_qc_prep, .mode_filter = serverworks_csb_filter, }; @@ -404,6 +411,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id } }; const struct ata_port_info *ppi[] = { &info[id->driver_data], NULL }; + struct scsi_host_template *sht = &serverworks_csb_sht; int rc; rc = pcim_enable_device(pdev); @@ -417,6 +425,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id /* Select non UDMA capable OSB4 if we can't do fixups */ if (rc < 0) ppi[0] = &info[1]; + sht = &serverworks_osb4_sht; } /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || @@ -433,7 +442,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id ppi[1] = &ata_dummy_port_info; } - return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0); + return ata_pci_bmdma_init_one(pdev, ppi, sht, NULL, 0); } #ifdef CONFIG_PM_SLEEP