-enum pdc_packet_bits {
- PDC_PKT_READ = (1 << 2),
- PDC_PKT_NODATA = (1 << 3),
-
- PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
- PDC_PKT_CLEAR_BSY = (1 << 4),
- PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
- PDC_LAST_REG = (1 << 3),
-
- PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
-};
-
-static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
- dma_addr_t sg_table,
- unsigned int devno, u8 *buf)
-{
- u8 dev_reg;
- u32 *buf32 = (u32 *) buf;
-
- /* set control bits (byte 0), zero delay seq id (byte 3),
- * and seq id (byte 2)
- */
- switch (tf->protocol) {
- case ATA_PROT_DMA:
- if (!(tf->flags & ATA_TFLAG_WRITE))
- buf32[0] = cpu_to_le32(PDC_PKT_READ);
- else
- buf32[0] = 0;
- break;
-
- case ATA_PROT_NODATA:
- buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
- break;
-
- default:
- BUG();
- break;
- }
-
- buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
- buf32[2] = 0; /* no next-packet */
-
- if (devno == 0)
- dev_reg = ATA_DEVICE_OBS;
- else
- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
- /* select device */
- buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
- buf[13] = dev_reg;
-
- /* device control register */
- buf[14] = (1 << 5) | PDC_REG_DEVCTL;
- buf[15] = tf->ctl;
-
- return 16; /* offset of next byte */
-}
-
-static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
- unsigned int i)
-{
- if (tf->flags & ATA_TFLAG_DEVICE) {
- buf[i++] = (1 << 5) | ATA_REG_DEVICE;
- buf[i++] = tf->device;
- }
-
- /* and finally the command itself; also includes end-of-pkt marker */
- buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
- buf[i++] = tf->command;
-
- return i;
-}
-
-static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
- /* the "(1 << 5)" should be read "(count << 5)" */
-
- /* ATA command block registers */
- buf[i++] = (1 << 5) | ATA_REG_FEATURE;
- buf[i++] = tf->feature;
-
- buf[i++] = (1 << 5) | ATA_REG_NSECT;
- buf[i++] = tf->nsect;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAL;
- buf[i++] = tf->lbal;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAM;
- buf[i++] = tf->lbam;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAH;
- buf[i++] = tf->lbah;
-
- return i;
-}
-
-static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
- /* the "(2 << 5)" should be read "(count << 5)" */
-
- /* ATA command block registers */
- buf[i++] = (2 << 5) | ATA_REG_FEATURE;
- buf[i++] = tf->hob_feature;
- buf[i++] = tf->feature;
-
- buf[i++] = (2 << 5) | ATA_REG_NSECT;
- buf[i++] = tf->hob_nsect;
- buf[i++] = tf->nsect;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAL;
- buf[i++] = tf->hob_lbal;
- buf[i++] = tf->lbal;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAM;
- buf[i++] = tf->hob_lbam;
- buf[i++] = tf->lbam;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAH;
- buf[i++] = tf->hob_lbah;
- buf[i++] = tf->lbah;
-
- return i;
-}
-
-static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
-{
- u32 addr;
- unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
- u32 *buf32 = (u32 *) buf;
-
- /* output ATA packet S/G table */
- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
- (PDC_DIMM_DATA_STEP * portno);
- VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
- buf32[dw] = cpu_to_le32(addr);
- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
- VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
- PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_APKT_PRD,
- buf32[dw], buf32[dw + 1]);
-}
-
-static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
-{
- u32 addr;
- unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
- u32 *buf32 = (u32 *) buf;
-
- /* output Host DMA packet S/G table */
- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
- (PDC_DIMM_DATA_STEP * portno);
-
- buf32[dw] = cpu_to_le32(addr);
- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
- VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
- PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HPKT_PRD,
- buf32[dw], buf32[dw + 1]);
-}
-
-static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
- unsigned int devno, u8 *buf,
- unsigned int portno)
-{
- unsigned int i, dw;
- u32 *buf32 = (u32 *) buf;
- u8 dev_reg;
-
- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_APKT_PRD;
- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
-
- i = PDC_DIMM_ATA_PKT;
-
- /*
- * Set up ATA packet
- */
- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
- buf[i++] = PDC_PKT_READ;
- else if (tf->protocol == ATA_PROT_NODATA)
- buf[i++] = PDC_PKT_NODATA;
- else
- buf[i++] = 0;
- buf[i++] = 0; /* reserved */
- buf[i++] = portno + 1; /* seq. id */
- buf[i++] = 0xff; /* delay seq. id */
-
- /* dimm dma S/G, and next-pkt */
- dw = i >> 2;
- buf32[dw] = cpu_to_le32(dimm_sg);
- buf32[dw + 1] = 0;
- i += 8;
-
- if (devno == 0)
- dev_reg = ATA_DEVICE_OBS;
- else
- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
- /* select device */
- buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
- buf[i++] = dev_reg;
-
- /* device control register */
- buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
- buf[i++] = tf->ctl;
-
- return i;
-}
-
-static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno)
-{
- unsigned int dw;
- u32 tmp, *buf32 = (u32 *) buf;
-
- unsigned int host_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HOST_PRD;
- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HPKT_PRD;
- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
- VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
-
- dw = PDC_DIMM_HOST_PKT >> 2;
-
- /*
- * Set up Host DMA packet
- */
- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
- tmp = PDC_PKT_READ;
- else
- tmp = 0;
- tmp |= ((portno + 1 + 4) << 16); /* seq. id */
- tmp |= (0xff << 24); /* delay seq. id */
- buf32[dw + 0] = cpu_to_le32(tmp);
- buf32[dw + 1] = cpu_to_le32(host_sg);
- buf32[dw + 2] = cpu_to_le32(dimm_sg);
- buf32[dw + 3] = 0;
-
- VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HOST_PKT,
- buf32[dw + 0],
- buf32[dw + 1],
- buf32[dw + 2],
- buf32[dw + 3]);
-}
-
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
-{
- struct scatterlist *sg = qc->sg;
- struct ata_port *ap = qc->ap;
- struct pdc_port_priv *pp = ap->private_data;
- void *mmio = ap->host_set->mmio_base;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
- unsigned int portno = ap->port_no;
- unsigned int i, last, idx, total_len = 0, sgt_len;
- u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- * Build S/G table
- */
- last = qc->n_elem;
- idx = 0;
- for (i = 0; i < last; i++) {
- buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
- buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
- total_len += sg[i].length;
- }
- buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
- sgt_len = idx * 4;
-
- /*
- * Build ATA, host DMA packets
- */
- pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
- pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
-
- pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
- i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
-
- if (qc->tf.flags & ATA_TFLAG_LBA48)
- i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
- else
- i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
-
- pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
-
- /* copy three S/G tables and two packets to DIMM MMIO window */
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
- &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
- PDC_DIMM_HOST_PRD,
- &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
-
- /* force host FIFO dump */
- writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
-
- readl(dimm_mmio); /* MMIO PCI posting flush */
-
- VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
-}
-
-static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
- unsigned int seq,
- u32 pkt_ofs)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- void *mmio = host_set->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
-
- writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
- readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
-}
-
-static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
- unsigned int seq,
- u32 pkt_ofs)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
- unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
-
- if (!pp->doing_hdma) {
- __pdc20621_push_hdma(qc, seq, pkt_ofs);
- pp->doing_hdma = 1;
- return;
- }
-
- pp->hdma[idx].qc = qc;
- pp->hdma[idx].seq = seq;
- pp->hdma[idx].pkt_ofs = pkt_ofs;
- pp->hdma_prod++;
-}
-
-static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
- unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
-
- /* if nothing on queue, we're done */
- if (pp->hdma_prod == pp->hdma_cons) {
- pp->doing_hdma = 0;
- return;
- }
-
- __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
- pp->hdma[idx].pkt_ofs);
- pp->hdma_cons++;
-}
-
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int port_no = ap->port_no;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
-
- dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
- dimm_mmio += PDC_DIMM_HOST_PKT;
-
- printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
- printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
- printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
- printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
-}
-#else
-static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
-#endif /* ATA_VERBOSE_DEBUG */
-
-static void pdc20621_dma_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- unsigned int port_no = ap->port_no;
- void *mmio = host_set->mmio_base;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 seq = (u8) (port_no + 1);
- unsigned int doing_hdma = 0, port_ofs;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
-
- /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
- if (rw) {
- doing_hdma = 1;
- seq += 4;
- }
-
- wmb(); /* flush PRD, pkt writes */
-
- if (doing_hdma) {
- pdc20621_dump_hdma(qc);
- pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
- VPRINTK("queued ofs 0x%x (%u), seq %u\n",
- port_ofs + PDC_DIMM_HOST_PKT,
- port_ofs + PDC_DIMM_HOST_PKT,
- seq);
- } else {
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
-
- writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
- port_ofs + PDC_DIMM_ATA_PKT,
- port_ofs + PDC_DIMM_ATA_PKT,
- seq);
- }
-}
-
-static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
- struct ata_queued_cmd *qc,
- unsigned int doing_hdma,
- void *mmio)
-{
- unsigned int port_no = ap->port_no;
- unsigned int port_ofs =
- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
- u8 status;
- unsigned int handled = 0;
-
- VPRINTK("ENTER\n");
-
- if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
- (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
-
- /* step two - DMA from DIMM to host */
- if (doing_hdma) {
- VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
- pdc_dma_complete(ap, qc, 0);
- pdc20621_pop_hdma(qc);
- }
-
- /* step one - exec ATA command */
- else {
- u8 seq = (u8) (port_no + 1 + 4);
- VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
- /* submit hdma pkt */
- pdc20621_dump_hdma(qc);
- pdc20621_push_hdma(qc, seq,
- port_ofs + PDC_DIMM_HOST_PKT);
- }
- handled = 1;
-
- } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
-
- /* step one - DMA from host to DIMM */
- if (doing_hdma) {
- u8 seq = (u8) (port_no + 1);
- VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
- /* submit ata pkt */
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4));
- writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- }
-
- /* step two - execute ATA command */
- else {
- VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
- pdc_dma_complete(ap, qc, 0);
- pdc20621_pop_hdma(qc);
- }
- handled = 1;
-
- /* command completion, but no data xfer */
- } else if (qc->tf.protocol == ATA_PROT_NODATA) {
-
- status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
- DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
- ata_qc_complete(qc, status, 0);
- handled = 1;
-
- } else {
- ap->stats.idle_irq++;
- }
-
- return handled;
-}
-
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- struct ata_port *ap;
- u32 mask = 0;
- unsigned int i, tmp, port_no;
- unsigned int handled = 0;
- void *mmio_base;
-
- VPRINTK("ENTER\n");
-
- if (!host_set || !host_set->mmio_base) {
- VPRINTK("QUICK EXIT\n");
- return IRQ_NONE;
- }
-
- mmio_base = host_set->mmio_base;
-
- /* reading should also clear interrupts */
- mmio_base += PDC_CHIP0_OFS;
- mask = readl(mmio_base + PDC_20621_SEQMASK);
- VPRINTK("mask == 0x%x\n", mask);
-
- if (mask == 0xffffffff) {
- VPRINTK("QUICK EXIT 2\n");
- return IRQ_NONE;
- }
- mask &= 0xffff; /* only 16 tags possible */
- if (!mask) {
- VPRINTK("QUICK EXIT 3\n");
- return IRQ_NONE;
- }
-
- spin_lock(&host_set->lock);
-
- for (i = 1; i < 9; i++) {
- port_no = i - 1;
- if (port_no > 3)
- port_no -= 4;
- if (port_no >= host_set->n_ports)
- ap = NULL;
- else
- ap = host_set->ports[port_no];
- tmp = mask & (1 << i);
- VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
- if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
- handled += pdc20621_host_intr(ap, qc, (i > 4),
- mmio_base);
- }
- }
-
- spin_unlock(&host_set->lock);
-
- VPRINTK("mask == 0x%x\n", mask);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static void pdc_fill_sg(struct ata_queued_cmd *qc)