From 3b6eefc1c9381f4222de755c131c0718e9faac2a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 2 May 2015 00:59:16 +0900 Subject: libata: samsung_cf: Constify platform_device_id The platform_device_id is not modified by the driver and core uses it as const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index fa44eb2872db..cbb5a471eb9d 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -638,7 +638,7 @@ static const struct dev_pm_ops pata_s3c_pm_ops = { #endif /* driver device registration */ -static struct platform_device_id pata_s3c_driver_ids[] = { +static const struct platform_device_id pata_s3c_driver_ids[] = { { .name = "s3c64xx-pata", .driver_data = TYPE_S3C64XX, -- cgit v1.2.3-59-g8ed1b From d7b16e4f6283c6ec52b411aa6deb02ca4d030d20 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 4 May 2015 21:54:18 -0400 Subject: libata: Allow NCQ TRIM to be enabled or disabled with a module parameter We have started seeing SSD firmware updates introduce support for queued TRIM. Sadly, in most cases this support is completely untested and can lead to either errors or data corruption. Add two libata force flags that can be used to either enable or disable queued TRIM support. Signed-off-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Signed-off-by: Tejun Heo --- Documentation/kernel-parameters.txt | 2 ++ drivers/ata/libata-core.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 01aa47d3b6ab..14a4be114cdc 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1755,6 +1755,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. * [no]ncq: Turn on or off NCQ. + * [no]ncqtrim: Turn off queued DSM TRIM. + * nohrst, nosrst, norst: suppress hard, soft and both resets. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f6cb1f1b30b7..8c1f0742cc1a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6472,6 +6472,8 @@ static int __init ata_parse_force_one(char **cur, { "3.0Gbps", .spd_limit = 2 }, { "noncq", .horkage_on = ATA_HORKAGE_NONCQ }, { "ncq", .horkage_off = ATA_HORKAGE_NONCQ }, + { "noncqtrim", .horkage_on = ATA_HORKAGE_NO_NCQ_TRIM }, + { "ncqtrim", .horkage_off = ATA_HORKAGE_NO_NCQ_TRIM }, { "dump_id", .horkage_on = ATA_HORKAGE_DUMP_ID }, { "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) }, { "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) }, -- cgit v1.2.3-59-g8ed1b From f303074160d3401970ccae082014e1ee5a9a52c5 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 4 May 2015 21:54:19 -0400 Subject: libata: Expose TRIM capability in sysfs Create a sysfs "trim" attribute for each ata_device that displays whether DSM TRIM is "unsupported", "unqueued", "forced_unqueued" (blacklisted) or "queued". Signed-off-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Signed-off-by: Tejun Heo --- Documentation/ABI/testing/sysfs-ata | 11 +++++++++++ drivers/ata/libata-transport.c | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-ata b/Documentation/ABI/testing/sysfs-ata index 0a932155cbba..9231daef3813 100644 --- a/Documentation/ABI/testing/sysfs-ata +++ b/Documentation/ABI/testing/sysfs-ata @@ -90,6 +90,17 @@ gscr 130: SATA_PMP_GSCR_SII_GPIO Only valid if the device is a PM. +trim + + Shows the DSM TRIM mode currently used by the device. Valid + values are: + unsupported: Drive does not support DSM TRIM + unqueued: Drive supports unqueued DSM TRIM only + queued: Drive supports queued DSM TRIM + forced_unqueued: Drive's unqueued DSM support is known to be + buggy and only unqueued TRIM commands + are sent + spdn_cnt Number of time libata decided to lower the speed of link due to errors. diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index 3227b7c8a05f..d6c37bcd416d 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -560,6 +560,27 @@ show_ata_dev_gscr(struct device *dev, static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL); +static ssize_t +show_ata_dev_trim(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ata_device *ata_dev = transport_class_to_dev(dev); + unsigned char *mode; + + if (!ata_id_has_trim(ata_dev->id)) + mode = "unsupported"; + else if (ata_dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) + mode = "forced_unqueued"; + else if (ata_fpdma_dsm_supported(ata_dev)) + mode = "queued"; + else + mode = "unqueued"; + + return snprintf(buf, 20, "%s\n", mode); +} + +static DEVICE_ATTR(trim, S_IRUGO, show_ata_dev_trim, NULL); + static DECLARE_TRANSPORT_CLASS(ata_dev_class, "ata_device", NULL, NULL, NULL); @@ -733,6 +754,7 @@ struct scsi_transport_template *ata_attach_transport(void) SETUP_DEV_ATTRIBUTE(ering); SETUP_DEV_ATTRIBUTE(id); SETUP_DEV_ATTRIBUTE(gscr); + SETUP_DEV_ATTRIBUTE(trim); BUG_ON(count > ATA_DEV_ATTRS); i->dev_attrs[count] = NULL; -- cgit v1.2.3-59-g8ed1b From 5d3abf8ff67f49271a42c0f7fa4f20f9e046bf0e Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 4 May 2015 21:54:21 -0400 Subject: libata: Fall back to unqueued READ LOG EXT if the DMA variant fails Some devices advertise support for the READ/WRITE LOG DMA EXT commands but fail when we try to issue them. This can lead to queued TRIM being unintentionally disabled since the relevant feature flag is located in a general purpose log page. Fall back to unqueued READ LOG EXT if the DMA variant fails while reading a log page. Signed-off-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 12 +++++++++++- include/linux/libata.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 07f41be38fbe..2893563d0537 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1507,13 +1507,17 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, { struct ata_taskfile tf; unsigned int err_mask; + bool dma = false; DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page); +retry: ata_tf_init(dev, &tf); - if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id)) { + if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) && + !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) { tf.command = ATA_CMD_READ_LOG_DMA_EXT; tf.protocol = ATA_PROT_DMA; + dma = true; } else { tf.command = ATA_CMD_READ_LOG_EXT; tf.protocol = ATA_PROT_PIO; @@ -1527,6 +1531,12 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, buf, sectors * ATA_SECT_SIZE, 0); + if (err_mask && dma) { + dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG; + ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n"); + goto retry; + } + DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 8dad4a307bb8..c3ef58014b33 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -424,6 +424,7 @@ enum { ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */ ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */ ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */ + ATA_HORKAGE_NO_NCQ_LOG = (1 << 23), /* don't use NCQ for log read */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ -- cgit v1.2.3-59-g8ed1b From a129db89d865b1b91995989bcdee783358d774a5 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Wed, 6 May 2015 00:51:10 +0530 Subject: libahci: Refactoring of ahci_single_irq_intr function. This patch refactors the ahci_single_irq_intr function and also rename it to ahci_single_level_irq_intr as it handles a level triggered latch. Signed-off-by: Suman tripathi Signed-off-by: Tejun Heo --- drivers/ata/libahci.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 61a9c07e0dff..aa89c8eecd76 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1826,27 +1826,9 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) return IRQ_WAKE_THREAD; } -static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) +static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) { - struct ata_host *host = dev_instance; - struct ahci_host_priv *hpriv; unsigned int i, handled = 0; - void __iomem *mmio; - u32 irq_stat, irq_masked; - - VPRINTK("ENTER\n"); - - hpriv = host->private_data; - mmio = hpriv->mmio; - - /* sigh. 0xffffffff is a valid return from h/w */ - irq_stat = readl(mmio + HOST_IRQ_STAT); - if (!irq_stat) - return IRQ_NONE; - - irq_masked = irq_stat & hpriv->port_map; - - spin_lock(&host->lock); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap; @@ -1868,6 +1850,33 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) handled = 1; } + return handled; +} + +static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + struct ahci_host_priv *hpriv; + unsigned int rc = 0; + void __iomem *mmio; + u32 irq_stat, irq_masked; + + VPRINTK("ENTER\n"); + + hpriv = host->private_data; + mmio = hpriv->mmio; + + /* sigh. 0xffffffff is a valid return from h/w */ + irq_stat = readl(mmio + HOST_IRQ_STAT); + if (!irq_stat) + return IRQ_NONE; + + irq_masked = irq_stat & hpriv->port_map; + + spin_lock(&host->lock); + + rc = ahci_handle_port_intr(host, irq_masked); + /* HOST_IRQ_STAT behaves as level triggered latch meaning that * it should be cleared after all the port events are cleared; * otherwise, it will raise a spurious interrupt after each @@ -1883,7 +1892,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) VPRINTK("EXIT\n"); - return IRQ_RETVAL(handled); + return IRQ_RETVAL(rc); } unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) @@ -2487,7 +2496,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, + rc = ata_host_activate(host, irq, ahci_single_level_irq_intr, IRQF_SHARED, sht); return rc; } -- cgit v1.2.3-59-g8ed1b From 5903b1643f41ccc0cb3a0cde1d12b1c942914317 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Wed, 6 May 2015 00:51:11 +0530 Subject: libahci: Add support to handle HOST_IRQ_STAT as edge trigger latch. This patch adds the support to handle HOST_IRQ_STAT as edge trigger latch. Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo --- drivers/ata/ahci.h | 2 ++ drivers/ata/libahci.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 71262e08648e..f4429600e2bf 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -238,6 +238,8 @@ enum { 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 */ /* ap->flags bits */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index aa89c8eecd76..1add5baec584 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1853,6 +1853,43 @@ static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) return handled; } +static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + struct ahci_host_priv *hpriv; + unsigned int rc = 0; + void __iomem *mmio; + u32 irq_stat, irq_masked; + + VPRINTK("ENTER\n"); + + hpriv = host->private_data; + mmio = hpriv->mmio; + + /* sigh. 0xffffffff is a valid return from h/w */ + irq_stat = readl(mmio + HOST_IRQ_STAT); + if (!irq_stat) + return IRQ_NONE; + + irq_masked = irq_stat & hpriv->port_map; + + spin_lock(&host->lock); + + /* + * HOST_IRQ_STAT behaves as edge triggered latch meaning that + * it should be cleared before all the port events are cleared. + */ + writel(irq_stat, mmio + HOST_IRQ_STAT); + + rc = ahci_handle_port_intr(host, irq_masked); + + spin_unlock(&host->lock); + + VPRINTK("EXIT\n"); + + return IRQ_RETVAL(rc); +} + static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance) { struct ata_host *host = dev_instance; @@ -2495,6 +2532,9 @@ 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 if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ) + rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr, + IRQF_SHARED, sht); else rc = ata_host_activate(host, irq, ahci_single_level_irq_intr, IRQF_SHARED, sht); -- cgit v1.2.3-59-g8ed1b From c9802a4be6611520dd99d91d0d9c4efcaa0fa281 Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Mon, 11 May 2015 14:06:15 +0530 Subject: ata: ahci_xgene: Add AHCI Support for 2nd HW version of APM X-Gene SoC AHCI SATA Host controller. This patch enables full AHCI feature support for APM X-Gene SoC SATA host controller. The following errata's are removed: 1. 2a0bdff6b95 ("ahci-xgene: fix the dma state machine lockup for the IDENTIFY DEVICE PIO mode command") 2. 09c32aaa368 ("ahci_xgene: Fix the dma state machine lockup for the ATA_CMD_SMART PIO mode command") 3. 1540035da71 ("ahci_xgene: Implement the xgene_ahci_poll_reg_val to support PMP") 4. a3a84bc7c88 ("ahci_xgene: Implement the workaround to support PMP enumeration and discovery") 5. 1102407bb71 ("ahci_xgene: Fix the DMA state machine lockup for the ATA_CMD_PACKET PIO mode command") 6. 72f79f9e35b ("ahci_xgene: Removing NCQ support from the APM X-Gene SoC AHCI SATA Host Controller driver") In addition, enable PMP support for APM X-Gene SoC and enable FBS support for second generation APM X-Gene SoC. Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 105 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 2b78510d94dd..2add250d1555 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "ahci.h" @@ -84,6 +85,11 @@ /* Max retry for link down */ #define MAX_LINK_DOWN_RETRY 3 +enum xgene_ahci_version { + XGENE_AHCI_V1 = 1, + XGENE_AHCI_V2, +}; + struct xgene_ahci_context { struct ahci_host_priv *hpriv; struct device *dev; @@ -542,7 +548,7 @@ softreset_retry: return rc; } -static struct ata_port_operations xgene_ahci_ops = { +static struct ata_port_operations xgene_ahci_v1_ops = { .inherits = &ahci_ops, .host_stop = xgene_ahci_host_stop, .hardreset = xgene_ahci_hardreset, @@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = { .pmp_softreset = xgene_ahci_pmp_softreset }; -static const struct ata_port_info xgene_ahci_port_info = { +static const struct ata_port_info xgene_ahci_v1_port_info = { .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, - .port_ops = &xgene_ahci_ops, + .port_ops = &xgene_ahci_v1_ops, +}; + +static struct ata_port_operations xgene_ahci_v2_ops = { + .inherits = &ahci_ops, + .host_stop = xgene_ahci_host_stop, + .hardreset = xgene_ahci_hardreset, + .read_id = xgene_ahci_read_id, +}; + +static const struct ata_port_info xgene_ahci_v2_port_info = { + .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &xgene_ahci_v2_ops, }; static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) @@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = { AHCI_SHT(DRV_NAME), }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_ahci_acpi_match[] = { + { "APMC0D0D", XGENE_AHCI_V1}, + { "APMC0D32", XGENE_AHCI_V2}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match); +#endif + +static const struct of_device_id xgene_ahci_of_match[] = { + {.compatible = "apm,xgene-ahci", .data = (void *) XGENE_AHCI_V1}, + {.compatible = "apm,xgene-ahci-v2", .data = (void *) XGENE_AHCI_V2}, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); + static int xgene_ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct xgene_ahci_context *ctx; struct resource *res; + const struct of_device_id *of_devid; + enum xgene_ahci_version version = XGENE_AHCI_V1; + const struct ata_port_info *ppi[] = { &xgene_ahci_v1_port_info, + &xgene_ahci_v2_port_info }; int rc; hpriv = ahci_platform_get_resources(pdev); @@ -677,6 +717,37 @@ static int xgene_ahci_probe(struct platform_device *pdev) ctx->csr_mux = csr; } + of_devid = of_match_device(xgene_ahci_of_match, dev); + if (of_devid) { + if (of_devid->data) + version = (enum xgene_ahci_version) of_devid->data; + } +#ifdef CONFIG_ACPI + else { + const struct acpi_device_id *acpi_id; + struct acpi_device_info *info; + acpi_status status; + + acpi_id = acpi_match_device(xgene_ahci_acpi_match, &pdev->dev); + if (!acpi_id) { + dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n"); + version = XGENE_AHCI_V1; + } + + if (acpi_id->driver_data) { + version = (enum xgene_ahci_version) acpi_id->driver_data; + status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info); + if (ACPI_FAILURE(status)) { + dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n", + __func__); + version = XGENE_AHCI_V1; + } + if (info->valid & ACPI_VALID_CID) + version = XGENE_AHCI_V2; + } + } +#endif + dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, hpriv->mmio); @@ -704,9 +775,19 @@ static int xgene_ahci_probe(struct platform_device *pdev) /* Configure the host controller */ xgene_ahci_hw_init(hpriv); skip_clk_phy: - hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; - rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, + switch (version) { + case XGENE_AHCI_V1: + hpriv->flags = AHCI_HFLAG_NO_NCQ; + break; + case XGENE_AHCI_V2: + hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ; + break; + default: + break; + } + + rc = ahci_platform_init_host(pdev, hpriv, ppi[version - 1], &ahci_platform_sht); if (rc) goto disable_resources; @@ -719,20 +800,6 @@ disable_resources: return rc; } -#ifdef CONFIG_ACPI -static const struct acpi_device_id xgene_ahci_acpi_match[] = { - { "APMC0D0D", }, - { } -}; -MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match); -#endif - -static const struct of_device_id xgene_ahci_of_match[] = { - {.compatible = "apm,xgene-ahci"}, - {}, -}; -MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); - static struct platform_driver xgene_ahci_driver = { .probe = xgene_ahci_probe, .remove = ata_platform_remove_one, -- cgit v1.2.3-59-g8ed1b From 2d32d10103bc94ad2461864664b61ea98c930619 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 15 May 2015 12:24:15 +0300 Subject: ata: ahci_xgene: potential NULL dereference in probe Smatch complains about this potential NULL dereference of "acpi_id". Fixes: c9802a4be661 ('ata: ahci_xgene: Add AHCI Support for 2nd HW version of APM X-Gene SoC AHCI SATA Host controller.') Signed-off-by: Dan Carpenter Signed-off-by: Tejun Heo --- drivers/ata/ahci_xgene.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 2add250d1555..e2c6d9e0c5ac 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -732,9 +732,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) if (!acpi_id) { dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n"); version = XGENE_AHCI_V1; - } - - if (acpi_id->driver_data) { + } else if (acpi_id->driver_data) { version = (enum xgene_ahci_version) acpi_id->driver_data; status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info); if (ACPI_FAILURE(status)) { -- cgit v1.2.3-59-g8ed1b From 6ec0a86c645be3fce7ade42f165a6a417c3503b1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 19 May 2015 16:34:05 +0200 Subject: ata: hpt366: fix constant cast warning gcc-5.x warns about a preexisting problem in the hpt36x pata driver: drivers/ata/pata_hpt366.c: In function 'hpt36x_init_one': drivers/ata/pata_hpt366.c:376:9: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-array-qualifiers] Other ata drivers have the same problem, as ata_pci_bmdma_init_one takes a non-const pointer, and they solve it by using a cast to turn that pointer into a normal non-const pointer. I also tried to change the ata core code to make host->private_data a const pointer, but that quickly got out of hand, as some other drivers expect it to be writable, so I ended up using the same hack as the others here. Signed-off-by: Arnd Bergmann Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo --- drivers/ata/pata_hpt366.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index cbc3de793d1d..0038dc4c06c7 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -352,7 +352,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) }; const struct ata_port_info *ppi[] = { &info_hpt366, NULL }; - void *hpriv = NULL; + const void *hpriv = NULL; u32 reg1; int rc; @@ -383,7 +383,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) break; } /* Now kick off ATA set up */ - return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0); + return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, (void *)hpriv, 0); } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3-59-g8ed1b From eab6ee1ce3c4678224d70338134f7a02005768cb Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 19 May 2015 19:44:17 -0400 Subject: libata: Fix regression when the NCQ Send and Receive log page is absent Commit 5d3abf8ff67f ("libata: Fall back to unqueued READ LOG EXT if the DMA variant fails") allowed us to fall back to the unqueued READ LOG variant if the queued version failed. However, if the device did not support the page at all we would end up looping due to a merge snafu. Ensure we only take the fallback path once. Signed-off-by: Martin K. Petersen Reported-by: Sergey Senozhatsky Tested-by: Sergey Senozhatsky Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2893563d0537..2b370ee0ae86 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1521,6 +1521,7 @@ retry: } else { tf.command = ATA_CMD_READ_LOG_EXT; tf.protocol = ATA_PROT_PIO; + dma = false; } tf.lbal = log; tf.lbam = page; -- cgit v1.2.3-59-g8ed1b From 766a2d9796327b9fe7581b51601c15dec5082885 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 12 May 2015 16:28:21 -0700 Subject: ata: add Broadcom AHCI SATA3 driver for STB chips Pretty straightforward driver, using the nice library-ization of the generic ahci_platform driver. Signed-off-by: Brian Norris Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/ahci_brcmstb.c | 322 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 drivers/ata/ahci_brcmstb.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ee5209fb82b2..e881503fd4c6 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -98,6 +98,15 @@ config SATA_AHCI_PLATFORM If unsure, say N. +config AHCI_BRCMSTB + tristate "Broadcom STB AHCI SATA support" + depends on ARCH_BRCMSTB + help + This option enables support for the AHCI SATA3 controller found on + STB SoC's. + + If unsure, say N. + config AHCI_DA850 tristate "DaVinci DA850 AHCI SATA support" depends on ARCH_DAVINCI_DA850 diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 40f7865f20a1..5154753ade63 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o +obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c new file mode 100644 index 000000000000..ce1e3a885981 --- /dev/null +++ b/drivers/ata/ahci_brcmstb.c @@ -0,0 +1,322 @@ +/* + * Broadcom SATA3 AHCI Controller Driver + * + * Copyright © 2009-2015 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ahci.h" + +#define DRV_NAME "brcm-ahci" + +#define SATA_TOP_CTRL_VERSION 0x0 +#define SATA_TOP_CTRL_BUS_CTRL 0x4 + #define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */ + #define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */ + #define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */ + #define PIODATA_ENDIAN_SHIFT 6 + #define ENDIAN_SWAP_NONE 0 + #define ENDIAN_SWAP_FULL 2 + #define OVERRIDE_HWINIT BIT(16) +#define SATA_TOP_CTRL_TP_CTRL 0x8 +#define SATA_TOP_CTRL_PHY_CTRL 0xc + #define SATA_TOP_CTRL_PHY_CTRL_1 0x0 + #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14) + #define SATA_TOP_CTRL_PHY_CTRL_2 0x4 + #define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0) + #define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1) + #define SATA_TOP_CTRL_2_SW_RST_RX BIT(2) + #define SATA_TOP_CTRL_2_SW_RST_TX BIT(3) + #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) +#define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */ +#define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */ +#else +#define DATA_ENDIAN 0 +#define MMIO_ENDIAN 0 +#endif + +#define BUS_CTRL_ENDIAN_CONF \ + ((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \ + (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \ + (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT)) + +struct brcm_ahci_priv { + struct device *dev; + void __iomem *top_ctrl; + u32 port_mask; +}; + +static const struct ata_port_info ahci_brcm_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_platform_ops, +}; + +static inline u32 brcm_sata_readreg(void __iomem *addr) +{ + /* + * MIPS endianness is configured by boot strap, which also reverses all + * bus endianness (i.e., big-endian CPU + big endian bus ==> native + * endian I/O). + * + * Other architectures (e.g., ARM) either do not support big endian, or + * else leave I/O in little endian mode. + */ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) + return __raw_readl(addr); + else + return readl_relaxed(addr); +} + +static inline void brcm_sata_writereg(u32 val, void __iomem *addr) +{ + /* See brcm_sata_readreg() comments */ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) + __raw_writel(val, addr); + else + writel_relaxed(val, addr); +} + +static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port) +{ + void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL + + (port * SATA_TOP_CTRL_PHY_OFFS); + void __iomem *p; + u32 reg; + + /* clear PHY_DEFAULT_POWER_STATE */ + p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1; + reg = brcm_sata_readreg(p); + reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE; + brcm_sata_writereg(reg, p); + + /* reset the PHY digital logic */ + p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2; + reg = brcm_sata_readreg(p); + reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB | + SATA_TOP_CTRL_2_SW_RST_RX); + reg |= SATA_TOP_CTRL_2_SW_RST_TX; + brcm_sata_writereg(reg, p); + reg = brcm_sata_readreg(p); + reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET; + brcm_sata_writereg(reg, p); + reg = brcm_sata_readreg(p); + reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET; + brcm_sata_writereg(reg, p); + (void)brcm_sata_readreg(p); +} + +static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port) +{ + void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL + + (port * SATA_TOP_CTRL_PHY_OFFS); + void __iomem *p; + u32 reg; + + /* power-off the PHY digital logic */ + p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2; + reg = brcm_sata_readreg(p); + reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB | + SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX | + SATA_TOP_CTRL_2_PHY_GLOBAL_RESET); + brcm_sata_writereg(reg, p); + + /* set PHY_DEFAULT_POWER_STATE */ + p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1; + reg = brcm_sata_readreg(p); + reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE; + brcm_sata_writereg(reg, p); +} + +static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv) +{ + int i; + + for (i = 0; i < SATA_TOP_MAX_PHYS; i++) + if (priv->port_mask & BIT(i)) + brcm_sata_phy_enable(priv, i); +} + +static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv) +{ + int i; + + for (i = 0; i < SATA_TOP_MAX_PHYS; i++) + if (priv->port_mask & BIT(i)) + brcm_sata_phy_disable(priv, i); +} + +static u32 brcm_ahci_get_portmask(struct platform_device *pdev, + struct brcm_ahci_priv *priv) +{ + void __iomem *ahci; + struct resource *res; + u32 impl; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci"); + ahci = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ahci)) + return 0; + + impl = readl(ahci + HOST_PORTS_IMPL); + + if (fls(impl) > SATA_TOP_MAX_PHYS) + dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n", + impl); + else if (!impl) + dev_info(priv->dev, "no ports found\n"); + + devm_iounmap(&pdev->dev, ahci); + devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); + + return impl; +} + +static void brcm_sata_init(struct brcm_ahci_priv *priv) +{ + /* Configure endianness */ + brcm_sata_writereg(BUS_CTRL_ENDIAN_CONF, + priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL); +} + +static int brcm_ahci_suspend(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + struct brcm_ahci_priv *priv = hpriv->plat_data; + int ret; + + ret = ahci_platform_suspend(dev); + brcm_sata_phys_disable(priv); + return ret; +} + +static int brcm_ahci_resume(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; + struct brcm_ahci_priv *priv = hpriv->plat_data; + + brcm_sata_init(priv); + brcm_sata_phys_enable(priv); + return ahci_platform_resume(dev); +} + +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + +static int brcm_ahci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct brcm_ahci_priv *priv; + struct ahci_host_priv *hpriv; + struct resource *res; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl"); + priv->top_ctrl = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->top_ctrl)) + return PTR_ERR(priv->top_ctrl); + + brcm_sata_init(priv); + + priv->port_mask = brcm_ahci_get_portmask(pdev, priv); + if (!priv->port_mask) + return -ENODEV; + + brcm_sata_phys_enable(priv); + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + hpriv->plat_data = priv; + + ret = ahci_platform_enable_resources(hpriv); + if (ret) + return ret; + + ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info, + &ahci_platform_sht); + if (ret) + return ret; + + dev_info(dev, "Broadcom AHCI SATA3 registered\n"); + + return 0; +} + +static int brcm_ahci_remove(struct platform_device *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct ahci_host_priv *hpriv = host->private_data; + struct brcm_ahci_priv *priv = hpriv->plat_data; + int ret; + + ret = ata_platform_remove_one(pdev); + if (ret) + return ret; + + brcm_sata_phys_disable(priv); + + return 0; +} + +static const struct of_device_id ahci_of_match[] = { + {.compatible = "brcm,bcm7445-ahci"}, + {}, +}; +MODULE_DEVICE_TABLE(of, ahci_of_match); + +static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume); + +static struct platform_driver brcm_ahci_driver = { + .probe = brcm_ahci_probe, + .remove = brcm_ahci_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = ahci_of_match, + .pm = &ahci_brcm_pm_ops, + }, +}; +module_platform_driver(brcm_ahci_driver); + +MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver"); +MODULE_AUTHOR("Brian Norris"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sata-brcmstb"); -- cgit v1.2.3-59-g8ed1b From c13aff32135f96e2d53373c807260b96a62cfead Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 26 May 2015 01:38:25 +0530 Subject: ata:sata_nv - Change 1 to true for bool type variable. The variable swncq_enabled is bool type. Hence initialize it with true instead of 1. Signed-off-by: Shailendra Verma Signed-off-by: Tejun Heo --- drivers/ata/sata_nv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 7ece85f43020..734f563b8d37 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -599,7 +599,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); static bool adma_enabled; -static bool swncq_enabled = 1; +static bool swncq_enabled = true; static bool msi_enabled; static void nv_adma_register_mode(struct ata_port *ap) -- cgit v1.2.3-59-g8ed1b From 8485187b5e458d17d63a597484391b98bbcdbb7b Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 29 May 2015 23:11:51 +0900 Subject: Doc: libata: Fix spelling typo found in libata.xml This patch fix a spelling typo found in libata.xml. It is because libata.xml is generated from comments in source, I have to fix it in libata-core.c Signed-off-by: Masanari Iida Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8c1f0742cc1a..52c640da9d4e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3654,7 +3654,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * EH context. * * RETURNS: - * 0 on succes, -errno otherwise. + * 0 on success, -errno otherwise. */ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, bool spm_wakeup) -- cgit v1.2.3-59-g8ed1b From a1c823117894ed79943a87b1c718139cc1be1b6a Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 31 May 2015 13:55:17 +0200 Subject: ahci: Move interrupt enablement code to a separate function This patch refactors ahci_init_interrupts() and moves msi code to a separate function. Need the split since we add msix initialization in a later patch. The initialization for msix will be done after msi but before intx. Signed-off-by: Robert Richter Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c7a92a743ed0..7ba5332476c6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1201,17 +1201,17 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) {} #endif -static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, - struct ahci_host_priv *hpriv) +static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, + struct ahci_host_priv *hpriv) { int rc, nvec; if (hpriv->flags & AHCI_HFLAG_NO_MSI) - goto intx; + return -ENODEV; nvec = pci_msi_vec_count(pdev); if (nvec < 0) - goto intx; + return nvec; /* * If number of MSIs is less than number of ports then Sharing Last @@ -1224,8 +1224,8 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, rc = pci_enable_msi_exact(pdev, nvec); if (rc == -ENOSPC) goto single_msi; - else if (rc < 0) - goto intx; + if (rc < 0) + return rc; /* fallback to single MSI mode if the controller enforced MRSM mode */ if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) { @@ -1240,12 +1240,25 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, return nvec; single_msi: - if (pci_enable_msi(pdev)) - goto intx; + rc = pci_enable_msi(pdev); + if (rc < 0) + return rc; + return 1; +} -intx: +static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, + struct ahci_host_priv *hpriv) +{ + int nvec; + + nvec = ahci_init_msi(pdev, n_ports, hpriv); + if (nvec >= 0) + return nvec; + + /* lagacy intx interrupts */ pci_intx(pdev, 1); + return 0; } -- cgit v1.2.3-59-g8ed1b From 21bfd1aa9527811408d6073d45e5ac8283a28b72 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 31 May 2015 13:55:18 +0200 Subject: ahci: Store irq number in struct ahci_host_priv Currently, ahci supports only msi and intx. To also support msix the handling of the irq number need to be changed. The irq number for msix devices is taken from msi_list instead of pci_dev. Thus, the irq number of a device needs to be stored in struct ahci_host_priv now. This allows the host controller to be activated in a generic way. This change is only intended for ahci drivers. For that reason the irq number is stored in struct ahci_host_priv used only by ahci drivers. Thus, the ABI changes only for ahci_host_activate(), but existing ata drivers (about 50) are unaffected and keep unchanged. All users of ahci_host_activate() have been updated. While touching drivers/ata/libahci.c, doing a small code cleanup in ahci_port_start(). Signed-off-by: Robert Richter Signed-off-by: Tejun Heo --- drivers/ata/acard-ahci.c | 4 +++- drivers/ata/ahci.c | 15 ++++++++++----- drivers/ata/ahci.h | 4 ++-- drivers/ata/libahci.c | 16 +++++++--------- drivers/ata/libahci_platform.c | 4 +++- drivers/ata/sata_highbank.c | 3 ++- 6 files changed, 27 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 12489ce863c4..ed6a30cd681a 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -433,6 +433,8 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; + + hpriv->irq = pdev->irq; hpriv->flags |= (unsigned long)pi.private_data; if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) @@ -498,7 +500,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 ahci_host_activate(host, pdev->irq, &acard_ahci_sht); + return ahci_host_activate(host, &acard_ahci_sht); } module_pci_driver(acard_ahci_pci_driver); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7ba5332476c6..a3c66c3bb76e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1237,14 +1237,18 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, if (nvec > 1) hpriv->flags |= AHCI_HFLAG_MULTI_MSI; - return nvec; + goto out; single_msi: + nvec = 1; + rc = pci_enable_msi(pdev); if (rc < 0) return rc; +out: + hpriv->irq = pdev->irq; - return 1; + return nvec; } static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, @@ -1258,6 +1262,7 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, /* lagacy intx interrupts */ pci_intx(pdev, 1); + hpriv->irq = pdev->irq; return 0; } @@ -1423,13 +1428,13 @@ 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)); - ahci_init_interrupts(pdev, n_ports, hpriv); - host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); if (!host) return -ENOMEM; host->private_data = hpriv; + ahci_init_interrupts(pdev, n_ports, hpriv); + if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) host->flags |= ATA_HOST_PARALLEL_SCAN; else @@ -1475,7 +1480,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - return ahci_host_activate(host, pdev->irq, &ahci_sht); + return ahci_host_activate(host, &ahci_sht); } module_pci_driver(ahci_pci_driver); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index f4429600e2bf..5b8e8a0fab48 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -343,6 +343,7 @@ struct ahci_host_priv { struct phy **phys; unsigned nports; /* Number of ports */ void *plat_data; /* Other platform data */ + unsigned int irq; /* interrupt line */ /* * Optional ahci_start_engine override, if not set this gets set to the * default ahci_start_engine during ahci_save_initial_config, this can @@ -395,8 +396,7 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, struct ata_port_info *pi); int ahci_reset_em(struct ata_host *host); 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); +int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht); void ahci_error_handler(struct ata_port *ap); static inline void __iomem *__ahci_port_base(struct ata_host *host, diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 1add5baec584..1c99402a1017 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2344,7 +2344,7 @@ static int ahci_port_start(struct ata_port *ap) /* * Switch to per-port locking in case each port has its own MSI vector. */ - if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) { + if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) { spin_lock_init(&pp->lock); ap->lock = &pp->lock; } @@ -2472,7 +2472,10 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, rc = ata_host_start(host); if (rc) return rc; - + /* + * Requests IRQs according to AHCI-1.1 when multiple MSIs were + * allocated. That is one MSI per port, starting from @irq. + */ for (i = 0; i < host->n_ports; i++) { struct ahci_port_priv *pp = host->ports[i]->private_data; @@ -2511,23 +2514,18 @@ out_free_irqs: /** * 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 ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) { struct ahci_host_priv *hpriv = host->private_data; + int irq = hpriv->irq; int rc; if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index d89305d289f6..aaa761b9081c 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -518,6 +518,8 @@ int ahci_platform_init_host(struct platform_device *pdev, return -EINVAL; } + hpriv->irq = irq; + /* prepare host */ pi.private_data = (void *)(unsigned long)hpriv->flags; @@ -588,7 +590,7 @@ int ahci_platform_init_host(struct platform_device *pdev, ahci_init_controller(host); ahci_print_info(host, "platform"); - return ahci_host_activate(host, irq, sht); + return ahci_host_activate(host, sht); } EXPORT_SYMBOL_GPL(ahci_platform_init_host); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 24e311fe2c1c..8638d575b2b9 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -499,6 +499,7 @@ static int ahci_highbank_probe(struct platform_device *pdev) return -ENOMEM; } + hpriv->irq = irq; hpriv->flags |= (unsigned long)pi.private_data; hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); @@ -568,7 +569,7 @@ static int ahci_highbank_probe(struct platform_device *pdev) ahci_init_controller(host); ahci_print_info(host, "platform"); - rc = ahci_host_activate(host, irq, &ahci_highbank_platform_sht); + rc = ahci_host_activate(host, &ahci_highbank_platform_sht); if (rc) goto err0; -- cgit v1.2.3-59-g8ed1b From 5163fb62541e38fea400f96dcef9aa539fd00b48 Mon Sep 17 00:00:00 2001 From: Tang Yuantian Date: Thu, 4 Jun 2015 15:10:04 +0800 Subject: ahci: added support for Freescale AHCI sata Freescale introduced QorIQ series SOCs, like ls1021 ls2085, with AHCI sata support. It complies with the serial ATA 3.0 specification and the AHCI 1.3 specification. Signed-off-by: Shaohui Xie Signed-off-by: Yuantian Tang Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/ahci-platform.txt | 2 ++ drivers/ata/ahci_platform.c | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index c2340eeeb97f..a2321819e7f5 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -16,6 +16,8 @@ Required properties: - "snps,dwc-ahci" - "snps,exynos5440-ahci" - "snps,spear-ahci" + - "fsl,qoriq-ahci" : for qoriq series socs which include ls1021, ls2085, etc. + - "fsl,-ahci" : chip could be ls1021, ls2085 etc. - "generic-ahci" - interrupts : - reg : diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 78d6ae0b90c4..614c78f510f0 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -74,6 +74,7 @@ static const struct of_device_id ahci_of_match[] = { { .compatible = "ibm,476gtr-ahci", }, { .compatible = "snps,dwc-ahci", }, { .compatible = "hisilicon,hisi-ahci", }, + { .compatible = "fsl,qoriq-ahci", }, {}, }; MODULE_DEVICE_TABLE(of, ahci_of_match); -- cgit v1.2.3-59-g8ed1b From a73ed35052ca85ff627cf9646760b2a7d69ec5c8 Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Tue, 9 Jun 2015 14:23:50 +0530 Subject: drivers: ata: add support for Ceva sata host controller Adds support for Ceva sata host controller on Xilinx Zynq UltraScale+ MPSoC. Signed-off-by: Suneel Garapati Acked-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 1 + drivers/ata/ahci_ceva.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 drivers/ata/ahci_ceva.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index e881503fd4c6..a987d6f86f6e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -133,6 +133,15 @@ config AHCI_IMX If unsure, say N. +config AHCI_CEVA + tristate "CEVA AHCI SATA support" + depends on OF + help + This option enables support for the CEVA AHCI SATA. + It can be found on the Xilinx Zynq UltraScale+ MPSoC. + + If unsure, say N. + config AHCI_MVEBU tristate "Marvell EBU AHCI SATA support" depends on ARCH_MVEBU diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 5154753ade63..af70919f7dde 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.o libahci.o libahci_platform.o +obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c new file mode 100644 index 000000000000..207649d323c5 --- /dev/null +++ b/drivers/ata/ahci_ceva.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2015 Xilinx, Inc. + * CEVA AHCI SATA platform driver + * + * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +/* Vendor Specific Register Offsets */ +#define AHCI_VEND_PCFG 0xA4 +#define AHCI_VEND_PPCFG 0xA8 +#define AHCI_VEND_PP2C 0xAC +#define AHCI_VEND_PP3C 0xB0 +#define AHCI_VEND_PP4C 0xB4 +#define AHCI_VEND_PP5C 0xB8 +#define AHCI_VEND_PAXIC 0xC0 +#define AHCI_VEND_PTC 0xC8 + +/* Vendor Specific Register bit definitions */ +#define PAXIC_ADBW_BW64 0x1 +#define PAXIC_MAWIDD (1 << 8) +#define PAXIC_MARIDD (1 << 16) +#define PAXIC_OTL (0x4 << 20) + +#define PCFG_TPSS_VAL (0x32 << 16) +#define PCFG_TPRS_VAL (0x2 << 12) +#define PCFG_PAD_VAL 0x2 + +#define PPCFG_TTA 0x1FFFE +#define PPCFG_PSSO_EN (1 << 28) +#define PPCFG_PSS_EN (1 << 29) +#define PPCFG_ESDF_EN (1 << 31) + +#define PP2C_CIBGMN 0x0F +#define PP2C_CIBGMX (0x25 << 8) +#define PP2C_CIBGN (0x18 << 16) +#define PP2C_CINMP (0x29 << 24) + +#define PP3C_CWBGMN 0x04 +#define PP3C_CWBGMX (0x0B << 8) +#define PP3C_CWBGN (0x08 << 16) +#define PP3C_CWNMP (0x0F << 24) + +#define PP4C_BMX 0x0a +#define PP4C_BNM (0x08 << 8) +#define PP4C_SFD (0x4a << 16) +#define PP4C_PTST (0x06 << 24) + +#define PP5C_RIT 0x60216 +#define PP5C_RCT (0x7f0 << 20) + +#define PTC_RX_WM_VAL 0x40 +#define PTC_RSVD (1 << 27) + +#define PORT0_BASE 0x100 +#define PORT1_BASE 0x180 + +/* Port Control Register Bit Definitions */ +#define PORT_SCTL_SPD_GEN2 (0x2 << 4) +#define PORT_SCTL_SPD_GEN1 (0x1 << 4) +#define PORT_SCTL_IPM (0x3 << 8) + +#define PORT_BASE 0x100 +#define PORT_OFFSET 0x80 +#define NR_PORTS 2 +#define DRV_NAME "ahci-ceva" +#define CEVA_FLAG_BROKEN_GEN2 1 + +struct ceva_ahci_priv { + struct platform_device *ahci_pdev; + int flags; +}; + +static struct ata_port_operations ahci_ceva_ops = { + .inherits = &ahci_platform_ops, +}; + +static const struct ata_port_info ahci_ceva_port_info = { + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ceva_ops, +}; + +static void ahci_ceva_setup(struct ahci_host_priv *hpriv) +{ + void __iomem *mmio = hpriv->mmio; + struct ceva_ahci_priv *cevapriv = hpriv->plat_data; + u32 tmp; + int i; + + /* + * AXI Data bus width to 64 + * Set Mem Addr Read, Write ID for data transfers + * Transfer limit to 72 DWord + */ + tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL; + writel(tmp, mmio + AHCI_VEND_PAXIC); + + /* Set AHCI Enable */ + tmp = readl(mmio + HOST_CTL); + tmp |= HOST_AHCI_EN; + writel(tmp, mmio + HOST_CTL); + + for (i = 0; i < NR_PORTS; i++) { + /* TPSS TPRS scalars, CISE and Port Addr */ + tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i); + writel(tmp, mmio + AHCI_VEND_PCFG); + + /* Port Phy Cfg register enables */ + tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN; + writel(tmp, mmio + AHCI_VEND_PPCFG); + + /* Phy Control OOB timing parameters COMINIT */ + tmp = PP2C_CIBGMN | PP2C_CIBGMX | PP2C_CIBGN | PP2C_CINMP; + writel(tmp, mmio + AHCI_VEND_PP2C); + + /* Phy Control OOB timing parameters COMWAKE */ + tmp = PP3C_CWBGMN | PP3C_CWBGMX | PP3C_CWBGN | PP3C_CWNMP; + writel(tmp, mmio + AHCI_VEND_PP3C); + + /* Phy Control Burst timing setting */ + tmp = PP4C_BMX | PP4C_BNM | PP4C_SFD | PP4C_PTST; + writel(tmp, mmio + AHCI_VEND_PP4C); + + /* Rate Change Timer and Retry Interval Timer setting */ + tmp = PP5C_RIT | PP5C_RCT; + writel(tmp, mmio + AHCI_VEND_PP5C); + + /* Rx Watermark setting */ + tmp = PTC_RX_WM_VAL | PTC_RSVD; + writel(tmp, mmio + AHCI_VEND_PTC); + + /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */ + tmp = PORT_SCTL_SPD_GEN2 | PORT_SCTL_IPM; + if (cevapriv->flags & CEVA_FLAG_BROKEN_GEN2) + tmp = PORT_SCTL_SPD_GEN1 | PORT_SCTL_IPM; + writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i); + } +} + +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + +static int ceva_ahci_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct ceva_ahci_priv *cevapriv; + int rc; + + cevapriv = devm_kzalloc(dev, sizeof(*cevapriv), GFP_KERNEL); + if (!cevapriv) + return -ENOMEM; + + cevapriv->ahci_pdev = pdev; + + hpriv = ahci_platform_get_resources(pdev); + if (IS_ERR(hpriv)) + return PTR_ERR(hpriv); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) + return rc; + + if (of_property_read_bool(np, "ceva,broken-gen2")) + cevapriv->flags = CEVA_FLAG_BROKEN_GEN2; + + hpriv->plat_data = cevapriv; + + /* CEVA specific initialization */ + ahci_ceva_setup(hpriv); + + rc = ahci_platform_init_host(pdev, hpriv, &ahci_ceva_port_info, + &ahci_platform_sht); + if (rc) + goto disable_resources; + + return 0; + +disable_resources: + ahci_platform_disable_resources(hpriv); + return rc; +} + +static int __maybe_unused ceva_ahci_suspend(struct device *dev) +{ + return ahci_platform_suspend_host(dev); +} + +static int __maybe_unused ceva_ahci_resume(struct device *dev) +{ + return ahci_platform_resume_host(dev); +} + +static SIMPLE_DEV_PM_OPS(ahci_ceva_pm_ops, ceva_ahci_suspend, ceva_ahci_resume); + +static const struct of_device_id ceva_ahci_of_match[] = { + { .compatible = "ceva,ahci-1v84" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ceva_ahci_of_match); + +static struct platform_driver ceva_ahci_driver = { + .probe = ceva_ahci_probe, + .remove = ata_platform_remove_one, + .driver = { + .name = DRV_NAME, + .of_match_table = ceva_ahci_of_match, + .pm = &ahci_ceva_pm_ops, + }, +}; +module_platform_driver(ceva_ahci_driver); + +MODULE_DESCRIPTION("CEVA AHCI SATA platform driver"); +MODULE_AUTHOR("Xilinx Inc."); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 0f5f264b38122b39cfa0beb65eef6b5ccac94917 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 9 Jun 2015 15:33:19 +0200 Subject: libata: finally use __initconst in ata_parse_force_one() Just six days after this FIXME was added seven years ago, Sam Ravnborg added the missing feature (37c514e3dfc8 "Add missing init section definitions"), though it ended up being called __initconst. Let's use it; better late than never. Signed-off-by: Rasmus Villemoes Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 52c640da9d4e..86052e88b65c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6456,12 +6456,7 @@ static int __init ata_parse_force_one(char **cur, struct ata_force_ent *force_ent, const char **reason) { - /* FIXME: Currently, there's no way to tag init const data and - * using __initdata causes build failure on some versions of - * gcc. Once __initdataconst is implemented, add const to the - * following structure. - */ - static struct ata_force_param force_tbl[] __initdata = { + static const struct ata_force_param force_tbl[] __initconst = { { "40c", .cbl = ATA_CBL_PATA40 }, { "80c", .cbl = ATA_CBL_PATA80 }, { "short40c", .cbl = ATA_CBL_PATA40_SHORT }, -- cgit v1.2.3-59-g8ed1b From ee2aad42e4b6eaa9721196f07f7d5d8d049e6530 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 5 Jun 2015 19:49:25 +0200 Subject: ahci: Add generic MSI-X support for single interrupts to SATA PCI driver This patch adds generic MSI-X support for single interrupts to the SATA PCI driver. MSI-X support is needed for host controller that only have MSI-X support implemented, but no MSI or intx. This patch only adds support for single interrupts, multiple per-port MSI-X interrupts are not yet implemented. The new implementation still initializes MSIs first. Only if that fails, the code tries to enable MSI-X. If that fails too, setup is continued with intx interrupts. To not break other chips by this generic code change, there are the following precautions: * Interrupt ranges are not enabled at all. * Only single interrupt mode is enabled for msix cap devices. Thus, only one interrupt will be setup. * During the discussion with Tejun we agreed to change the init sequence from msix-msi-intx to msi-msix-intx. Thus, if a device offers msi and init does not fail, the msix init code will not be executed. This is equivalent to current code. With this, the code only setups single mode msix as a last resort if msi fails. No interrupt range is enabled at all. Only one interrupt will be enabled. tj: comment edits. Changes of the patch series: v5: * updated patch subject that the patch only implements single IRQ * moved Cavium specific code to a separate patch * detect Cavium ThunderX device with PCI_CLASS_STORAGE_SATA_AHCI instead of vendor/dev id * added more comments to the code * enable single msix support for all kind of devices (removing strict check) * rebased onto update libata/for-4.2 with patch 1, 2 applied v4: * removed implementation of ahci_init_intx() * improved patch descriptions * rebased onto libata/for-4.2 v3: * store irq number in struct ahci_host_priv * change initialization order from msix-msi-intx to msi-msix-intx * improve comments in ahci_init_msix() * improve error message in ahci_init_msix() * do not enable MSI-X if MSI is actively disabled for the device v2: * determine irq vector from pci_dev->msi_list Based on a patch from Sunil Goutham . Signed-off-by: Robert Richter Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a3c66c3bb76e..77a34fc04138 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1201,6 +1202,68 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) {} #endif +static struct msi_desc *msix_get_desc(struct pci_dev *dev, u16 entry) +{ + struct msi_desc *desc; + + list_for_each_entry(desc, &dev->msi_list, list) { + if (desc->msi_attrib.entry_nr == entry) + return desc; + } + + return NULL; +} + +/* + * 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. + */ +static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, + struct ahci_host_priv *hpriv) +{ + struct msi_desc *desc; + int rc, nvec; + struct msix_entry entry = {}; + + /* Do not init MSI-X if MSI is disabled for the device */ + if (hpriv->flags & AHCI_HFLAG_NO_MSI) + return -ENODEV; + + nvec = pci_msix_vec_count(pdev); + if (nvec < 0) + return nvec; + + if (!nvec) { + 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); + if (rc < 0) + goto fail; + + desc = msix_get_desc(pdev, 0); /* first entry */ + if (!desc) { + rc = -EINVAL; + goto fail; + } + + hpriv->irq = desc->irq; + + return 1; +fail: + dev_err(&pdev->dev, + "failed to enable MSI-X with error %d, # of vectors: %d\n", + rc, nvec); + + return rc; +} + static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, struct ahci_host_priv *hpriv) { @@ -1260,6 +1323,15 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, 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); + if (nvec >= 0) + return nvec; + /* lagacy intx interrupts */ pci_intx(pdev, 1); hpriv->irq = pdev->irq; -- cgit v1.2.3-59-g8ed1b From b7ae128d728c42583dac9db48dce9a44bc0fb900 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 5 Jun 2015 19:49:26 +0200 Subject: ahci: Add support for Cavium's ThunderX host controller This patch adds support for Cavium's ThunderX host controller. The controller resides on the SoC and is a AHCI compatible SATA controller with one port, compliant with Serial ATA 3.1 and AHCI Revision 1.31. There can exists multiple SATA controllers on the SoC. The controller depends on MSI-X support since the PCI ECAM controller on the SoC does not implement MSI nor lagacy intx interrupt support. Thus, during device initialization, if MSI fails MSI-X will be used to enable the device's interrupts. The controller uses non-standard BAR0 for its register range. The already existing device lookup (vendor and device id) that is already implemented for other host controllers is used to change the PCI BAR. Signed-off-by: Robert Richter Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 77a34fc04138..bdedaa4f9d7b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -53,6 +53,7 @@ enum { AHCI_PCI_BAR_STA2X11 = 0, + AHCI_PCI_BAR_CAVIUM = 0, AHCI_PCI_BAR_ENMOTUS = 2, AHCI_PCI_BAR_STANDARD = 5, }; @@ -1374,11 +1375,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "PDC42819 can only drive SATA devices with this driver\n"); - /* Both Connext and Enmotus devices use non-standard BARs */ + /* Some devices use non-standard BARs */ if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06) ahci_pci_bar = AHCI_PCI_BAR_STA2X11; else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000) ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; + else if (pdev->vendor == 0x177d && pdev->device == 0xa01c) + ahci_pci_bar = AHCI_PCI_BAR_CAVIUM; /* * The JMicron chip 361/363 contains one SATA controller and one -- cgit v1.2.3-59-g8ed1b From 34c56932ce5278b8bbae13936f9df05cd59e3193 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 17 Jun 2015 15:30:02 +0200 Subject: ahci, msix: Fix build error for !PCI_MSI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turned out the irq vector of the msix can be obtained from struct msix_entry. This makes the lookup function for msi_desc obsolete. This fixes a build error if PCI_MSI is unset: drivers/ata/ahci.c: In function ‘msix_get_desc’: drivers/ata/ahci.c:1210:2: error: ‘struct pci_dev’ has no member named ‘msi_list’ Catched by Fengguang's build bot. Reported-by: kbuild test robot Signed-off-by: Robert Richter Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index bdedaa4f9d7b..c478a40e32c6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1203,18 +1203,6 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) {} #endif -static struct msi_desc *msix_get_desc(struct pci_dev *dev, u16 entry) -{ - struct msi_desc *desc; - - list_for_each_entry(desc, &dev->msi_list, list) { - if (desc->msi_attrib.entry_nr == entry) - return desc; - } - - return NULL; -} - /* * ahci_init_msix() only implements single MSI-X support, not multiple * MSI-X per-port interrupts. This is needed for host controllers that only @@ -1223,7 +1211,6 @@ static struct msi_desc *msix_get_desc(struct pci_dev *dev, u16 entry) static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, struct ahci_host_priv *hpriv) { - struct msi_desc *desc; int rc, nvec; struct msix_entry entry = {}; @@ -1248,13 +1235,7 @@ static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, if (rc < 0) goto fail; - desc = msix_get_desc(pdev, 0); /* first entry */ - if (!desc) { - rc = -EINVAL; - goto fail; - } - - hpriv->irq = desc->irq; + hpriv->irq = entry.vector; return 1; fail: -- cgit v1.2.3-59-g8ed1b From d6ecf158148883be1588859c46d6d424513e2e0d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 17 Jun 2015 14:11:01 +0200 Subject: ata: ahci_mvebu: add suspend/resume support This commit adds suspend/resume support to the ahci_mvebu driver. The suspend hook doesn't do anything special despite calling the generic ahci_platform_suspend_host() function. However, the resume hook has to restore the MBus windows configuration, as well as the regret option. Tested on Marvell Armada 388 GP. Signed-off-by: Thomas Petazzoni Signed-off-by: Tejun Heo --- drivers/ata/ahci_mvebu.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 23716dd8a7ec..8cbbedebadbb 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -62,6 +62,26 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); } +static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state) +{ + return ahci_platform_suspend_host(&pdev->dev); +} + +static int ahci_mvebu_resume(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct ahci_host_priv *hpriv = host->private_data; + const struct mbus_dram_target_info *dram; + + dram = mv_mbus_dram_info(); + if (dram) + ahci_mvebu_mbus_config(hpriv, dram); + + ahci_mvebu_regret_option(hpriv); + + return ahci_platform_resume_host(&pdev->dev); +} + static const struct ata_port_info ahci_mvebu_port_info = { .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, @@ -120,6 +140,8 @@ MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); static struct platform_driver ahci_mvebu_driver = { .probe = ahci_mvebu_probe, .remove = ata_platform_remove_one, + .suspend = ahci_mvebu_suspend, + .resume = ahci_mvebu_resume, .driver = { .name = DRV_NAME, .of_match_table = ahci_mvebu_of_match, -- cgit v1.2.3-59-g8ed1b From 243918be6393f643e513a26e7882e6ae06ff7717 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 18 Jun 2015 14:50:18 -0400 Subject: libata: Do not blacklist Micron M500DC Queued TRIM got disabled on Micron M500DC drives thanks to the "Micron_M500*" pattern we had in place to accommodate the previous generation of this drive family. Tweak the blacklist entry slightly so we only disable queued TRIM for the non-DC variants of M500 drives. Signed-off-by: Martin K. Petersen Cc: stable@vger.kernel.org Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 86052e88b65c..0ed3cb8c0f36 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4225,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, /* devices that don't properly handle queued TRIM commands */ - { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- cgit v1.2.3-59-g8ed1b