Merge branch 'for-4.5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata fixes from Tejun Heo: - PORTS_IMPL workaround for very early ahci controllers is misbehaving on new systems. Disabled on recent ahci versions. - Old-style PIO state machine had a horrible locking problem. Don't know how we've been getting away this far. Fixed. - Other device specific updates. * 'for-4.5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: ahci: Intel DNV device IDs SATA libata: fix sff host state machine locking while polling libata-sff: use WARN instead of BUG on illegal host state machine state libata: disable forced PORTS_IMPL for >= AHCI 1.3 libata: blacklist a Viking flash model for MWDMA corruption drivers: ata: wake port before DMA stop for ALPM
This commit is contained in:
commit
4e54169986
|
@ -264,6 +264,26 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
|
||||
{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
|
||||
|
|
|
@ -250,6 +250,7 @@ enum {
|
|||
AHCI_HFLAG_MULTI_MSI = 0,
|
||||
AHCI_HFLAG_MULTI_MSIX = 0,
|
||||
#endif
|
||||
AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */
|
||||
|
||||
/* ap->flags bits */
|
||||
|
||||
|
|
|
@ -317,6 +317,7 @@ static int brcm_ahci_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(hpriv))
|
||||
return PTR_ERR(hpriv);
|
||||
hpriv->plat_data = priv;
|
||||
hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
|
||||
|
||||
brcm_sata_alpm_init(hpriv);
|
||||
|
||||
|
|
|
@ -496,8 +496,8 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
|
|||
}
|
||||
}
|
||||
|
||||
/* fabricate port_map from cap.nr_ports */
|
||||
if (!port_map) {
|
||||
/* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
|
||||
if (!port_map && vers < 0x10300) {
|
||||
port_map = (1 << ahci_nr_ports(cap)) - 1;
|
||||
dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
|
||||
|
||||
|
@ -593,8 +593,22 @@ EXPORT_SYMBOL_GPL(ahci_start_engine);
|
|||
int ahci_stop_engine(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_mmio = ahci_port_base(ap);
|
||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||
u32 tmp;
|
||||
|
||||
/*
|
||||
* On some controllers, stopping a port's DMA engine while the port
|
||||
* is in ALPM state (partial or slumber) results in failures on
|
||||
* subsequent DMA engine starts. For those controllers, put the
|
||||
* port back in active state before stopping its DMA engine.
|
||||
*/
|
||||
if ((hpriv->flags & AHCI_HFLAG_WAKE_BEFORE_STOP) &&
|
||||
(ap->link.lpm_policy > ATA_LPM_MAX_POWER) &&
|
||||
ahci_set_lpm(&ap->link, ATA_LPM_MAX_POWER, ATA_LPM_WAKE_ONLY)) {
|
||||
dev_err(ap->host->dev, "Failed to wake up port before engine stop\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
tmp = readl(port_mmio + PORT_CMD);
|
||||
|
||||
/* check if the HBA is idle */
|
||||
|
@ -689,6 +703,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
|||
void __iomem *port_mmio = ahci_port_base(ap);
|
||||
|
||||
if (policy != ATA_LPM_MAX_POWER) {
|
||||
/* wakeup flag only applies to the max power policy */
|
||||
hints &= ~ATA_LPM_WAKE_ONLY;
|
||||
|
||||
/*
|
||||
* Disable interrupts on Phy Ready. This keeps us from
|
||||
* getting woken up due to spurious phy ready
|
||||
|
@ -704,7 +721,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
|||
u32 cmd = readl(port_mmio + PORT_CMD);
|
||||
|
||||
if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
|
||||
cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
|
||||
if (!(hints & ATA_LPM_WAKE_ONLY))
|
||||
cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
|
||||
cmd |= PORT_CMD_ICC_ACTIVE;
|
||||
|
||||
writel(cmd, port_mmio + PORT_CMD);
|
||||
|
@ -712,6 +730,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
|||
|
||||
/* wait 10ms to be sure we've come out of LPM state */
|
||||
ata_msleep(ap, 10);
|
||||
|
||||
if (hints & ATA_LPM_WAKE_ONLY)
|
||||
return 0;
|
||||
} else {
|
||||
cmd |= PORT_CMD_ALPE;
|
||||
if (policy == ATA_LPM_MIN_POWER)
|
||||
|
|
|
@ -4125,6 +4125,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
|
|||
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
|
||||
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
|
||||
{ " 2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA },
|
||||
{ "VRFDFC22048UCHC-TE*", NULL, ATA_HORKAGE_NODMA },
|
||||
/* Odd clown on sil3726/4726 PMPs */
|
||||
{ "Config Disk", NULL, ATA_HORKAGE_DISABLE },
|
||||
|
||||
|
|
|
@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap,
|
|||
static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
unsigned long flags;
|
||||
|
||||
if (ap->ops->error_handler) {
|
||||
if (in_wq) {
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
/* EH might have kicked in while host lock is
|
||||
* released.
|
||||
*/
|
||||
|
@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
|
|||
} else
|
||||
ata_port_freeze(ap);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
} else {
|
||||
if (likely(!(qc->err_mask & AC_ERR_HSM)))
|
||||
ata_qc_complete(qc);
|
||||
|
@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
|
|||
}
|
||||
} else {
|
||||
if (in_wq) {
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ata_sff_irq_on(ap);
|
||||
ata_qc_complete(qc);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
} else
|
||||
ata_qc_complete(qc);
|
||||
}
|
||||
|
@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
|
|||
{
|
||||
struct ata_link *link = qc->dev->link;
|
||||
struct ata_eh_info *ehi = &link->eh_info;
|
||||
unsigned long flags = 0;
|
||||
int poll_next;
|
||||
|
||||
lockdep_assert_held(ap->lock);
|
||||
|
||||
WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
|
||||
|
||||
/* Make sure ata_sff_qc_issue() does not throw things
|
||||
|
@ -1112,14 +1106,6 @@ fsm_start:
|
|||
}
|
||||
}
|
||||
|
||||
/* Send the CDB (atapi) or the first data block (ata pio out).
|
||||
* During the state transition, interrupt handler shouldn't
|
||||
* be invoked before the data transfer is complete and
|
||||
* hsm_task_state is changed. Hence, the following locking.
|
||||
*/
|
||||
if (in_wq)
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
if (qc->tf.protocol == ATA_PROT_PIO) {
|
||||
/* PIO data out protocol.
|
||||
* send first data block.
|
||||
|
@ -1135,9 +1121,6 @@ fsm_start:
|
|||
/* send CDB */
|
||||
atapi_send_cdb(ap, qc);
|
||||
|
||||
if (in_wq)
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* if polling, ata_sff_pio_task() handles the rest.
|
||||
* otherwise, interrupt handler takes over from here.
|
||||
*/
|
||||
|
@ -1296,7 +1279,8 @@ fsm_start:
|
|||
break;
|
||||
default:
|
||||
poll_next = 0;
|
||||
BUG();
|
||||
WARN(true, "ata%d: SFF host state machine in invalid state %d",
|
||||
ap->print_id, ap->hsm_task_state);
|
||||
}
|
||||
|
||||
return poll_next;
|
||||
|
@ -1361,12 +1345,14 @@ static void ata_sff_pio_task(struct work_struct *work)
|
|||
u8 status;
|
||||
int poll_next;
|
||||
|
||||
spin_lock_irq(ap->lock);
|
||||
|
||||
BUG_ON(ap->sff_pio_task_link == NULL);
|
||||
/* qc can be NULL if timeout occurred */
|
||||
qc = ata_qc_from_tag(ap, link->active_tag);
|
||||
if (!qc) {
|
||||
ap->sff_pio_task_link = NULL;
|
||||
return;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
fsm_start:
|
||||
|
@ -1381,11 +1367,14 @@ fsm_start:
|
|||
*/
|
||||
status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
|
||||
if (status & ATA_BUSY) {
|
||||
spin_unlock_irq(ap->lock);
|
||||
ata_msleep(ap, 2);
|
||||
spin_lock_irq(ap->lock);
|
||||
|
||||
status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
|
||||
if (status & ATA_BUSY) {
|
||||
ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
|
||||
return;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1402,6 +1391,8 @@ fsm_start:
|
|||
*/
|
||||
if (poll_next)
|
||||
goto fsm_start;
|
||||
out_unlock:
|
||||
spin_unlock_irq(ap->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -526,6 +526,7 @@ enum ata_lpm_policy {
|
|||
enum ata_lpm_hints {
|
||||
ATA_LPM_EMPTY = (1 << 0), /* port empty/probing */
|
||||
ATA_LPM_HIPM = (1 << 1), /* may use HIPM */
|
||||
ATA_LPM_WAKE_ONLY = (1 << 2), /* only wake up link */
|
||||
};
|
||||
|
||||
/* forward declarations */
|
||||
|
|
Loading…
Reference in New Issue