Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c930204 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull libata updates from Tejun Heo:
 "Mostly low level driver specific changes.

  Two changes are somewhat noteworthy.  First, Dan's patchset to support
  per-port msix interrupt handling for ahci, which was tried last cycle
  but had to be backed out due to a couple issues, is back and seems to
  be working fine.  Second, libata exception handling now uses
  usleep_range() instead of msleep() for sleeps < 20ms which can make
  things snappier in some corner cases"

* 'for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata:
  libata: skip debounce delay on link resume
  ata: ahci_brcmstb: disable DIPM support
  ata: ahci_brcmstb: enable support for ALPM
  drivers: libata-core: Use usleep_range() instead of msleep() for short sleeps (<20 ms)
  sata_sx4: correctly handling failed allocation
  ata: ahci_brcmstb: add support for MIPS-based platforms
  ahci: qoriq: Adjust the default register values on ls1021a
  ahci: qoriq: Update the default Rx watermark value
  ahci: qoriq: Adjust the default register values on ls1043a
  ahci: compile out msi/msix infrastructure
  ata: core: fix irq description on AHCI single irq systems
  ata: ahci_brcmstb: remove unused definitions
  ata: ahci_brcmstb: add a quirk for MIPS-based platforms
  ata: ahci_brcmstb: disable NCQ for MIPS-based platforms
  ata: sata_rcar: Remove obsolete platform_device_id entries
  sata_rcar: Add compatible string for r8a7795
  ahci: kill 'intr_status'
  ahci: switch from 'threaded' to 'hardirq' interrupt handling
  ahci: per-port msix support
parents 367262c1 e39b2bb3
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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"
+1 −0
Original line number Diff line number Diff line
@@ -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.
+1 −1
Original line number Diff line number Diff line
@@ -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.
+45 −22
Original line number Diff line number Diff line
@@ -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)
+25 −2
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H

#include <linux/pci.h>
#include <linux/clk.h>
#include <linux/libata.h>
#include <linux/phy/phy.h>
@@ -237,11 +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 */
#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 */

@@ -308,7 +316,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 */
@@ -343,6 +350,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 */
@@ -354,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[];
Loading