diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-25 16:49:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-25 16:49:21 -0700 |
commit | 64e22b86854227b4d13a57fa02f26472bc426812 (patch) | |
tree | 2a23b94b3310592249c807c4235ff674b59d844a /drivers/ata/ahci.c | |
parent | 6597ac8a514e2085cf19822a5783345c613312a5 (diff) | |
parent | 243918be6393f643e513a26e7882e6ae06ff7717 (diff) |
Merge branch 'for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata updates from Tejun Heo:
- a number of libata core changes to better support NCQ TRIM.
- ahci now supports MSI-X in single IRQ mode to support a new
controller which doesn't implement MSI or INTX.
- ahci now supports edge-triggered IRQ mode to support a new controller
which for some odd reason did edge-triggered IRQ.
- the usual controller support additions and changes.
* 'for-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (27 commits)
libata: Do not blacklist Micron M500DC
ata: ahci_mvebu: add suspend/resume support
ahci, msix: Fix build error for !PCI_MSI
ahci: Add support for Cavium's ThunderX host controller
ahci: Add generic MSI-X support for single interrupts to SATA PCI driver
libata: finally use __initconst in ata_parse_force_one()
drivers: ata: add support for Ceva sata host controller
devicetree:bindings: add devicetree bindings for ceva ahci
ahci: added support for Freescale AHCI sata
ahci: Store irq number in struct ahci_host_priv
ahci: Move interrupt enablement code to a separate function
Doc: libata: Fix spelling typo found in libata.xml
ata:sata_nv - Change 1 to true for bool type variable.
ata: add Broadcom AHCI SATA3 driver for STB chips
Documentation: devicetree: add Broadcom SATA binding
libata: Fix regression when the NCQ Send and Receive log page is absent
ata: hpt366: fix constant cast warning
ata: ahci_xgene: potential NULL dereference in probe
ata: ahci_xgene: Add AHCI Support for 2nd HW version of APM X-Gene SoC AHCI SATA Host controller.
libahci: Add support to handle HOST_IRQ_STAT as edge trigger latch.
...
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 104 |
1 files changed, 89 insertions, 15 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 65ee94454bbd..7e62751abfac 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -42,6 +42,7 @@ #include <linux/device.h> #include <linux/dmi.h> #include <linux/gfp.h> +#include <linux/msi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <linux/libata.h> @@ -52,6 +53,7 @@ enum { AHCI_PCI_BAR_STA2X11 = 0, + AHCI_PCI_BAR_CAVIUM = 0, AHCI_PCI_BAR_ENMOTUS = 2, AHCI_PCI_BAR_STANDARD = 5, }; @@ -1288,17 +1290,60 @@ 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) +/* + * 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) { 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) - goto intx; + 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; + + hpriv->irq = entry.vector; + + 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) +{ + int rc, nvec; + + if (hpriv->flags & AHCI_HFLAG_NO_MSI) + 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 @@ -1311,8 +1356,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) { @@ -1324,15 +1369,42 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, if (nvec > 1) hpriv->flags |= AHCI_HFLAG_MULTI_MSI; - return nvec; + goto out; single_msi: - if (pci_enable_msi(pdev)) - goto intx; - return 1; + nvec = 1; + + rc = pci_enable_msi(pdev); + if (rc < 0) + return rc; +out: + hpriv->irq = pdev->irq; + + return nvec; +} + +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; + + /* + * 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; -intx: + /* lagacy intx interrupts */ pci_intx(pdev, 1); + hpriv->irq = pdev->irq; + return 0; } @@ -1371,11 +1443,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 @@ -1497,13 +1571,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 @@ -1549,7 +1623,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); |