Merge branch 'for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

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
This commit is contained in:
Linus Torvalds 2016-01-11 19:33:59 -08:00
commit 8c930204ce
12 changed files with 198 additions and 83 deletions

View File

@ -4,7 +4,9 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
Each SATA controller should have its own node. Each SATA controller should have its own node.
Required properties: 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" "brcm,sata3-ahci"
- reg : register mappings for AHCI and SATA_TOP_CTRL - reg : register mappings for AHCI and SATA_TOP_CTRL
- reg-names : "ahci" and "top-ctrl" - reg-names : "ahci" and "top-ctrl"

View File

@ -8,6 +8,7 @@ Required properties:
- "renesas,sata-r8a7790" for R-Car H2 other than ES1 - "renesas,sata-r8a7790" for R-Car H2 other than ES1
- "renesas,sata-r8a7791" for R-Car M2-W - "renesas,sata-r8a7791" for R-Car M2-W
- "renesas,sata-r8a7793" for R-Car M2-N - "renesas,sata-r8a7793" for R-Car M2-N
- "renesas,sata-r8a7795" for R-Car H3
- reg : address and length of the SATA registers; - reg : address and length of the SATA registers;
- interrupts : must consist of one interrupt specifier. - interrupts : must consist of one interrupt specifier.
- clocks : must contain a reference to the functional clock. - clocks : must contain a reference to the functional clock.

View File

@ -100,7 +100,7 @@ config SATA_AHCI_PLATFORM
config AHCI_BRCMSTB config AHCI_BRCMSTB
tristate "Broadcom STB AHCI SATA support" tristate "Broadcom STB AHCI SATA support"
depends on ARCH_BRCMSTB depends on ARCH_BRCMSTB || BMIPS_GENERIC
help help
This option enables support for the AHCI SATA3 controller found on This option enables support for the AHCI SATA3 controller found on
STB SoC's. STB SoC's.

View File

@ -1306,15 +1306,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
#endif #endif
/* /*
* ahci_init_msix() only implements single MSI-X support, not multiple * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
* MSI-X per-port interrupts. This is needed for host controllers that only * to single msi.
* have MSI-X support implemented, but no MSI or intx.
*/ */
static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, 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; int nvec, i, rc;
struct msix_entry entry = {};
/* Do not init MSI-X if MSI is disabled for the device */ /* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI) 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) if (nvec < 0)
return nvec; 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; rc = -ENODEV;
goto fail; goto fail;
} }
/* for (i = 0; i < nvec; i++)
* There can be more than one vector (e.g. for error detection or hpriv->msix[i].entry = i;
* hdd hotplug). Only the first vector (entry.entry = 0) is used. rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec);
*/
rc = pci_enable_msix_exact(pdev, &entry, 1);
if (rc < 0) if (rc < 0)
goto fail; 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: fail:
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to enable MSI-X with error %d, # of vectors: %d\n", "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; 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); nvec = ahci_init_msi(pdev, n_ports, hpriv);
if (nvec >= 0) if (nvec >= 0)
return nvec; return nvec;
/* /* try single-msix */
* Currently, MSI-X support only implements single IRQ mode and nvec = ahci_init_msix(pdev, n_ports, hpriv, 0);
* 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) if (nvec >= 0)
return nvec; return nvec;
/* lagacy intx interrupts */ /* legacy intx interrupts */
pci_intx(pdev, 1); pci_intx(pdev, 1);
hpriv->irq = pdev->irq; 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) if (!host)
return -ENOMEM; return -ENOMEM;
host->private_data = hpriv; 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); ahci_init_interrupts(pdev, n_ports, hpriv);
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)

View File

@ -35,6 +35,7 @@
#ifndef _AHCI_H #ifndef _AHCI_H
#define _AHCI_H #define _AHCI_H
#include <linux/pci.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/libata.h> #include <linux/libata.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
@ -237,11 +238,18 @@ enum {
AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on
port start (wait until port start (wait until
error-handling stage) */ error-handling stage) */
AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
Edge Triggered */ 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 */ /* ap->flags bits */
@ -308,7 +316,6 @@ struct ahci_port_priv {
unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1; unsigned int ncq_saw_sdb:1;
atomic_t intr_status; /* interrupts to handle */
spinlock_t lock; /* protects parent ata_port */ spinlock_t lock; /* protects parent ata_port */
u32 intr_mask; /* interrupts to enable */ u32 intr_mask; /* interrupts to enable */
bool fbs_supported; /* set iff FBS is supported */ bool fbs_supported; /* set iff FBS is supported */
@ -343,6 +350,7 @@ struct ahci_host_priv {
* the PHY position in this array. * the PHY position in this array.
*/ */
struct phy **phys; struct phy **phys;
struct msix_entry *msix; /* Optional MSI-X support */
unsigned nports; /* Number of ports */ unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */ void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */ unsigned int irq; /* interrupt line */
@ -354,6 +362,21 @@ struct ahci_host_priv {
void (*start_engine)(struct ata_port *ap); 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 int ahci_ignore_sss;
extern struct device_attribute *ahci_shost_attrs[]; extern struct device_attribute *ahci_shost_attrs[];

View File

@ -52,8 +52,10 @@
#define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14) #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
#define SATA_TOP_CTRL_PHY_OFFS 0x8 #define SATA_TOP_CTRL_PHY_OFFS 0x8
#define SATA_TOP_MAX_PHYS 2 #define SATA_TOP_MAX_PHYS 2
#define SATA_TOP_CTRL_SATA_TP_OUT 0x1c
#define SATA_TOP_CTRL_CLIENT_INIT_CTRL 0x20 #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 */ /* On big-endian MIPS, buses are reversed to big endian, so switch them back */
#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN) #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
@ -69,14 +71,21 @@
(DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \ (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
(MMIO_ENDIAN << MMIO_ENDIAN_SHIFT)) (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
enum brcm_ahci_quirks {
BRCM_AHCI_QUIRK_NO_NCQ = BIT(0),
BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1),
};
struct brcm_ahci_priv { struct brcm_ahci_priv {
struct device *dev; struct device *dev;
void __iomem *top_ctrl; void __iomem *top_ctrl;
u32 port_mask; u32 port_mask;
u32 quirks;
}; };
static const struct ata_port_info ahci_brcm_port_info = { static const struct ata_port_info ahci_brcm_port_info = {
.flags = AHCI_FLAG_COMMON, .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
.link_flags = ATA_LFLAG_NO_DB_DELAY,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &ahci_platform_ops, .port_ops = &ahci_platform_ops,
@ -107,6 +116,34 @@ static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
writel_relaxed(val, 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) static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
{ {
void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL + void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
@ -114,6 +151,9 @@ static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
void __iomem *p; void __iomem *p;
u32 reg; u32 reg;
if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
return;
/* clear PHY_DEFAULT_POWER_STATE */ /* clear PHY_DEFAULT_POWER_STATE */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1; p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
reg = brcm_sata_readreg(p); reg = brcm_sata_readreg(p);
@ -143,6 +183,9 @@ static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
void __iomem *p; void __iomem *p;
u32 reg; u32 reg;
if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
return;
/* power-off the PHY digital logic */ /* power-off the PHY digital logic */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2; p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
reg = brcm_sata_readreg(p); reg = brcm_sata_readreg(p);
@ -230,6 +273,7 @@ static int brcm_ahci_resume(struct device *dev)
brcm_sata_init(priv); brcm_sata_init(priv);
brcm_sata_phys_enable(priv); brcm_sata_phys_enable(priv);
brcm_sata_alpm_init(hpriv);
return ahci_platform_resume(dev); return ahci_platform_resume(dev);
} }
#endif #endif
@ -256,6 +300,11 @@ static int brcm_ahci_probe(struct platform_device *pdev)
if (IS_ERR(priv->top_ctrl)) if (IS_ERR(priv->top_ctrl))
return PTR_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;
priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
}
brcm_sata_init(priv); brcm_sata_init(priv);
priv->port_mask = brcm_ahci_get_portmask(pdev, priv); priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
@ -269,10 +318,15 @@ static int brcm_ahci_probe(struct platform_device *pdev)
return PTR_ERR(hpriv); return PTR_ERR(hpriv);
hpriv->plat_data = priv; hpriv->plat_data = priv;
brcm_sata_alpm_init(hpriv);
ret = ahci_platform_enable_resources(hpriv); ret = ahci_platform_enable_resources(hpriv);
if (ret) if (ret)
return 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, ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
&ahci_platform_sht); &ahci_platform_sht);
if (ret) if (ret)
@ -300,6 +354,7 @@ static int brcm_ahci_remove(struct platform_device *pdev)
} }
static const struct of_device_id ahci_of_match[] = { static const struct of_device_id ahci_of_match[] = {
{.compatible = "brcm,bcm7425-ahci"},
{.compatible = "brcm,bcm7445-ahci"}, {.compatible = "brcm,bcm7445-ahci"},
{}, {},
}; };

View File

@ -34,14 +34,20 @@
/* port register default value */ /* port register default value */
#define AHCI_PORT_PHY_1_CFG 0xa003fffe #define AHCI_PORT_PHY_1_CFG 0xa003fffe
#define AHCI_PORT_PHY_2_CFG 0x28183411 #define AHCI_PORT_TRANS_CFG 0x08000029
#define AHCI_PORT_PHY_3_CFG 0x0e081004
#define AHCI_PORT_PHY_4_CFG 0x00480811 /* for ls1021a */
#define AHCI_PORT_PHY_5_CFG 0x192c96a4 #define LS1021A_PORT_PHY2 0x28183414
#define AHCI_PORT_TRANS_CFG 0x08000025 #define LS1021A_PORT_PHY3 0x0e080e06
#define LS1021A_PORT_PHY4 0x064a080b
#define LS1021A_PORT_PHY5 0x2aa86470
#define SATA_ECC_DISABLE 0x00020000 #define SATA_ECC_DISABLE 0x00020000
/* for ls1043a */
#define LS1043A_PORT_PHY2 0x28184d1f
#define LS1043A_PORT_PHY3 0x0e081509
enum ahci_qoriq_type { enum ahci_qoriq_type {
AHCI_LS1021A, AHCI_LS1021A,
AHCI_LS1043A, AHCI_LS1043A,
@ -151,16 +157,23 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
case AHCI_LS1021A: case AHCI_LS1021A:
writel(SATA_ECC_DISABLE, qpriv->ecc_addr); writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_PHY_2_CFG, reg_base + PORT_PHY2); writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
writel(AHCI_PORT_PHY_3_CFG, reg_base + PORT_PHY3); writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3);
writel(AHCI_PORT_PHY_4_CFG, reg_base + PORT_PHY4); writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
writel(AHCI_PORT_PHY_5_CFG, reg_base + PORT_PHY5); writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
break; break;
case AHCI_LS1043A: 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: case AHCI_LS2080A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
break; break;
} }

View File

@ -43,6 +43,7 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h> #include <scsi/scsi_cmnd.h>
#include <linux/libata.h> #include <linux/libata.h>
#include <linux/pci.h>
#include "ahci.h" #include "ahci.h"
#include "libata.h" #include "libata.h"
@ -1804,29 +1805,10 @@ static void ahci_port_intr(struct ata_port *ap)
ahci_handle_port_interrupt(ap, port_mmio, status); 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; struct ata_port *ap = dev_instance;
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_port_priv *pp = ap->private_data;
u32 status; u32 status;
VPRINTK("ENTER\n"); VPRINTK("ENTER\n");
@ -1834,11 +1816,13 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
status = readl(port_mmio + PORT_IRQ_STAT); status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, 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"); VPRINTK("EXIT\n");
return IRQ_WAKE_THREAD; return IRQ_HANDLED;
} }
static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
@ -2479,9 +2463,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
} }
EXPORT_SYMBOL_GPL(ahci_set_em_messages); 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 scsi_host_template *sht)
{ {
struct ahci_host_priv *hpriv = host->private_data;
int i, rc; int i, rc;
rc = ata_host_start(host); rc = ata_host_start(host);
@ -2493,6 +2478,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
*/ */
for (i = 0; i < host->n_ports; i++) { for (i = 0; i < host->n_ports; i++) {
struct ahci_port_priv *pp = host->ports[i]->private_data; struct ahci_port_priv *pp = host->ports[i]->private_data;
int irq = ahci_irq_vector(hpriv, i);
/* Do not receive interrupts sent by dummy ports */ /* Do not receive interrupts sent by dummy ports */
if (!pp) { if (!pp) {
@ -2500,14 +2486,14 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
continue; continue;
} }
rc = devm_request_threaded_irq(host->dev, irq + i, rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard,
ahci_multi_irqs_intr, 0, pp->irq_desc, host->ports[i]);
ahci_port_thread_fn, 0,
pp->irq_desc, host->ports[i]);
if (rc) if (rc)
return 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); return ata_host_register(host, sht);
} }
@ -2528,8 +2514,8 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
int irq = hpriv->irq; int irq = hpriv->irq;
int rc; int rc;
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX))
rc = ahci_host_activate_multi_irqs(host, irq, sht); rc = ahci_host_activate_multi_irqs(host, sht);
else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ) else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr, rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
IRQF_SHARED, sht); IRQF_SHARED, sht);

View File

@ -50,6 +50,7 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/time.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/suspend.h> #include <linux/suspend.h>
@ -3597,6 +3598,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
* immediately after resuming. Delay 200ms before * immediately after resuming. Delay 200ms before
* debouncing. * debouncing.
*/ */
if (!(link->flags & ATA_LFLAG_NO_DB_DELAY))
ata_msleep(link->ap, 200); ata_msleep(link->ap, 200);
/* is SControl restored correctly? */ /* is SControl restored correctly? */
@ -6223,6 +6225,7 @@ int ata_host_activate(struct ata_host *host, int irq,
struct scsi_host_template *sht) struct scsi_host_template *sht)
{ {
int i, rc; int i, rc;
char *irq_desc;
rc = ata_host_start(host); rc = ata_host_start(host);
if (rc) if (rc)
@ -6234,8 +6237,14 @@ int ata_host_activate(struct ata_host *host, int irq,
return ata_host_register(host, sht); 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, rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
dev_name(host->dev), host); irq_desc, host);
if (rc) if (rc)
return rc; return rc;
@ -6697,7 +6706,12 @@ void ata_msleep(struct ata_port *ap, unsigned int msecs)
if (owns_eh) if (owns_eh)
ata_eh_release(ap); ata_eh_release(ap);
if (msecs < 20) {
unsigned long usecs = msecs * USEC_PER_MSEC;
usleep_range(usecs, usecs + 50);
} else {
msleep(msecs); msleep(msecs);
}
if (owns_eh) if (owns_eh)
ata_eh_acquire(ap); ata_eh_acquire(ap);

View File

@ -854,17 +854,14 @@ static struct of_device_id sata_rcar_match[] = {
.compatible = "renesas,sata-r8a7793", .compatible = "renesas,sata-r8a7793",
.data = (void *)RCAR_GEN2_SATA .data = (void *)RCAR_GEN2_SATA
}, },
{
.compatible = "renesas,sata-r8a7795",
.data = (void *)RCAR_GEN2_SATA
},
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, 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) static int sata_rcar_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id; const struct of_device_id *of_id;
@ -884,11 +881,10 @@ static int sata_rcar_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
of_id = of_match_device(sata_rcar_match, &pdev->dev); of_id = of_match_device(sata_rcar_match, &pdev->dev);
if (of_id) if (!of_id)
priv->type = (enum sata_rcar_type)of_id->data; return -ENODEV;
else
priv->type = platform_get_device_id(pdev)->driver_data;
priv->type = (enum sata_rcar_type)of_id->data;
priv->clk = devm_clk_get(&pdev->dev, NULL); priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "failed to get access to sata clock\n"); dev_err(&pdev->dev, "failed to get access to sata clock\n");
@ -1018,7 +1014,6 @@ static const struct dev_pm_ops sata_rcar_pm_ops = {
static struct platform_driver sata_rcar_driver = { static struct platform_driver sata_rcar_driver = {
.probe = sata_rcar_probe, .probe = sata_rcar_probe,
.remove = sata_rcar_remove, .remove = sata_rcar_remove,
.id_table = sata_rcar_id_table,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = sata_rcar_match, .of_match_table = sata_rcar_match,

View File

@ -1396,6 +1396,8 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
addr = 0; addr = 0;
length = size * 1024 * 1024; length = size * 1024 * 1024;
buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL); buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
if (!buf)
return 1;
while (addr < length) { while (addr < length) {
pdc20621_put_to_dimm(host, buf, addr, pdc20621_put_to_dimm(host, buf, addr,
ECC_ERASE_BUF_SZ); ECC_ERASE_BUF_SZ);

View File

@ -205,6 +205,7 @@ enum {
ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */
ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */
ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */ 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 */ /* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */