static void ahci_thaw(struct ata_port *ap);
static void ahci_pmp_attach(struct ata_port *ap);
static void ahci_pmp_detach(struct ata_port *ap);
-static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val);
-static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
.pmp_attach = ahci_pmp_attach,
.pmp_detach = ahci_pmp_detach,
- .pmp_read = ahci_pmp_read,
- .pmp_write = ahci_pmp_write,
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.pmp_attach = ahci_pmp_attach,
.pmp_detach = ahci_pmp_detach,
- .pmp_read = ahci_pmp_read,
- .pmp_write = ahci_pmp_write,
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
u32 status, qc_active;
int rc, known_irq = 0;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
+ /* ignore BAD_PMP while resetting */
+ if (unlikely(resetting))
+ status &= ~PORT_IRQ_BAD_PMP;
+
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
return;
}
if (status & PORT_IRQ_SDB_FIS) {
- /* If the 'N' bit in word 0 of the FIS is set, we just
- * received asynchronous notification. Tell libata
- * about it. Note that as the SDB FIS itself is
- * accessible, SNotification can be emulated by the
- * driver but don't bother for the time being.
+ /* If SNotification is available, leave notification
+ * handling to sata_async_notification(). If not,
+ * emulate it by snooping SDB FIS RX area.
+ *
+ * Snooping FIS RX area is probably cheaper than
+ * poking SNotification but some constrollers which
+ * implement SNotification, ICH9 for example, don't
+ * store AN SDB FIS into receive area.
*/
- const __le32 *f = pp->rx_fis + RX_FIS_SDB;
- u32 f0 = le32_to_cpu(f[0]);
-
- if (f0 & (1 << 15))
+ if (hpriv->cap & HOST_CAP_SNTF)
sata_async_notification(ap);
+ else {
+ /* If the 'N' bit in word 0 of the FIS is set,
+ * we just received asynchronous notification.
+ * Tell libata about it.
+ */
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
}
/* pp->active_link is valid iff any command is in flight */
qc_active = readl(port_mmio + PORT_CMD_ISSUE);
rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+
+ /* If resetting, spurious or invalid completions are expected,
+ * return unconditionally.
+ */
+ if (resetting)
+ return;
+
if (rc > 0)
return;
if (rc < 0) {
writel(tmp, port_mmio + PORT_IRQ_STAT);
writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
- /* turn IRQ back on, ignore BAD_PMP if PMP isn't attached */
- tmp = pp->intr_mask;
- if (!ap->nr_pmp_links)
- tmp &= ~PORT_IRQ_BAD_PMP;
- writel(tmp, port_mmio + PORT_IRQ_MASK);
+ /* turn IRQ back on */
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
static void ahci_error_handler(struct ata_port *ap)
static void ahci_pmp_attach(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
u32 cmd;
cmd = readl(port_mmio + PORT_CMD);
cmd |= PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask |= PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
static void ahci_pmp_detach(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_host_priv *hpriv = ap->host->private_data;
- unsigned long flags;
+ struct ahci_port_priv *pp = ap->private_data;
u32 cmd;
cmd = readl(port_mmio + PORT_CMD);
cmd &= ~PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
- if (hpriv->cap & HOST_CAP_NCQ) {
- spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_NCQ;
- spin_unlock_irqrestore(ap->lock, flags);
- }
-}
-
-static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val)
-{
- struct ata_port *ap = dev->link->ap;
- struct ata_taskfile tf;
- int rc;
-
- ahci_kick_engine(ap, 0);
-
- sata_pmp_read_init_tf(&tf, dev, pmp, reg);
- rc = ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0,
- SATA_PMP_SCR_TIMEOUT);
- if (rc == 0) {
- ahci_tf_read(ap, &tf);
- *r_val = sata_pmp_read_val(&tf);
- }
- return rc;
-}
-
-static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val)
-{
- struct ata_port *ap = dev->link->ap;
- struct ata_taskfile tf;
-
- ahci_kick_engine(ap, 0);
-
- sata_pmp_write_init_tf(&tf, dev, pmp, reg, val);
- return ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0,
- SATA_PMP_SCR_TIMEOUT);
+ pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
static int ahci_port_resume(struct ata_port *ap)