⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sata_sx4.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -