sata_sx4.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,500 行 · 第 1/3 页
C
1,500 行
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 *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; VPRINTK("ata%u: ENTER\n", ap->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_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_DEBUGstatic 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));}#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_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 port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->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, (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 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 *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)); /* get drive status; clear intr; complete txn */ ata_qc_complete(qc, ata_wait_idle(ap)); 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)); /* get drive status; clear intr; complete txn */ ata_qc_complete(qc, ata_wait_idle(ap)); 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); handled = 1; } else { ap->stats.idle_irq++; } return handled;}static void pdc20621_irq_clear(struct ata_port *ap){ struct ata_host_set *host_set = ap->host_set; void *mmio = host_set->mmio_base; mmio += PDC_CHIP0_OFS; readl(mmio + PDC_20621_SEQMASK);}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->tf.ctl & ATA_NIEN))) 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_eng_timeout(struct ata_port *ap){ u8 drv_stat; struct ata_queued_cmd *qc; DPRINTK("ENTER\n"); qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); goto out; } /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in * any kernel, so the default scsi_done() assumes it is * not being called from the SCSI EH. */ qc->scsidone = scsi_finish_command; switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: printk(KERN_ERR "ata%u: command timeout\n", ap->id); ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", ap->id, qc->tf.command, drv_stat); ata_qc_complete(qc, drv_stat); break; }out: DPRINTK("EXIT\n");}static void pdc_tf_load_mmio(struct ata_port *ap, 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, 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, unsigned long 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_probe_ent *pe, void *psource, u32 offset, u32 size){ u32 window_size; u16 idx; u8 page_mask; long dist; void *mmio = pe->mmio_base; struct pdc_host_priv *hpriv = pe->private_data; void *dimm_mmio = hpriv->dimm_mmio; /* 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); readl(mmio + PDC_DIMM_WINDOW_CTLR); memcpy_fromio((char *) psource, (char *) (dimm_mmio), window_size / 4); psource += window_size; size -= window_size; idx ++; } if (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); memcpy_fromio((char *) psource, (char *) (dimm_mmio), size / 4); }}#endifstatic void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size){ u32 window_size; u16 idx; u8 page_mask; long dist; void *mmio = pe->mmio_base; struct pdc_host_priv *hpriv = pe->private_data; void *dimm_mmio = hpriv->dimm_mmio; /* 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(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); offset -= (idx * window_size); idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?