Commit fab3e94a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull libata fixes from Tejun Heo:
 "Assorted fixes for libata drivers.

   - Turns out HDIO_GET_32BIT ioctl was subtly broken all along.

   - Recent update to ahci external port handling was incorrectly
     marking hotpluggable ports as external making userland handle
     devices connected to those ports incorrectly.

   - ahci_xgene needs its own irq handler to work around a hardware
     erratum.  libahci updated to allow irq handler override.

   - Misc driver specific updates"

* 'for-4.5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata:
  ata: ahci: don't mark HotPlugCapable Ports as external/removable
  ahci: Workaround for ThunderX Errata#22536
  libata: Align ata_device's id on a cacheline
  Adding Intel Lewisburg device IDs for SATA
  pata-rb532-cf: get rid of the irq_to_gpio() call
  libata: fix HDIO_GET_32BIT ioctl
  ahci_xgene: Implement the workaround to fix the missing of the edge interrupt for the HOST_IRQ_STAT.
  ata: Remove the AHCI_HFLAG_EDGE_IRQ support from libahci.
  libahci: Implement the capability to override the generic ahci interrupt handler.
parents e5322c54 dc8b4afc
...@@ -367,15 +367,21 @@ static const struct pci_device_id ahci_pci_tbl[] = { ...@@ -367,15 +367,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/ { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/ { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
{ PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
/* JMicron 360/1/3/5/6, match class to avoid IDE function */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
...@@ -1325,6 +1331,44 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) ...@@ -1325,6 +1331,44 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{} {}
#endif #endif
#ifdef CONFIG_ARM64
/*
* Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
* Workaround is to make sure all pending IRQs are served before leaving
* handler.
*/
static irqreturn_t ahci_thunderx_irq_handler(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;
unsigned int handled = 1;
VPRINTK("ENTER\n");
hpriv = host->private_data;
mmio = hpriv->mmio;
irq_stat = readl(mmio + HOST_IRQ_STAT);
if (!irq_stat)
return IRQ_NONE;
do {
irq_masked = irq_stat & hpriv->port_map;
spin_lock(&host->lock);
rc = ahci_handle_port_intr(host, irq_masked);
if (!rc)
handled = 0;
writel(irq_stat, mmio + HOST_IRQ_STAT);
irq_stat = readl(mmio + HOST_IRQ_STAT);
spin_unlock(&host->lock);
} while (irq_stat);
VPRINTK("EXIT\n");
return IRQ_RETVAL(handled);
}
#endif
/* /*
* ahci_init_msix() - optionally enable per-port MSI-X otherwise defer * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
* to single msi. * to single msi.
...@@ -1560,6 +1604,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1560,6 +1604,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ahci_broken_devslp(pdev)) if (ahci_broken_devslp(pdev))
hpriv->flags |= AHCI_HFLAG_NO_DEVSLP; hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
#ifdef CONFIG_ARM64
if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
hpriv->irq_handler = ahci_thunderx_irq_handler;
#endif
/* save initial config */ /* save initial config */
ahci_pci_save_initial_config(pdev, hpriv); ahci_pci_save_initial_config(pdev, hpriv);
......
...@@ -240,8 +240,7 @@ enum { ...@@ -240,8 +240,7 @@ enum {
error-handling stage) */ error-handling stage) */
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
Edge Triggered */
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */ AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */
AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */ AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */
...@@ -361,6 +360,7 @@ struct ahci_host_priv { ...@@ -361,6 +360,7 @@ struct ahci_host_priv {
* be overridden anytime before the host is activated. * be overridden anytime before the host is activated.
*/ */
void (*start_engine)(struct ata_port *ap); void (*start_engine)(struct ata_port *ap);
irqreturn_t (*irq_handler)(int irq, void *dev_instance);
}; };
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
...@@ -424,6 +424,7 @@ int ahci_reset_em(struct ata_host *host); ...@@ -424,6 +424,7 @@ int ahci_reset_em(struct ata_host *host);
void ahci_print_info(struct ata_host *host, const char *scc_s); void ahci_print_info(struct ata_host *host, const char *scc_s);
int ahci_host_activate(struct ata_host *host, 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); void ahci_error_handler(struct ata_port *ap);
u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
static inline void __iomem *__ahci_port_base(struct ata_host *host, static inline void __iomem *__ahci_port_base(struct ata_host *host,
unsigned int port_no) unsigned int port_no)
......
...@@ -548,6 +548,88 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, ...@@ -548,6 +548,88 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
return rc; return rc;
} }
/**
* xgene_ahci_handle_broken_edge_irq - Handle the broken irq.
* @ata_host: Host that recieved the irq
* @irq_masked: HOST_IRQ_STAT value
*
* For hardware with broken edge trigger latch
* the HOST_IRQ_STAT register misses the edge interrupt
* when clearing of HOST_IRQ_STAT register and hardware
* reporting the PORT_IRQ_STAT register at the
* same clock cycle.
* As such, the algorithm below outlines the workaround.
*
* 1. Read HOST_IRQ_STAT register and save the state.
* 2. Clear the HOST_IRQ_STAT register.
* 3. Read back the HOST_IRQ_STAT register.
* 4. If HOST_IRQ_STAT register equals to zero, then
* traverse the rest of port's PORT_IRQ_STAT register
* to check if an interrupt is triggered at that point else
* go to step 6.
* 5. If PORT_IRQ_STAT register of rest ports is not equal to zero
* then update the state of HOST_IRQ_STAT saved in step 1.
* 6. Handle port interrupts.
* 7. Exit
*/
static int xgene_ahci_handle_broken_edge_irq(struct ata_host *host,
u32 irq_masked)
{
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *port_mmio;
int i;
if (!readl(hpriv->mmio + HOST_IRQ_STAT)) {
for (i = 0; i < host->n_ports; i++) {
if (irq_masked & (1 << i))
continue;
port_mmio = ahci_port_base(host->ports[i]);
if (readl(port_mmio + PORT_IRQ_STAT))
irq_masked |= (1 << i);
}
}
return ahci_handle_port_intr(host, irq_masked);
}
static irqreturn_t xgene_ahci_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 = xgene_ahci_handle_broken_edge_irq(host, irq_masked);
spin_unlock(&host->lock);
VPRINTK("EXIT\n");
return IRQ_RETVAL(rc);
}
static struct ata_port_operations xgene_ahci_v1_ops = { static struct ata_port_operations xgene_ahci_v1_ops = {
.inherits = &ahci_ops, .inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop, .host_stop = xgene_ahci_host_stop,
...@@ -779,7 +861,8 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -779,7 +861,8 @@ static int xgene_ahci_probe(struct platform_device *pdev)
hpriv->flags = AHCI_HFLAG_NO_NCQ; hpriv->flags = AHCI_HFLAG_NO_NCQ;
break; break;
case XGENE_AHCI_V2: case XGENE_AHCI_V2:
hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ; hpriv->flags |= AHCI_HFLAG_YES_FBS;
hpriv->irq_handler = xgene_ahci_irq_intr;
break; break;
default: default:
break; break;
......
...@@ -113,6 +113,7 @@ static ssize_t ahci_store_em_buffer(struct device *dev, ...@@ -113,6 +113,7 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
const char *buf, size_t size); const char *buf, size_t size);
static ssize_t ahci_show_em_supported(struct device *dev, static ssize_t ahci_show_em_supported(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance);
static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
...@@ -512,6 +513,9 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) ...@@ -512,6 +513,9 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
if (!hpriv->start_engine) if (!hpriv->start_engine)
hpriv->start_engine = ahci_start_engine; hpriv->start_engine = ahci_start_engine;
if (!hpriv->irq_handler)
hpriv->irq_handler = ahci_single_level_irq_intr;
} }
EXPORT_SYMBOL_GPL(ahci_save_initial_config); EXPORT_SYMBOL_GPL(ahci_save_initial_config);
...@@ -1164,8 +1168,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap, ...@@ -1164,8 +1168,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
/* mark esata ports */ /* mark esata ports */
tmp = readl(port_mmio + PORT_CMD); tmp = readl(port_mmio + PORT_CMD);
if ((tmp & PORT_CMD_HPCP) || if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))
((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)))
ap->pflags |= ATA_PFLAG_EXTERNAL; ap->pflags |= ATA_PFLAG_EXTERNAL;
} }
...@@ -1846,7 +1849,7 @@ static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance) ...@@ -1846,7 +1849,7 @@ static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
{ {
unsigned int i, handled = 0; unsigned int i, handled = 0;
...@@ -1872,43 +1875,7 @@ static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) ...@@ -1872,43 +1875,7 @@ static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
return handled; return handled;
} }
EXPORT_SYMBOL_GPL(ahci_handle_port_intr);
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) static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
{ {
...@@ -2535,14 +2502,18 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) ...@@ -2535,14 +2502,18 @@ 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 | AHCI_HFLAG_MULTI_MSIX)) if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) {
if (hpriv->irq_handler)
dev_warn(host->dev, "both AHCI_HFLAG_MULTI_MSI flag set \
and custom irq handler implemented\n");
rc = ahci_host_activate_multi_irqs(host, sht); rc = ahci_host_activate_multi_irqs(host, sht);
else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ) } else {
rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr, rc = ata_host_activate(host, irq, hpriv->irq_handler,
IRQF_SHARED, sht);
else
rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
IRQF_SHARED, sht); IRQF_SHARED, sht);
}
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(ahci_host_activate); EXPORT_SYMBOL_GPL(ahci_host_activate);
......
...@@ -675,19 +675,18 @@ static int ata_ioc32(struct ata_port *ap) ...@@ -675,19 +675,18 @@ static int ata_ioc32(struct ata_port *ap)
int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
int cmd, void __user *arg) int cmd, void __user *arg)
{ {
int val = -EINVAL, rc = -EINVAL; unsigned long val;
int rc = -EINVAL;
unsigned long flags; unsigned long flags;
switch (cmd) { switch (cmd) {
case ATA_IOC_GET_IO32: case HDIO_GET_32BIT:
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
val = ata_ioc32(ap); val = ata_ioc32(ap);
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
if (copy_to_user(arg, &val, 1)) return put_user(val, (unsigned long __user *)arg);
return -EFAULT;
return 0;
case ATA_IOC_SET_IO32: case HDIO_SET_32BIT:
val = (unsigned long) arg; val = (unsigned long) arg;
rc = 0; rc = 0;
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <linux/libata.h> #include <linux/libata.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <asm/mach-rc32434/rb.h>
#define DRV_NAME "pata-rb532-cf" #define DRV_NAME "pata-rb532-cf"
#define DRV_VERSION "0.1.0" #define DRV_VERSION "0.1.0"
#define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash"
...@@ -107,6 +109,7 @@ static int rb532_pata_driver_probe(struct platform_device *pdev) ...@@ -107,6 +109,7 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
int gpio; int gpio;
struct resource *res; struct resource *res;
struct ata_host *ah; struct ata_host *ah;
struct cf_device *pdata;
struct rb532_cf_info *info; struct rb532_cf_info *info;
int ret; int ret;
...@@ -122,7 +125,13 @@ static int rb532_pata_driver_probe(struct platform_device *pdev) ...@@ -122,7 +125,13 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
return -ENOENT; return -ENOENT;
} }
gpio = irq_to_gpio(irq); pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data specified\n");
return -EINVAL;
}
gpio = pdata->gpio_pin;
if (gpio < 0) { if (gpio < 0) {
dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq); dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq);
return -ENOENT; return -ENOENT;
......
...@@ -487,8 +487,8 @@ enum ata_tf_protocols { ...@@ -487,8 +487,8 @@ enum ata_tf_protocols {
}; };
enum ata_ioctls { enum ata_ioctls {
ATA_IOC_GET_IO32 = 0x309, ATA_IOC_GET_IO32 = 0x309, /* HDIO_GET_32BIT */
ATA_IOC_SET_IO32 = 0x324, ATA_IOC_SET_IO32 = 0x324, /* HDIO_SET_32BIT */
}; };
/* core structures */ /* core structures */
......
...@@ -720,7 +720,7 @@ struct ata_device { ...@@ -720,7 +720,7 @@ struct ata_device {
union { union {
u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
}; } ____cacheline_aligned;
/* DEVSLP Timing Variables from Identify Device Data Log */ /* DEVSLP Timing Variables from Identify Device Data Log */
u8 devslp_timing[ATA_LOG_DEVSLP_SIZE]; u8 devslp_timing[ATA_LOG_DEVSLP_SIZE];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment