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. ...
This commit is contained in:
@@ -1825,27 +1825,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;
|
||||
@@ -1867,6 +1849,70 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
@@ -1882,7 +1928,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)
|
||||
@@ -2297,7 +2343,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;
|
||||
}
|
||||
@@ -2425,7 +2471,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;
|
||||
|
||||
@@ -2464,29 +2513,27 @@ 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)
|
||||
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_irq_intr,
|
||||
rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
|
||||
IRQF_SHARED, sht);
|
||||
return rc;
|
||||
}
|
||||
|
Reference in New Issue
Block a user