Commit 37e79a43 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev

* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  ata_piix: add workaround for Samsung DB-P70
  libata: Keep shadow last_ctl up to date during resets
  sata_mv: fix MSI irq race condition
parents f1823acf e9c1670c
...@@ -1289,6 +1289,39 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, ...@@ -1289,6 +1289,39 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
return map; return map;
} }
static bool piix_no_sidpr(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
/*
* Samsung DB-P70 only has three ATA ports exposed and
* curiously the unconnected first port reports link online
* while not responding to SRST protocol causing excessive
* detection delay.
*
* Unfortunately, the system doesn't carry enough DMI
* information to identify the machine but does have subsystem
* vendor and device set. As it's unclear whether the
* subsystem vendor/device is used only for this specific
* board, the port can't be disabled solely with the
* information; however, turning off SIDPR access works around
* the problem. Turn it off.
*
* This problem is reported in bnc#441240.
*
* https://bugzilla.novell.com/show_bug.cgi?id=441420
*/
if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2920 &&
pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG &&
pdev->subsystem_device == 0xb049) {
dev_printk(KERN_WARNING, host->dev,
"Samsung DB-P70 detected, disabling SIDPR\n");
return true;
}
return false;
}
static int __devinit piix_init_sidpr(struct ata_host *host) static int __devinit piix_init_sidpr(struct ata_host *host)
{ {
struct pci_dev *pdev = to_pci_dev(host->dev); struct pci_dev *pdev = to_pci_dev(host->dev);
...@@ -1302,6 +1335,10 @@ static int __devinit piix_init_sidpr(struct ata_host *host) ...@@ -1302,6 +1335,10 @@ static int __devinit piix_init_sidpr(struct ata_host *host)
if (hpriv->map[i] == IDE) if (hpriv->map[i] == IDE)
return 0; return 0;
/* is it blacklisted? */
if (piix_no_sidpr(host))
return 0;
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
return 0; return 0;
......
...@@ -2066,6 +2066,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, ...@@ -2066,6 +2066,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
udelay(20); /* FIXME: flush */ udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr); iowrite8(ap->ctl, ioaddr->ctl_addr);
ap->last_ctl = ap->ctl;
/* wait the port to become ready */ /* wait the port to become ready */
return ata_sff_wait_after_reset(&ap->link, devmask, deadline); return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
...@@ -2190,8 +2191,10 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes) ...@@ -2190,8 +2191,10 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
} }
/* set up device control */ /* set up device control */
if (ap->ioaddr.ctl_addr) if (ap->ioaddr.ctl_addr) {
iowrite8(ap->ctl, ap->ioaddr.ctl_addr); iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
ap->last_ctl = ap->ctl;
}
} }
EXPORT_SYMBOL_GPL(ata_sff_postreset); EXPORT_SYMBOL_GPL(ata_sff_postreset);
...@@ -2534,6 +2537,7 @@ void ata_bus_reset(struct ata_port *ap) ...@@ -2534,6 +2537,7 @@ void ata_bus_reset(struct ata_port *ap)
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
/* set up device control for ATA_FLAG_SATA_RESET */ /* set up device control for ATA_FLAG_SATA_RESET */
iowrite8(ap->ctl, ioaddr->ctl_addr); iowrite8(ap->ctl, ioaddr->ctl_addr);
ap->last_ctl = ap->ctl;
} }
DPRINTK("EXIT\n"); DPRINTK("EXIT\n");
......
...@@ -2218,12 +2218,13 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) ...@@ -2218,12 +2218,13 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
else else
handled = mv_host_intr(host, pending_irqs); handled = mv_host_intr(host, pending_irqs);
} }
spin_unlock(&host->lock);
/* for MSI: unmask; interrupt cause bits will retrigger now */ /* for MSI: unmask; interrupt cause bits will retrigger now */
if (using_msi) if (using_msi)
writel(hpriv->main_irq_mask, hpriv->main_irq_mask_addr); writel(hpriv->main_irq_mask, hpriv->main_irq_mask_addr);
spin_unlock(&host->lock);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
......
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