From d684a90d38e24dcaf95fdb32c83efe05f80d152a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 11 Nov 2015 16:27:33 -0800 Subject: ahci: per-port msix support Some AHCI controllers support per-port MSI-X vectors. At the same time the Linux AHCI driver needs to support one-off architectures that implement a single MSI-X vector for all ports. The heuristic for enabling AHCI ports becomes, in order of preference: 1/ per-port multi-MSI-X 2/ per-port multi-MSI 3/ single MSI 4/ single MSI-X 5/ legacy INTX This all depends on AHCI implementations with potentially broken MSI-X requesting less vectors than the number of ports. If this assumption is violated we will need to start explicitly white-listing AHCI-MSIX implementations. Reported-by: Ricardo Neri [ricardo: fix struct msix_entry handling] Reported-by: kernel test robot Signed-off-by: Dan Williams Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index cdfbcc5..594fcab 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1306,15 +1306,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) #endif /* - * ahci_init_msix() only implements single MSI-X support, not multiple - * MSI-X per-port interrupts. This is needed for host controllers that only - * have MSI-X support implemented, but no MSI or intx. + * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer + * to single msi. */ static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, - struct ahci_host_priv *hpriv) + struct ahci_host_priv *hpriv, unsigned long flags) { - int rc, nvec; - struct msix_entry entry = {}; + int nvec, i, rc; /* Do not init MSI-X if MSI is disabled for the device */ if (hpriv->flags & AHCI_HFLAG_NO_MSI) @@ -1324,22 +1322,39 @@ static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, if (nvec < 0) return nvec; - if (!nvec) { + /* + * Proper MSI-X implementations will have a vector per-port. + * Barring that, we prefer single-MSI over single-MSIX. If this + * check fails (not enough MSI-X vectors for all ports) we will + * be called again with the flag clear iff ahci_init_msi() + * fails. + */ + if (flags & AHCI_HFLAG_MULTI_MSIX) { + if (nvec < n_ports) + return -ENODEV; + nvec = n_ports; + } else if (nvec) { + nvec = 1; + } else { + /* + * Emit dev_err() since this was the non-legacy irq + * method of last resort. + */ rc = -ENODEV; goto fail; } - /* - * There can be more than one vector (e.g. for error detection or - * hdd hotplug). Only the first vector (entry.entry = 0) is used. - */ - rc = pci_enable_msix_exact(pdev, &entry, 1); + for (i = 0; i < nvec; i++) + hpriv->msix[i].entry = i; + rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec); if (rc < 0) goto fail; - hpriv->irq = entry.vector; + if (nvec > 1) + hpriv->flags |= AHCI_HFLAG_MULTI_MSIX; + hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */ - return 1; + return nvec; fail: dev_err(&pdev->dev, "failed to enable MSI-X with error %d, # of vectors: %d\n", @@ -1403,20 +1418,25 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, { int nvec; + /* + * Try to enable per-port MSI-X. If the host is not capable + * fall back to single MSI before finally attempting single + * MSI-X. + */ + nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX); + if (nvec >= 0) + return nvec; + nvec = ahci_init_msi(pdev, n_ports, hpriv); if (nvec >= 0) return nvec; - /* - * Currently, MSI-X support only implements single IRQ mode and - * exists for controllers which can't do other types of IRQ. Only - * set it up if MSI fails. - */ - nvec = ahci_init_msix(pdev, n_ports, hpriv); + /* try single-msix */ + nvec = ahci_init_msix(pdev, n_ports, hpriv, 0); if (nvec >= 0) return nvec; - /* lagacy intx interrupts */ + /* legacy intx interrupts */ pci_intx(pdev, 1); hpriv->irq = pdev->irq; @@ -1578,7 +1598,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!host) return -ENOMEM; host->private_data = hpriv; - + hpriv->msix = devm_kzalloc(&pdev->dev, + sizeof(struct msix_entry) * n_ports, GFP_KERNEL); + if (!hpriv->msix) + return -ENOMEM; ahci_init_interrupts(pdev, n_ports, hpriv); if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 45586c1..9e60c50 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -242,6 +242,7 @@ enum { AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as Edge Triggered */ + AHCI_HFLAG_MULTI_MSIX = (1 << 20), /* per-port MSI-X */ /* ap->flags bits */ @@ -343,6 +344,7 @@ struct ahci_host_priv { * the PHY position in this array. */ struct phy **phys; + struct msix_entry *msix; /* Optional MSI-X support */ unsigned nports; /* Number of ports */ void *plat_data; /* Other platform data */ unsigned int irq; /* interrupt line */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 096064c..0a5645f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "ahci.h" #include "libata.h" @@ -2470,9 +2471,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, } EXPORT_SYMBOL_GPL(ahci_set_em_messages); -static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, +static int ahci_host_activate_multi_irqs(struct ata_host *host, struct scsi_host_template *sht) { + struct ahci_host_priv *hpriv = host->private_data; int i, rc; rc = ata_host_start(host); @@ -2484,6 +2486,12 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, */ for (i = 0; i < host->n_ports; i++) { struct ahci_port_priv *pp = host->ports[i]->private_data; + int irq; + + if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX) + irq = hpriv->msix[i].vector; + else + irq = hpriv->irq + i; /* Do not receive interrupts sent by dummy ports */ if (!pp) { @@ -2491,14 +2499,15 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, continue; } - rc = devm_request_threaded_irq(host->dev, irq + i, + rc = devm_request_threaded_irq(host->dev, irq, ahci_multi_irqs_intr, ahci_port_thread_fn, 0, pp->irq_desc, host->ports[i]); if (rc) return rc; - ata_port_desc(host->ports[i], "irq %d", irq + i); + ata_port_desc(host->ports[i], "irq %d", irq); } + return ata_host_register(host, sht); } @@ -2519,8 +2528,8 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) int irq = hpriv->irq; int rc; - if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) - rc = ahci_host_activate_multi_irqs(host, irq, sht); + if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) + rc = ahci_host_activate_multi_irqs(host, sht); else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ) rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr, IRQF_SHARED, sht); -- cgit v0.10.2 From a6b7fb764ed2a6b7bb1ac96d93c06787aa589092 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 11 Nov 2015 16:27:38 -0800 Subject: ahci: switch from 'threaded' to 'hardirq' interrupt handling For high frequency I/O the overhead of threaded interrupts impacts performance. A quick out-of-the-box test (i.e. no affinity tuning) shows ~10% random read performance at ~20% less cpu. The cpu wins appear to be from reduced lock contention. Signed-off-by: Dan Williams Signed-off-by: Tejun Heo diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 0a5645f..1b6c7cc 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1796,41 +1796,24 @@ static void ahci_port_intr(struct ata_port *ap) ahci_handle_port_interrupt(ap, port_mmio, status); } -static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) +static irqreturn_t ahci_multi_irqs_intr_hard(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); u32 status; - 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); - spin_unlock_bh(ap->lock); - - return IRQ_HANDLED; -} - -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); - atomic_or(status, &pp->intr_status); + spin_lock(ap->lock); + ahci_handle_port_interrupt(ap, port_mmio, status); + spin_unlock(ap->lock); VPRINTK("EXIT\n"); - return IRQ_WAKE_THREAD; + return IRQ_HANDLED; } static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) @@ -2499,10 +2482,9 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, continue; } - rc = devm_request_threaded_irq(host->dev, irq, - ahci_multi_irqs_intr, - ahci_port_thread_fn, 0, - pp->irq_desc, host->ports[i]); + rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard, + 0, pp->irq_desc, host->ports[i]); + if (rc) return rc; ata_port_desc(host->ports[i], "irq %d", irq); -- cgit v0.10.2 From f46c4bd16e26eaf85f82cf95f4c77ade5302171d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 11 Nov 2015 16:37:12 -0800 Subject: ahci: kill 'intr_status' This field in achi_port_priv was only used to support threaded interrupts. Now that we are hardirq only it can be deleted. Signed-off-by: Dan Williams Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 9e60c50..878470f 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -309,7 +309,6 @@ struct ahci_port_priv { unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_sdb:1; - 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 */ -- cgit v0.10.2 From fec7bc433a29ea75b83dd9447629c99b2d4d727a Mon Sep 17 00:00:00 2001 From: Kouei Abe Date: Fri, 20 Nov 2015 21:33:02 +0900 Subject: sata_rcar: Add compatible string for r8a7795 R-Car H3 SoC has compatible SATA controller with R-Car Gen2 SoCs. Signed-off-by: Kouei Abe Signed-off-by: Yoshihiro Kaneko Signed-off-by: Tejun Heo Acked-by: Simon Horman diff --git a/Documentation/devicetree/bindings/ata/sata_rcar.txt b/Documentation/devicetree/bindings/ata/sata_rcar.txt index 2493a5a3..0764f9a 100644 --- a/Documentation/devicetree/bindings/ata/sata_rcar.txt +++ b/Documentation/devicetree/bindings/ata/sata_rcar.txt @@ -8,6 +8,7 @@ Required properties: - "renesas,sata-r8a7790" for R-Car H2 other than ES1 - "renesas,sata-r8a7791" for R-Car M2-W - "renesas,sata-r8a7793" for R-Car M2-N + - "renesas,sata-r8a7795" for R-Car H3 - reg : address and length of the SATA registers; - interrupts : must consist of one interrupt specifier. - clocks : must contain a reference to the functional clock. diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 8804127..2b20b31 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -854,6 +854,10 @@ static struct of_device_id sata_rcar_match[] = { .compatible = "renesas,sata-r8a7793", .data = (void *)RCAR_GEN2_SATA }, + { + .compatible = "renesas,sata-r8a7795", + .data = (void *)RCAR_GEN2_SATA + }, { }, }; MODULE_DEVICE_TABLE(of, sata_rcar_match); -- cgit v0.10.2 From 7f64d642893bc0e6c501f95dad01c36783a94bee Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 24 Nov 2015 15:45:04 +0100 Subject: ata: sata_rcar: Remove obsolete platform_device_id entries Since commit c99cd90d98a98aa1 ("ARM: shmobile: r8a7779: Remove legacy SoC code"), R-Car SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the remaining platform_device_id entries and platform device support. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 2b20b31..f72d601 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -862,13 +862,6 @@ static struct of_device_id sata_rcar_match[] = { }; MODULE_DEVICE_TABLE(of, sata_rcar_match); -static const struct platform_device_id sata_rcar_id_table[] = { - { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */ - { "sata-r8a7779", RCAR_GEN1_SATA }, - { }, -}; -MODULE_DEVICE_TABLE(platform, sata_rcar_id_table); - static int sata_rcar_probe(struct platform_device *pdev) { const struct of_device_id *of_id; @@ -888,11 +881,10 @@ static int sata_rcar_probe(struct platform_device *pdev) return -ENOMEM; of_id = of_match_device(sata_rcar_match, &pdev->dev); - if (of_id) - priv->type = (enum sata_rcar_type)of_id->data; - else - priv->type = platform_get_device_id(pdev)->driver_data; + if (!of_id) + return -ENODEV; + priv->type = (enum sata_rcar_type)of_id->data; priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "failed to get access to sata clock\n"); @@ -1022,7 +1014,6 @@ static const struct dev_pm_ops sata_rcar_pm_ops = { static struct platform_driver sata_rcar_driver = { .probe = sata_rcar_probe, .remove = sata_rcar_remove, - .id_table = sata_rcar_id_table, .driver = { .name = DRV_NAME, .of_match_table = sata_rcar_match, -- cgit v0.10.2 From 7de3244530bf418cefdb64b635ee2d64ef63e3c9 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Thu, 26 Nov 2015 11:56:30 +0900 Subject: ata: ahci_brcmstb: disable NCQ for MIPS-based platforms The most MIPS-based platforms need to disable NCQ while have the NCQ capability in HOST_CAP, and several ARM-based platforms (eg. BCM7349A0, BCM7445A0, BCM7445B0) need to disable too. Signed-off-by: Jaedon Shin Tested-by: Florian Fainelli Acked-by: Brian Norris diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index 14b7305..69b8b02 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -69,10 +69,15 @@ (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \ (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT)) +enum brcm_ahci_quirks { + BRCM_AHCI_QUIRK_NO_NCQ = BIT(0), +}; + struct brcm_ahci_priv { struct device *dev; void __iomem *top_ctrl; u32 port_mask; + u32 quirks; }; static const struct ata_port_info ahci_brcm_port_info = { @@ -256,6 +261,9 @@ static int brcm_ahci_probe(struct platform_device *pdev) if (IS_ERR(priv->top_ctrl)) return PTR_ERR(priv->top_ctrl); + if (of_device_is_compatible(dev->of_node, "brcm,bcm7425-ahci")) + priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ; + brcm_sata_init(priv); priv->port_mask = brcm_ahci_get_portmask(pdev, priv); @@ -273,6 +281,9 @@ static int brcm_ahci_probe(struct platform_device *pdev) if (ret) return ret; + if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ) + hpriv->flags |= AHCI_HFLAG_NO_NCQ; + ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info, &ahci_platform_sht); if (ret) -- cgit v0.10.2 From b46f79bc78e00c392c5cb3eb56c5ee94e4142bcf Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Thu, 26 Nov 2015 11:56:31 +0900 Subject: ata: ahci_brcmstb: add a quirk for MIPS-based platforms Whereas ARM-based platforms have four phy interface registers and information, the MIPS-based platforms have only three registers, and there are no information and documentation. In the original BSP, It using "strict-ahci" did not control these registers. Signed-off-by: Jaedon Shin Tested-by: Florian Fainelli Acked-by: Brian Norris diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index 69b8b02..49f5a9e 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -71,6 +71,7 @@ enum brcm_ahci_quirks { BRCM_AHCI_QUIRK_NO_NCQ = BIT(0), + BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1), }; struct brcm_ahci_priv { @@ -119,6 +120,9 @@ static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port) void __iomem *p; u32 reg; + if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE) + return; + /* clear PHY_DEFAULT_POWER_STATE */ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1; reg = brcm_sata_readreg(p); @@ -148,6 +152,9 @@ static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port) void __iomem *p; u32 reg; + if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE) + return; + /* power-off the PHY digital logic */ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2; reg = brcm_sata_readreg(p); @@ -261,8 +268,10 @@ static int brcm_ahci_probe(struct platform_device *pdev) if (IS_ERR(priv->top_ctrl)) return PTR_ERR(priv->top_ctrl); - if (of_device_is_compatible(dev->of_node, "brcm,bcm7425-ahci")) + if (of_device_is_compatible(dev->of_node, "brcm,bcm7425-ahci")) { priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ; + priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE; + } brcm_sata_init(priv); -- cgit v0.10.2 From 2ef42f4a7ea3f44606ae8ef444f98a6720e82f7d Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Thu, 26 Nov 2015 11:56:32 +0900 Subject: ata: ahci_brcmstb: remove unused definitions Remove unused definitions, and this is to avoid confusion with MIPS-based platforms. Signed-off-by: Jaedon Shin Tested-by: Florian Fainelli Acked-by: Brian Norris diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index 49f5a9e..93e0703 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -52,8 +52,6 @@ #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14) #define SATA_TOP_CTRL_PHY_OFFS 0x8 #define SATA_TOP_MAX_PHYS 2 -#define SATA_TOP_CTRL_SATA_TP_OUT 0x1c -#define SATA_TOP_CTRL_CLIENT_INIT_CTRL 0x20 /* On big-endian MIPS, buses are reversed to big endian, so switch them back */ #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) -- cgit v0.10.2 From 7e22c0024cf89404407f19955eab39b6d66de7b6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 6 Dec 2015 21:56:33 +0100 Subject: ata: core: fix irq description on AHCI single irq systems On my machine with single irq AHCI just the PCI id is printed as description in /proc/interrupts. I found a related discussion from beginning of this year: http://www.gossamer-threads.com/lists/linux/kernel/2117335 Seems like 4f37b504768c ("libata: Use dev_name() for request_irq() to distinguish devices") tried to fix displaying a proper interrupt description for one scenario but broke it for another one. The mentioned discussion ended in the current situation being considered as broken but w/o a patch to fix it. The following patch is based on a proposal in this mail thread. Now the interrupt is properly described as: PCI-MSI 512000-edge ahci[0000:00:1f.2] By combining both values also the scenario that commit 4f37b504768c ("libata: Use dev_name() for request_irq() to distinguish devices") refers to should still be fine. There it should look like this now: ahci[20100000.ide] Using managed memory allocation ensures that the irq description lives at least as long as the interrupt. Signed-off-by: Heiner Kallweit Signed-off-by: Tejun Heo Cc: Sergei Shtylyov diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b79cb10..60e3686 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6223,6 +6223,7 @@ int ata_host_activate(struct ata_host *host, int irq, struct scsi_host_template *sht) { int i, rc; + char *irq_desc; rc = ata_host_start(host); if (rc) @@ -6234,8 +6235,14 @@ int ata_host_activate(struct ata_host *host, int irq, return ata_host_register(host, sht); } + irq_desc = devm_kasprintf(host->dev, GFP_KERNEL, "%s[%s]", + dev_driver_string(host->dev), + dev_name(host->dev)); + if (!irq_desc) + return -ENOMEM; + rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, - dev_name(host->dev), host); + irq_desc, host); if (rc) return rc; -- cgit v0.10.2 From f893180b79f6ada44068e4fe764eb2de70ee6bea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 5 Dec 2015 16:18:44 -0800 Subject: ahci: compile out msi/msix infrastructure Quoting Arnd: The AHCI driver is used for some on-chip devices that do not use PCI for probing, and it can be built even when CONFIG_PCI is disabled, but that now results in a build failure: ata/libahci.c: In function 'ahci_host_activate_multi_irqs': ata/libahci.c:2475:4: error: invalid use of undefined type 'struct msix_entry' ata/libahci.c:2475:21: error: dereferencing pointer to incomplete type 'struct msix_entry' Add ifdef CONFIG_PCI_MSI infrastructure to compile out the multi-msi and multi-msix code. Reported-by: Arnd Bergmann Tested--by: Arnd Bergmann [arnd: fix up pci enabled case] Reported-by: Paul Gortmaker Fixes: d684a90d38e2 ("ahci: per-port msix support") Signed-off-by: Dan Williams Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 878470f..a4faa43 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -35,6 +35,7 @@ #ifndef _AHCI_H #define _AHCI_H +#include #include #include #include @@ -237,12 +238,18 @@ enum { AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on port start (wait until error-handling stage) */ - AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */ AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as Edge Triggered */ - AHCI_HFLAG_MULTI_MSIX = (1 << 20), /* per-port MSI-X */ +#ifdef CONFIG_PCI_MSI + AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */ + AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */ +#else + /* compile out MSI infrastructure */ + AHCI_HFLAG_MULTI_MSI = 0, + AHCI_HFLAG_MULTI_MSIX = 0, +#endif /* ap->flags bits */ @@ -355,6 +362,21 @@ struct ahci_host_priv { void (*start_engine)(struct ata_port *ap); }; +#ifdef CONFIG_PCI_MSI +static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port) +{ + if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX) + return hpriv->msix[port].vector; + else + return hpriv->irq + port; +} +#else +static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port) +{ + return hpriv->irq; +} +#endif + extern int ahci_ignore_sss; extern struct device_attribute *ahci_shost_attrs[]; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 1b6c7cc..eda3cf2 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2469,12 +2469,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, */ for (i = 0; i < host->n_ports; i++) { struct ahci_port_priv *pp = host->ports[i]->private_data; - int irq; - - if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX) - irq = hpriv->msix[i].vector; - else - irq = hpriv->irq + i; + int irq = ahci_irq_vector(hpriv, i); /* Do not receive interrupts sent by dummy ports */ if (!pp) { -- cgit v0.10.2 From ef0cc7fef4721aa19663da7475c8b862f0a35e0b Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Wed, 16 Dec 2015 13:43:49 +0800 Subject: ahci: qoriq: Adjust the default register values on ls1043a Updated the registers' values to enhance SATA performance and reliability. Signed-off-by: Tang Yuantian Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index d0f9de9..4d613f8 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -39,6 +39,8 @@ #define AHCI_PORT_PHY_4_CFG 0x00480811 #define AHCI_PORT_PHY_5_CFG 0x192c96a4 #define AHCI_PORT_TRANS_CFG 0x08000025 +#define LS1043A_PORT_PHY2 0x28184d1f +#define LS1043A_PORT_PHY3 0x0e081509 #define SATA_ECC_DISABLE 0x00020000 @@ -159,6 +161,12 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) break; case AHCI_LS1043A: + writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); + writel(LS1043A_PORT_PHY2, reg_base + PORT_PHY2); + writel(LS1043A_PORT_PHY3, reg_base + PORT_PHY3); + writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); + break; + case AHCI_LS2080A: writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); break; -- cgit v0.10.2 From e3a6dadc6dca64f464238f8a36876c610400eef9 Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Wed, 16 Dec 2015 13:43:50 +0800 Subject: ahci: qoriq: Update the default Rx watermark value The PTC[RXWM] sets the watermark value for Rx FIFO. The default value 0x20 might be insufficient for some hard drives. If the watermark value is too small, a single-cycle overflow may occur and is reported as a CRC or internal error in the PxSERR register. Updated the value to 0x29 according to the validation test. All LS platforms are affected. Signed-off-by: Tang Yuantian Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 4d613f8..256d911 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -38,7 +38,7 @@ #define AHCI_PORT_PHY_3_CFG 0x0e081004 #define AHCI_PORT_PHY_4_CFG 0x00480811 #define AHCI_PORT_PHY_5_CFG 0x192c96a4 -#define AHCI_PORT_TRANS_CFG 0x08000025 +#define AHCI_PORT_TRANS_CFG 0x08000029 #define LS1043A_PORT_PHY2 0x28184d1f #define LS1043A_PORT_PHY3 0x0e081509 @@ -169,6 +169,7 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) case AHCI_LS2080A: writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); + writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); break; } -- cgit v0.10.2 From dfcdc5fe0379d5650c9306ecc6fcc5cb6cb8982a Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Wed, 16 Dec 2015 14:00:35 +0800 Subject: ahci: qoriq: Adjust the default register values on ls1021a Updated the registers' values to enhance SATA performance and reliability on ls1021a soc. Signed-off-by: Tang Yuantian Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 256d911..7bdee9b 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -34,16 +34,20 @@ /* port register default value */ #define AHCI_PORT_PHY_1_CFG 0xa003fffe -#define AHCI_PORT_PHY_2_CFG 0x28183411 -#define AHCI_PORT_PHY_3_CFG 0x0e081004 -#define AHCI_PORT_PHY_4_CFG 0x00480811 -#define AHCI_PORT_PHY_5_CFG 0x192c96a4 #define AHCI_PORT_TRANS_CFG 0x08000029 -#define LS1043A_PORT_PHY2 0x28184d1f -#define LS1043A_PORT_PHY3 0x0e081509 + +/* for ls1021a */ +#define LS1021A_PORT_PHY2 0x28183414 +#define LS1021A_PORT_PHY3 0x0e080e06 +#define LS1021A_PORT_PHY4 0x064a080b +#define LS1021A_PORT_PHY5 0x2aa86470 #define SATA_ECC_DISABLE 0x00020000 +/* for ls1043a */ +#define LS1043A_PORT_PHY2 0x28184d1f +#define LS1043A_PORT_PHY3 0x0e081509 + enum ahci_qoriq_type { AHCI_LS1021A, AHCI_LS1043A, @@ -153,10 +157,10 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) case AHCI_LS1021A: writel(SATA_ECC_DISABLE, qpriv->ecc_addr); writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); - writel(AHCI_PORT_PHY_2_CFG, reg_base + PORT_PHY2); - writel(AHCI_PORT_PHY_3_CFG, reg_base + PORT_PHY3); - writel(AHCI_PORT_PHY_4_CFG, reg_base + PORT_PHY4); - writel(AHCI_PORT_PHY_5_CFG, reg_base + PORT_PHY5); + writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2); + writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3); + writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4); + writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); break; -- cgit v0.10.2 From 1980eb9bd7d733ce089f9b154c08c2c71fb1f2a7 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Thu, 26 Nov 2015 11:56:29 +0900 Subject: ata: ahci_brcmstb: add support for MIPS-based platforms The BCM7xxx ARM-based and MIPS-based platforms share a similar hardware block for AHCI SATA3. This new compatible string, "brcm,bcm7425-ahci", may be used for most MIPS-based platforms of 40nm process technology. Signed-off-by: Jaedon Shin Tested-by: Florian Fainelli Acked-by: Brian Norris Signed-off-by: Tejun Heo diff --git a/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt index 20ac9bb..6087283 100644 --- a/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt +++ b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt @@ -4,7 +4,9 @@ SATA nodes are defined to describe on-chip Serial ATA controllers. Each SATA controller should have its own node. Required properties: -- compatible : compatible list, may contain "brcm,bcm7445-ahci" and/or +- compatible : should be one or more of + "brcm,bcm7425-ahci" + "brcm,bcm7445-ahci" "brcm,sata3-ahci" - reg : register mappings for AHCI and SATA_TOP_CTRL - reg-names : "ahci" and "top-ctrl" diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 6aaa3f8..861643ea 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -100,7 +100,7 @@ config SATA_AHCI_PLATFORM config AHCI_BRCMSTB tristate "Broadcom STB AHCI SATA support" - depends on ARCH_BRCMSTB + depends on ARCH_BRCMSTB || BMIPS_GENERIC help This option enables support for the AHCI SATA3 controller found on STB SoC's. diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index 93e0703..a4a0940 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -318,6 +318,7 @@ static int brcm_ahci_remove(struct platform_device *pdev) } static const struct of_device_id ahci_of_match[] = { + {.compatible = "brcm,bcm7425-ahci"}, {.compatible = "brcm,bcm7445-ahci"}, {}, }; -- cgit v0.10.2 From 427cc61a4486fa80eccaad2bdfcc50cfd1b46625 Mon Sep 17 00:00:00 2001 From: Insu Yun Date: Tue, 29 Dec 2015 16:21:15 -0500 Subject: sata_sx4: correctly handling failed allocation Since kzalloc can be failed in memory pressure, return error when failed. Signed-off-by: Insu Yun Signed-off-by: Tejun Heo diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index fab504f..48301cb 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -1396,6 +1396,8 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) addr = 0; length = size * 1024 * 1024; buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL); + if (!buf) + return 1; while (addr < length) { pdc20621_put_to_dimm(host, buf, addr, ECC_ERASE_BUF_SZ); -- cgit v0.10.2 From 848c3920866fdb7b8b353408348df7929306e9be Mon Sep 17 00:00:00 2001 From: Anil Veliyankara Madam Date: Thu, 7 Jan 2016 21:18:52 -0800 Subject: drivers: libata-core: Use usleep_range() instead of msleep() for short sleeps (<20 ms) Since msleep() may sleep longer than intended time for values less than 20ms, this patch allows the use of usleep_range for waits less that 20ms. usleep_range is a finer precision implementation of msleep and is designed to be a drop-in replacement for udelay where a precise sleep/busy-wait is unnecessary. More details can be found at http://lkml.org/lkml/2007/8/3/250 and in Documentation/timers/timers-howto.txt. This change has been done to improve the performace in PIO6 mode which is used by viking flash. Cc: xe-kernel@external.cisco.com Signed-off-by: Anil Veliyankara Madam Signed-off-by: Shikha Jain Signed-off-by: Tejun Heo diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 60e3686..f5ae6f4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -6704,7 +6705,12 @@ void ata_msleep(struct ata_port *ap, unsigned int msecs) if (owns_eh) ata_eh_release(ap); - msleep(msecs); + if (msecs < 20) { + unsigned long usecs = msecs * USEC_PER_MSEC; + usleep_range(usecs, usecs + 50); + } else { + msleep(msecs); + } if (owns_eh) ata_eh_acquire(ap); -- cgit v0.10.2 From 6863caaf15fce962db0387e852b26d9fbf206cfe Mon Sep 17 00:00:00 2001 From: Danesh Petigara Date: Thu, 7 Jan 2016 16:03:30 -0800 Subject: ata: ahci_brcmstb: enable support for ALPM Enable support for ALPM in the host controller's capabilities register. Also adjust the PLL timeout to give it enough time to lock when the port exits slumber mode. tj: minor style updates Signed-off-by: Danesh Petigara Signed-off-by: Florian Fainelli Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index a4a0940..719bed5 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -53,6 +53,10 @@ #define SATA_TOP_CTRL_PHY_OFFS 0x8 #define SATA_TOP_MAX_PHYS 2 +#define SATA_FIRST_PORT_CTRL 0x700 +#define SATA_NEXT_PORT_CTRL_OFFSET 0x80 +#define SATA_PORT_PCTRL6(reg_base) (reg_base + 0x18) + /* On big-endian MIPS, buses are reversed to big endian, so switch them back */ #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) #define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */ @@ -111,6 +115,34 @@ static inline void brcm_sata_writereg(u32 val, void __iomem *addr) writel_relaxed(val, addr); } +static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv) +{ + struct brcm_ahci_priv *priv = hpriv->plat_data; + u32 bus_ctrl, port_ctrl, host_caps; + int i; + + /* Enable support for ALPM */ + bus_ctrl = brcm_sata_readreg(priv->top_ctrl + + SATA_TOP_CTRL_BUS_CTRL); + brcm_sata_writereg(bus_ctrl | OVERRIDE_HWINIT, + priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL); + host_caps = readl(hpriv->mmio + HOST_CAP); + writel(host_caps | HOST_CAP_ALPM, hpriv->mmio); + brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL); + + /* + * Adjust timeout to allow PLL sufficient time to lock while waking + * up from slumber mode. + */ + for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL; + i < SATA_TOP_MAX_PHYS; + i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) { + if (priv->port_mask & BIT(i)) + writel(0xff1003fc, + hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl)); + } +} + static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port) { void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL + @@ -240,6 +272,7 @@ static int brcm_ahci_resume(struct device *dev) brcm_sata_init(priv); brcm_sata_phys_enable(priv); + brcm_sata_alpm_init(hpriv); return ahci_platform_resume(dev); } #endif @@ -284,6 +317,8 @@ static int brcm_ahci_probe(struct platform_device *pdev) return PTR_ERR(hpriv); hpriv->plat_data = priv; + brcm_sata_alpm_init(hpriv); + ret = ahci_platform_enable_resources(hpriv); if (ret) return ret; -- cgit v0.10.2 From 6ca92dd7aff899777a3081c5948409f4bdef7d38 Mon Sep 17 00:00:00 2001 From: Danesh Petigara Date: Thu, 7 Jan 2016 16:03:31 -0800 Subject: ata: ahci_brcmstb: disable DIPM support The Broadcom STB SATA host controller does not support device initiated power management. Disable support for this feature so the driver never sends SETFEATURES commands to the device to enable/disable DIPM. Signed-off-by: Danesh Petigara Signed-off-by: Florian Fainelli Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index 719bed5..f61cbe3 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -84,7 +84,7 @@ struct brcm_ahci_priv { }; static const struct ata_port_info ahci_brcm_port_info = { - .flags = AHCI_FLAG_COMMON, + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_platform_ops, -- cgit v0.10.2 From e39b2bb3b72b999a04e8d295882be3255aca5ade Mon Sep 17 00:00:00 2001 From: Danesh Petigara Date: Thu, 7 Jan 2016 16:03:33 -0800 Subject: libata: skip debounce delay on link resume The link resume logic uses a 200msec delay while debouncing the SControl register. The rationale behind that delay is to accommodate some PHYs that behave badly if their SStatus/ SControl registers are pounded immediately on resume. The Broadcom STB SATA PHY does not seem to have this issue. This patch introduces a new link flag that allows platforms to skip the debounce delay if it isn't needed. Signed-off-by: Danesh Petigara Signed-off-by: Florian Fainelli Signed-off-by: Tejun Heo diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c index f61cbe3..b36cae2 100644 --- a/drivers/ata/ahci_brcmstb.c +++ b/drivers/ata/ahci_brcmstb.c @@ -85,6 +85,7 @@ struct brcm_ahci_priv { static const struct ata_port_info ahci_brcm_port_info = { .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, + .link_flags = ATA_LFLAG_NO_DB_DELAY, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_platform_ops, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f5ae6f4..cbb7471 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3598,7 +3598,8 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * immediately after resuming. Delay 200ms before * debouncing. */ - ata_msleep(link->ap, 200); + if (!(link->flags & ATA_LFLAG_NO_DB_DELAY)) + ata_msleep(link->ap, 200); /* is SControl restored correctly? */ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) diff --git a/include/linux/libata.h b/include/linux/libata.h index 83577f8..088ed92 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -205,6 +205,7 @@ enum { ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */ + ATA_LFLAG_NO_DB_DELAY = (1 << 11), /* no debounce delay on link resume */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ -- cgit v0.10.2