📄 sata_sx4.c
字号:
idx = 0; ata_for_each_sg(sg, qc) { buf[idx++] = cpu_to_le32(sg_dma_address(sg)); buf[idx++] = cpu_to_le32(sg_dma_len(sg)); total_len += sg_dma_len(sg); } 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_nodata_prep(struct ata_queued_cmd *qc){ struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; unsigned int i; VPRINTK("ata%u: ENTER\n", ap->print_id); /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; 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); /* force host FIFO dump */ writel(0x00000001, mmio + PDC_20621_GENERAL_CTL); readl(dimm_mmio); /* MMIO PCI posting flush */ VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);}static void pdc20621_qc_prep(struct ata_queued_cmd *qc){ switch (qc->tf.protocol) { case ATA_PROT_DMA: pdc20621_dma_prep(qc); break; case ATA_PROT_NODATA: pdc20621_nodata_prep(qc); break; default: break; }}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 *host = ap->host; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; /* 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->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->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_DEBUGstatic void pdc20621_dump_hdma(struct ata_queued_cmd *qc){ struct ata_port *ap = qc->ap; unsigned int port_no = ap->port_no; void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; 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));}#elsestatic inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }#endif /* ATA_VERBOSE_DEBUG */static void pdc20621_packet_start(struct ata_queued_cmd *qc){ struct ata_port *ap = qc->ap; struct ata_host *host = ap->host; unsigned int port_no = ap->port_no; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); unsigned int port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->print_id); wmb(); /* flush PRD, pkt writes */ 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 && qc->tf.protocol == ATA_PROT_DMA) { seq += 4; 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, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); readl(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 unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc){ switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: pdc20621_packet_start(qc); return 0; case ATA_PROT_ATAPI_DMA: BUG(); break; default: break; } return ata_qc_issue_prot(qc);}static inline unsigned int pdc20621_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, void __iomem *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->print_id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); ata_qc_complete(qc); 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->print_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->print_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, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ else { VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->print_id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); ata_qc_complete(qc); 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); qc->err_mask |= ac_err_mask(status); ata_qc_complete(qc); handled = 1; } else { ap->stats.idle_irq++; } return handled;}static void pdc20621_irq_clear(struct ata_port *ap){ struct ata_host *host = ap->host; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; mmio += PDC_CHIP0_OFS; readl(mmio + PDC_20621_SEQMASK);}static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance){ struct ata_host *host = dev_instance; struct ata_port *ap; u32 mask = 0; unsigned int i, tmp, port_no; unsigned int handled = 0; void __iomem *mmio_base; VPRINTK("ENTER\n"); if (!host || !host->iomap[PDC_MMIO_BAR]) { VPRINTK("QUICK EXIT\n"); return IRQ_NONE; } mmio_base = host->iomap[PDC_MMIO_BAR]; /* 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->lock); for (i = 1; i < 9; i++) { port_no = i - 1; if (port_no > 3) port_no -= 4; if (port_no >= host->n_ports) ap = NULL; else ap = host->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_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc20621_host_intr(ap, qc, (i > 4), mmio_base); } } spin_unlock(&host->lock); VPRINTK("mask == 0x%x\n", mask); VPRINTK("EXIT\n"); return IRQ_RETVAL(handled);}static void pdc_eng_timeout(struct ata_port *ap){ u8 drv_stat; struct ata_host *host = ap->host; struct ata_queued_cmd *qc; unsigned long flags; DPRINTK("ENTER\n"); spin_lock_irqsave(&host->lock, flags); qc = ata_qc_from_tag(ap, ap->link.active_tag); switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: ata_port_printk(ap, KERN_ERR, "command timeout\n"); qc->err_mask |= __ac_err_mask(ata_wait_idle(ap)); break; default: drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); ata_port_printk(ap, KERN_ERR, "unknown timeout, cmd 0x%x stat 0x%x\n", qc->tf.command, drv_stat); qc->err_mask |= ac_err_mask(drv_stat); break; } spin_unlock_irqrestore(&host->lock, flags); ata_eh_qc_complete(qc); DPRINTK("EXIT\n");}static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf){ WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); ata_tf_load(ap, tf);}static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf){ WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); ata_exec_command(ap, tf);}static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base){ port->cmd_addr = base; port->data_addr = base; port->feature_addr = port->error_addr = base + 0x4; port->nsect_addr = base + 0x8; port->lbal_addr = base + 0xc; port->lbam_addr = base + 0x10; port->lbah_addr = base + 0x14; port->device_addr = base + 0x18; port->command_addr = port->status_addr = base + 0x1c; port->altstatus_addr = port->ctl_addr = base + 0x38;}#ifdef ATA_VERBOSE_DEBUGstatic void pdc20621_get_from_dimm(struct ata_host *host, void *psource, u32 offset, u32 size){ u32 window_size; u16 idx; u8 page_mask; long dist; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; page_mask = 0x00; window_size = 0x2000 * 4; /* 32K byte uchar size */ idx = (u16) (offset / window_size); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); offset -= (idx * window_size); idx++; dist = ((long) (window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), dist); psource += dist; size -= dist; for (; (long) size >= (long) window_size ;) { writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -