|
@@ -418,6 +418,240 @@ u8 ata_altstatus(struct ata_port *ap)
|
|
|
return inb(ap->ioaddr.altstatus_addr);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
|
|
|
+ * @qc: Info associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ struct ata_port *ap = qc->ap;
|
|
|
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
|
|
|
+ u8 dmactl;
|
|
|
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
|
|
|
+
|
|
|
+ /* load PRD table addr. */
|
|
|
+ mb(); /* make sure PRD table writes are visible to controller */
|
|
|
+ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
|
|
|
+
|
|
|
+ /* specify data direction, triple-check start bit is clear */
|
|
|
+ dmactl = readb(mmio + ATA_DMA_CMD);
|
|
|
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
|
|
|
+ if (!rw)
|
|
|
+ dmactl |= ATA_DMA_WR;
|
|
|
+ writeb(dmactl, mmio + ATA_DMA_CMD);
|
|
|
+
|
|
|
+ /* issue r/w command */
|
|
|
+ ap->ops->exec_command(ap, &qc->tf);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
|
|
|
+ * @qc: Info associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ struct ata_port *ap = qc->ap;
|
|
|
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
|
|
|
+ u8 dmactl;
|
|
|
+
|
|
|
+ /* start host DMA transaction */
|
|
|
+ dmactl = readb(mmio + ATA_DMA_CMD);
|
|
|
+ writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
|
|
|
+
|
|
|
+ /* Strictly, one may wish to issue a readb() here, to
|
|
|
+ * flush the mmio write. However, control also passes
|
|
|
+ * to the hardware at this point, and it will interrupt
|
|
|
+ * us when we are to resume control. So, in effect,
|
|
|
+ * we don't care when the mmio write flushes.
|
|
|
+ * Further, a read of the DMA status register _immediately_
|
|
|
+ * following the write may not be what certain flaky hardware
|
|
|
+ * is expected, so I think it is best to not add a readb()
|
|
|
+ * without first all the MMIO ATA cards/mobos.
|
|
|
+ * Or maybe I'm just being paranoid.
|
|
|
+ */
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
|
|
|
+ * @qc: Info associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ struct ata_port *ap = qc->ap;
|
|
|
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
|
|
|
+ u8 dmactl;
|
|
|
+
|
|
|
+ /* load PRD table addr. */
|
|
|
+ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
|
|
|
+
|
|
|
+ /* specify data direction, triple-check start bit is clear */
|
|
|
+ dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
|
|
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
|
|
|
+ if (!rw)
|
|
|
+ dmactl |= ATA_DMA_WR;
|
|
|
+ outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
|
|
+
|
|
|
+ /* issue r/w command */
|
|
|
+ ap->ops->exec_command(ap, &qc->tf);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
|
|
|
+ * @qc: Info associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ struct ata_port *ap = qc->ap;
|
|
|
+ u8 dmactl;
|
|
|
+
|
|
|
+ /* start host DMA transaction */
|
|
|
+ dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
|
|
+ outb(dmactl | ATA_DMA_START,
|
|
|
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_start - Start a PCI IDE BMDMA transaction
|
|
|
+ * @qc: Info associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * Writes the ATA_DMA_START flag to the DMA command register.
|
|
|
+ *
|
|
|
+ * May be used as the bmdma_start() entry in ata_port_operations.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+void ata_bmdma_start(struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ if (qc->ap->flags & ATA_FLAG_MMIO)
|
|
|
+ ata_bmdma_start_mmio(qc);
|
|
|
+ else
|
|
|
+ ata_bmdma_start_pio(qc);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
|
|
|
+ * @qc: Info associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * Writes address of PRD table to device's PRD Table Address
|
|
|
+ * register, sets the DMA control register, and calls
|
|
|
+ * ops->exec_command() to start the transfer.
|
|
|
+ *
|
|
|
+ * May be used as the bmdma_setup() entry in ata_port_operations.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ if (qc->ap->flags & ATA_FLAG_MMIO)
|
|
|
+ ata_bmdma_setup_mmio(qc);
|
|
|
+ else
|
|
|
+ ata_bmdma_setup_pio(qc);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
|
|
|
+ * @ap: Port associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * Clear interrupt and error flags in DMA status register.
|
|
|
+ *
|
|
|
+ * May be used as the irq_clear() entry in ata_port_operations.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+void ata_bmdma_irq_clear(struct ata_port *ap)
|
|
|
+{
|
|
|
+ if (!ap->ioaddr.bmdma_addr)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (ap->flags & ATA_FLAG_MMIO) {
|
|
|
+ void __iomem *mmio =
|
|
|
+ ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
|
|
|
+ writeb(readb(mmio), mmio);
|
|
|
+ } else {
|
|
|
+ unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
|
|
|
+ outb(inb(addr), addr);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_status - Read PCI IDE BMDMA status
|
|
|
+ * @ap: Port associated with this ATA transaction.
|
|
|
+ *
|
|
|
+ * Read and return BMDMA status register.
|
|
|
+ *
|
|
|
+ * May be used as the bmdma_status() entry in ata_port_operations.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+u8 ata_bmdma_status(struct ata_port *ap)
|
|
|
+{
|
|
|
+ u8 host_stat;
|
|
|
+ if (ap->flags & ATA_FLAG_MMIO) {
|
|
|
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
|
|
|
+ host_stat = readb(mmio + ATA_DMA_STATUS);
|
|
|
+ } else
|
|
|
+ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
|
|
|
+ return host_stat;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
|
|
|
+ * @qc: Command we are ending DMA for
|
|
|
+ *
|
|
|
+ * Clears the ATA_DMA_START flag in the dma control register
|
|
|
+ *
|
|
|
+ * May be used as the bmdma_stop() entry in ata_port_operations.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * spin_lock_irqsave(host_set lock)
|
|
|
+ */
|
|
|
+
|
|
|
+void ata_bmdma_stop(struct ata_queued_cmd *qc)
|
|
|
+{
|
|
|
+ struct ata_port *ap = qc->ap;
|
|
|
+ if (ap->flags & ATA_FLAG_MMIO) {
|
|
|
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
|
|
|
+
|
|
|
+ /* clear start/stop bit */
|
|
|
+ writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
|
|
|
+ mmio + ATA_DMA_CMD);
|
|
|
+ } else {
|
|
|
+ /* clear start/stop bit */
|
|
|
+ outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
|
|
|
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
|
|
|
+ ata_altstatus(ap); /* dummy read */
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_PCI
|
|
|
static struct ata_probe_ent *
|
|
|
ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
|