From f4c7bac13f48fdd66618f70b5d523b4cbcdfce77 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 22 Oct 2003 10:06:28 -0400 Subject: [PATCH] [libata] more pdc20621 work --- drivers/scsi/sata_promise.c | 308 +++++++++++++++++++++++++++--------- 1 file changed, 230 insertions(+), 78 deletions(-) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index c7fb28a564e0a..6974fb3835d02 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -32,6 +32,9 @@ #include "scsi.h" #include "hosts.h" #include +#include + +#undef DIRECT_HDMA #define DRV_NAME "sata_promise" #define DRV_VERSION "0.84" @@ -50,12 +53,23 @@ enum { PDC_SLEW_CTL = 0x470, /* slew rate control reg */ PDC_20621_SEQCTL = 0x400, PDC_20621_SEQMASK = 0x480, + PDC_20621_PAGE_SIZE = (32 * 1024), /* chosen, not constant, values; we design our own DIMM mem map */ PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */ PDC_20621_DIMM_BASE = 0x00200000, - PDC_20621_HOST_PRD = 64, - PDC_20621_ATA_PRD = 72, + PDC_20621_DIMM_DATA = (64 * 1024), + PDC_DIMM_DATA_STEP = (256 * 1024), + PDC_DIMM_WINDOW_STEP = (8 * 1024), + PDC_DIMM_HOST_PRD = (6 * 1024), + PDC_DIMM_HOST_PKT = (128 * 0), + PDC_DIMM_HPKT_PRD = (128 * 1), + PDC_DIMM_ATA_PKT = (128 * 2), + PDC_DIMM_APKT_PRD = (128 * 3), + PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128, + PDC_PAGE_DATA = 0x40 + + (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE), + PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE, PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */ @@ -68,8 +82,7 @@ enum { struct pdc_port_priv { - u8 prd_buf[ATA_PRD_SZ * ATA_MAX_PRD]; - u8 pkt_buf[256]; + u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512]; u8 *pkt; dma_addr_t pkt_dma; }; @@ -429,39 +442,64 @@ static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsi return i; } -static inline unsigned int pdc20621_pkt_header(struct ata_taskfile *tf, - unsigned int portno, - unsigned int devno, - u8 *buf, - unsigned int total_len) +static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf, + unsigned int portno, + unsigned int total_len) { - u8 dev_reg; + u32 addr; + unsigned int dw = PDC_DIMM_APKT_PRD >> 2; u32 *buf32 = (u32 *) buf; - unsigned int ofs, i = 0; - /* - * Set up Host DMA packet - */ - if (tf->protocol == ATA_PROT_DMA_READ) - buf[i++] = PDC20621_PKT_READ; - else - buf[i++] = 0; - buf[i++] = 0; /* reserved */ - buf[i++] = portno + 1 + 4; /* seq. id */ - buf[i++] = 0xff; /* delay seq. id */ - buf32[i / 4] = cpu_to_le32(PDC_20621_DIMM_BASE + (4 * 1024) + - (2 * 1024 * portno)); - i += 4; - buf32[i / 4] = cpu_to_le32(PDC_20621_DIMM_BASE + (portno * 1024) + - PDC_20621_HOST_PRD); - i += 4; - buf32[i / 4] = 0; - i += 4; - - ofs = PDC_20621_HOST_PRD / 4; - buf32[ofs] = cpu_to_le32(PDC_20621_DIMM_BASE + (32 * 1024) + - (256 * 1024 * portno)); - buf32[ofs + 1] = cpu_to_le32(total_len | ATA_PRD_EOT); + /* 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 @@ -475,16 +513,12 @@ static inline unsigned int pdc20621_pkt_header(struct ata_taskfile *tf, buf[i++] = 0; /* reserved */ buf[i++] = portno + 1; /* seq. id */ buf[i++] = 0xff; /* delay seq. id */ - buf32[i / 4] = cpu_to_le32(PDC_20621_DIMM_BASE + (portno * 1024) + - PDC_20621_ATA_PRD); - i += 4; - buf32[i / 4] = 0; /* no next-packet */ - i += 4; - ofs = PDC_20621_ATA_PRD / 4; - buf32[ofs] = cpu_to_le32(PDC_20621_DIMM_BASE + (32 * 1024) + - (256 * 1024 * portno)); - buf32[ofs + 1] = cpu_to_le32(total_len | ATA_PRD_EOT); + /* 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; @@ -499,7 +533,46 @@ static inline unsigned int pdc20621_pkt_header(struct ata_taskfile *tf, buf[i++] = (1 << 5) | PDC_REG_DEVCTL; buf[i++] = tf->ctl; - return i; /* offset of next byte */ + 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_READ) + tmp = PDC20621_PKT_READ; + else + tmp = 0; + tmp |= ((portno + 1 + 4) << 16); + 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) @@ -509,9 +582,10 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc) struct pdc_port_priv *pp = ap->private_data; void *dimm_mmio = ap->host_set->private_data; unsigned int portno = ap->port_no; - unsigned int i, last, idx, total_len = 0; - u32 *buf = (u32 *) &pp->prd_buf; + 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); /* * Build S/G table */ @@ -522,28 +596,66 @@ static void pdc20621_fill_sg(struct ata_queued_cmd *qc) buf[idx++] = cpu_to_le32(sg[i].length); total_len += sg[i].length; } - idx--; - buf[idx] |= cpu_to_le32(ATA_PRD_EOT); + buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT); + sgt_len = idx * 4; /* * Build ATA, host DMA packets */ - i = pdc20621_pkt_header(&qc->tf, portno, qc->dev->devno, - &pp->pkt_buf[0], total_len); + 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->pkt_buf[0], i); + i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i); else - i = pdc_prep_lba28(&qc->tf, &pp->pkt_buf[0], i); + i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i); - i = pdc_pkt_footer(&qc->tf, &pp->pkt_buf[0], i); + pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i); - /* copy two packets and three S/G tables to DIMM MMIO window */ - memcpy_toio(dimm_mmio + (portno * 1024), &pp->pkt_buf, i); - memcpy_toio(dimm_mmio + (4 * 1024) + (2 * 1024 * portno), - buf, idx * 4); + /* 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 + sgt_len); + VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } +#ifdef DIRECT_HDMA +static void pdc20621_push_hdma(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->flags & ATA_QCFLAG_WRITE); + u32 tmp; + + unsigned int host_sg = PDC_20621_DIMM_BASE + + (PDC_DIMM_WINDOW_STEP * port_no) + + PDC_DIMM_HOST_PRD; + unsigned int dimm_sg = PDC_20621_DIMM_BASE + + (PDC_DIMM_WINDOW_STEP * port_no) + + PDC_DIMM_HPKT_PRD; + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + tmp = port_no + 1 + 4; + if (!rw) + tmp |= (1 << 6); + writel(tmp, mmio + 0x12C); + readl(mmio + 0x12C); /* flush */ + writel(host_sg, mmio + 0x108); + writel(dimm_sg, mmio + 0x10C); + writel(0, mmio + 0x128); + + tmp |= (1 << 7); + writel(tmp, mmio + 0x12C); + readl(mmio + 0x12C); /* flush */ +} +#endif + static void pdc20621_dma_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -552,32 +664,44 @@ static void pdc20621_dma_start(struct ata_queued_cmd *qc) void *mmio = host_set->mmio_base; unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE); u8 seq = (u8) (port_no + 1); - u32 pkt_addr; - unsigned int doing_hdma = 0; + unsigned int doing_hdma = 0, port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - VPRINTK("ENTER, ap %p, mmio %p\n", ap, mmio); + 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; - pkt_addr = PDC_20621_DIMM_BASE + (4 * port_no); - } - - /* if reading, we (1) do ATA command, then (2) DMA from DIMM */ - else { - pkt_addr = PDC_20621_DIMM_BASE + (4 * port_no) + 16; } wmb(); /* flush PRD, pkt writes */ + writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); - if (doing_hdma) - writel(pkt_addr, mmio + PDC_HDMA_PKT_SUBMIT); - else - writel(pkt_addr, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + + if (doing_hdma) { +#ifdef DIRECT_HDMA + pdc20621_push_hdma(qc); +#else + writel(port_ofs + PDC_DIMM_HOST_PKT, + mmio + PDC_HDMA_PKT_SUBMIT); +#endif + VPRINTK("submitted ofs 0x%x (%u), seq %u\n", + port_ofs + PDC_DIMM_HOST_PKT, + port_ofs + PDC_DIMM_HOST_PKT, + seq); + } else { + writel(port_ofs + PDC_DIMM_ATA_PKT, + (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, @@ -586,23 +710,36 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, 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"); + switch (qc->tf.protocol) { case ATA_PROT_DMA_READ: /* step two - DMA from DIMM to host */ - if (doing_hdma) + if (doing_hdma) { + VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, + readl(mmio + 0x104), readl(mmio + 0x12c)); pdc_dma_complete(ap, qc); + } /* step one - exec ATA command */ else { - u32 pkt_addr = PDC_20621_DIMM_BASE + (4 * port_no); + VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id, + readl(mmio + 0x104), readl(mmio + 0x12c)); u8 seq = (u8) (port_no + 1 + 4); /* submit hdma pkt */ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); - writel(pkt_addr, mmio + PDC_HDMA_PKT_SUBMIT); +#ifdef DIRECT_HDMA + pdc20621_push_hdma(qc); +#else + writel(port_ofs + PDC_DIMM_HOST_PKT, + mmio + PDC_HDMA_PKT_SUBMIT); +#endif } handled = 1; break; @@ -610,16 +747,22 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, case ATA_PROT_DMA_WRITE: /* step one - DMA from host to DIMM */ if (doing_hdma) { - u32 pkt_addr = PDC_20621_DIMM_BASE + (4 * port_no) + 16; + VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id, + readl(mmio + 0x104), readl(mmio + 0x12c)); u8 seq = (u8) (port_no + 1); /* submit ata pkt */ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); - writel(pkt_addr, (void *) - ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + writel(port_ofs + PDC_DIMM_ATA_PKT, + (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + } + /* step two - execute ATA command */ - } else + else { + VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, + readl(mmio + 0x104), readl(mmio + 0x12c)); pdc_dma_complete(ap, qc); + } handled = 1; break; @@ -659,6 +802,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re /* 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"); @@ -673,7 +817,6 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re spin_lock_irq(&host_set->lock); for (i = 1; i < 9; i++) { - VPRINTK("port %u\n", port_no); port_no = i - 1; if (port_no > 3) port_no -= 4; @@ -682,6 +825,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re 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; @@ -694,6 +838,8 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re spin_unlock_irq(&host_set->lock); + VPRINTK("mask == 0x%x\n", mask); + VPRINTK("EXIT\n"); return IRQ_RETVAL(handled); @@ -704,6 +850,8 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc) struct pdc_port_priv *pp = qc->ap->private_data; unsigned int i; + VPRINTK("ENTER\n"); + ata_fill_sg(qc); i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); @@ -906,6 +1054,10 @@ static void pdc_20621_init(struct ata_probe_ent *pe) tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000; tmp |= 0x40; /* page 40h; arbitrarily selected */ writel(tmp, mmio + PDC_20621_DIMM_WINDOW); + + writel( (1 << 11), mmio + 0x12C); + udelay(10); + writel(0, mmio + 0x12C); } static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) -- 2.53.0