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

📄 sata_nv.c

📁 LINUX 系统内如 清大家快去下载 这2个把 破 东西 要下载 还的上传 估计来的会很少清管理 考虑从
💻 C
📖 第 1 页 / 共 4 页
字号:
{	void __iomem *mmio = nv_adma_ctl_block(ap);	u16 status = readw(mmio + NV_ADMA_STAT);	u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);	u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);	unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;	/* clear ADMA status */	writew(status, mmio + NV_ADMA_STAT);	writel(notifier | notifier_error,	       nv_adma_notifier_clear_block(ap));	/** clear legacy status */	outb(inb(dma_stat_addr), dma_stat_addr);}static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);	struct nv_adma_port_priv *pp = ap->private_data;	u8 dmactl;	if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {		WARN_ON(1);		return;	}	/* load PRD table addr. */	outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);	/* specify data direction, triple-check start bit is clear */	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);	if (!rw)		dmactl |= ATA_DMA_WR;	outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);	/* issue r/w command */	ata_exec_command(ap, &qc->tf);}static void nv_adma_bmdma_start(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct nv_adma_port_priv *pp = ap->private_data;	u8 dmactl;	if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {		WARN_ON(1);		return;	}	/* start host DMA transaction */	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);	outb(dmactl | ATA_DMA_START,	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);}static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct nv_adma_port_priv *pp = ap->private_data;	if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))		return;	/* clear start/stop bit */	outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,		ap->ioaddr.bmdma_addr + ATA_DMA_CMD);	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */	ata_altstatus(ap);        /* dummy read */}static u8 nv_adma_bmdma_status(struct ata_port *ap){	struct nv_adma_port_priv *pp = ap->private_data;	WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE));	return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);}static int nv_adma_port_start(struct ata_port *ap){	struct device *dev = ap->host->dev;	struct nv_adma_port_priv *pp;	int rc;	void *mem;	dma_addr_t mem_dma;	void __iomem *mmio = nv_adma_ctl_block(ap);	u16 tmp;	VPRINTK("ENTER\n");	rc = ata_port_start(ap);	if (rc)		return rc;	pp = kzalloc(sizeof(*pp), GFP_KERNEL);	if (!pp) {		rc = -ENOMEM;		goto err_out;	}	mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,				 &mem_dma, GFP_KERNEL);	if (!mem) {		rc = -ENOMEM;		goto err_out_kfree;	}	memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ);	/*	 * First item in chunk of DMA memory:	 * 128-byte command parameter block (CPB)	 * one for each command tag	 */	pp->cpb     = mem;	pp->cpb_dma = mem_dma;	writel(mem_dma & 0xFFFFFFFF, 	mmio + NV_ADMA_CPB_BASE_LOW);	writel((mem_dma >> 16 ) >> 16,	mmio + NV_ADMA_CPB_BASE_HIGH);	mem     += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ;	mem_dma += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ;	/*	 * Second item: block of ADMA_SGTBL_LEN s/g entries	 */	pp->aprd = mem;	pp->aprd_dma = mem_dma;	ap->private_data = pp;	/* clear any outstanding interrupt conditions */	writew(0xffff, mmio + NV_ADMA_STAT);	/* initialize port variables */	pp->flags = NV_ADMA_PORT_REGISTER_MODE;	/* clear CPB fetch count */	writew(0, mmio + NV_ADMA_CPB_COUNT);	/* clear GO for register mode */	tmp = readw(mmio + NV_ADMA_CTL);	writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);	tmp = readw(mmio + NV_ADMA_CTL);	writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);	readl( mmio + NV_ADMA_CTL );	/* flush posted write */	udelay(1);	writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);	readl( mmio + NV_ADMA_CTL );	/* flush posted write */	return 0;err_out_kfree:	kfree(pp);err_out:	ata_port_stop(ap);	return rc;}static void nv_adma_port_stop(struct ata_port *ap){	struct device *dev = ap->host->dev;	struct nv_adma_port_priv *pp = ap->private_data;	void __iomem *mmio = nv_adma_ctl_block(ap);	VPRINTK("ENTER\n");	writew(0, mmio + NV_ADMA_CTL);	ap->private_data = NULL;	dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma);	kfree(pp);	ata_port_stop(ap);}static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port){	void __iomem *mmio = probe_ent->mmio_base;	struct ata_ioports *ioport = &probe_ent->port[port];	VPRINTK("ENTER\n");	mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;	ioport->cmd_addr	= (unsigned long) mmio;	ioport->data_addr	= (unsigned long) mmio + (ATA_REG_DATA * 4);	ioport->error_addr	=	ioport->feature_addr	= (unsigned long) mmio + (ATA_REG_ERR * 4);	ioport->nsect_addr	= (unsigned long) mmio + (ATA_REG_NSECT * 4);	ioport->lbal_addr	= (unsigned long) mmio + (ATA_REG_LBAL * 4);	ioport->lbam_addr	= (unsigned long) mmio + (ATA_REG_LBAM * 4);	ioport->lbah_addr	= (unsigned long) mmio + (ATA_REG_LBAH * 4);	ioport->device_addr	= (unsigned long) mmio + (ATA_REG_DEVICE * 4);	ioport->status_addr	=	ioport->command_addr	= (unsigned long) mmio + (ATA_REG_STATUS * 4);	ioport->altstatus_addr	=	ioport->ctl_addr	= (unsigned long) mmio + 0x20;}static int nv_adma_host_init(struct ata_probe_ent *probe_ent){	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);	unsigned int i;	u32 tmp32;	VPRINTK("ENTER\n");	/* enable ADMA on the ports */	pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);	tmp32 |= NV_MCP_SATA_CFG_20_PORT0_EN |		 NV_MCP_SATA_CFG_20_PORT0_PWB_EN |		 NV_MCP_SATA_CFG_20_PORT1_EN |		 NV_MCP_SATA_CFG_20_PORT1_PWB_EN;	pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);	for (i = 0; i < probe_ent->n_ports; i++)		nv_adma_setup_port(probe_ent, i);	for (i = 0; i < probe_ent->n_ports; i++) {		void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i);		u16 tmp;		/* enable interrupt, clear reset if not already clear */		tmp = readw(mmio + NV_ADMA_CTL);		writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);	}	return 0;}static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,			      struct scatterlist *sg,			      int idx,			      struct nv_adma_prd *aprd){	u8 flags;	memset(aprd, 0, sizeof(struct nv_adma_prd));	flags = 0;	if (qc->tf.flags & ATA_TFLAG_WRITE)		flags |= NV_APRD_WRITE;	if (idx == qc->n_elem - 1)		flags |= NV_APRD_END;	else if (idx != 4)		flags |= NV_APRD_CONT;	aprd->addr  = cpu_to_le64(((u64)sg_dma_address(sg)));	aprd->len   = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */	aprd->flags = flags;}static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb){	struct nv_adma_port_priv *pp = qc->ap->private_data;	unsigned int idx;	struct nv_adma_prd *aprd;	struct scatterlist *sg;	VPRINTK("ENTER\n");	idx = 0;	ata_for_each_sg(sg, qc) {		aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];		nv_adma_fill_aprd(qc, sg, idx, aprd);		idx++;	}	if (idx > 5)		cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));}static void nv_adma_qc_prep(struct ata_queued_cmd *qc){	struct nv_adma_port_priv *pp = qc->ap->private_data;	struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];	u8 ctl_flags = NV_CPB_CTL_CPB_VALID |		       NV_CPB_CTL_APRD_VALID |		       NV_CPB_CTL_IEN;	VPRINTK("qc->flags = 0x%lx\n", qc->flags);	if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||	     (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {		nv_adma_register_mode(qc->ap);		ata_qc_prep(qc);		return;	}	memset(cpb, 0, sizeof(struct nv_adma_cpb));	cpb->len		= 3;	cpb->tag		= qc->tag;	cpb->next_cpb_idx	= 0;	/* turn on NCQ flags for NCQ commands */	if (qc->tf.protocol == ATA_PROT_NCQ)		ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA;	nv_adma_tf_to_cpb(&qc->tf, cpb->tf);	nv_adma_fill_sg(qc, cpb);	/* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are	   finished filling in all of the contents */	wmb();	cpb->ctl_flags = ctl_flags;}static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc){	struct nv_adma_port_priv *pp = qc->ap->private_data;	void __iomem *mmio = nv_adma_ctl_block(qc->ap);	VPRINTK("ENTER\n");	if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||	     (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {		/* use ATA register mode */		VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags);		nv_adma_register_mode(qc->ap);		return ata_qc_issue_prot(qc);	} else		nv_adma_mode(qc->ap);	/* write append register, command tag in lower 8 bits	   and (number of cpbs to append -1) in top 8 bits */	wmb();	writew(qc->tag, mmio + NV_ADMA_APPEND);	DPRINTK("Issued tag %u\n",qc->tag);	return 0;}static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance, struct pt_regs *pt_regs){	struct ata_host *host = dev_instance;	unsigned int i;	unsigned int handled = 0;	unsigned long flags;	spin_lock_irqsave(&host->lock, flags);	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap;		ap = host->ports[i];		if (ap &&		    !(ap->flags & ATA_FLAG_DISABLED)) {			struct ata_queued_cmd *qc;			qc = ata_qc_from_tag(ap, ap->active_tag);			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))				handled += ata_host_intr(ap, qc);			else				// No request pending?  Clear interrupt status				// anyway, in case there's one pending.				ap->ops->check_status(ap);		}	}	spin_unlock_irqrestore(&host->lock, flags);	return IRQ_RETVAL(handled);}static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat){	int i, handled = 0;	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap = host->ports[i];		if (ap && !(ap->flags & ATA_FLAG_DISABLED))			handled += nv_host_intr(ap, irq_stat);		irq_stat >>= NV_INT_PORT_SHIFT;	}	return IRQ_RETVAL(handled);}static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, struct pt_regs *pt_regs){	struct ata_host *host = dev_instance;	u8 irq_stat;	irqreturn_t ret;	spin_lock(&host->lock);	irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);	ret = nv_do_interrupt(host, irq_stat);	spin_unlock(&host->lock);	return ret;}static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, struct pt_regs *pt_regs){	struct ata_host *host = dev_instance;	u8 irq_stat;	irqreturn_t ret;	spin_lock(&host->lock);	irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804);	ret = nv_do_interrupt(host, irq_stat);	spin_unlock(&host->lock);	return ret;}static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg){	if (sc_reg > SCR_CONTROL)		return 0xffffffffU;	return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));}static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val){	if (sc_reg > SCR_CONTROL)		return;	iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));}static void nv_nf2_freeze(struct ata_port *ap){	unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;	int shift = ap->port_no * NV_INT_PORT_SHIFT;	u8 mask;	mask = inb(scr_addr + NV_INT_ENABLE);	mask &= ~(NV_INT_ALL << shift);	outb(mask, scr_addr + NV_INT_ENABLE);}static void nv_nf2_thaw(struct ata_port *ap){	unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;	int shift = ap->port_no * NV_INT_PORT_SHIFT;	u8 mask;	outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);	mask = inb(scr_addr + NV_INT_ENABLE);	mask |= (NV_INT_MASK << shift);	outb(mask, scr_addr + NV_INT_ENABLE);}static void nv_ck804_freeze(struct ata_port *ap){	void __iomem *mmio_base = ap->host->mmio_base;	int shift = ap->port_no * NV_INT_PORT_SHIFT;	u8 mask;	mask = readb(mmio_base + NV_INT_ENABLE_CK804);	mask &= ~(NV_INT_ALL << shift);	writeb(mask, mmio_base + NV_INT_ENABLE_CK804);}static void nv_ck804_thaw(struct ata_port *ap){	void __iomem *mmio_base = ap->host->mmio_base;	int shift = ap->port_no * NV_INT_PORT_SHIFT;	u8 mask;	writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804);	mask = readb(mmio_base + NV_INT_ENABLE_CK804);	mask |= (NV_INT_MASK << shift);	writeb(mask, mmio_base + NV_INT_ENABLE_CK804);}static int nv_hardreset(struct ata_port *ap, unsigned int *class){	unsigned int dummy;	/* SATA hardreset fails to retrieve proper device signature on	 * some controllers.  Don't classify on hardreset.  For more	 * info, see http://bugme.osdl.org/show_bug.cgi?id=3352	 */	return sata_std_hardreset(ap, &dummy);}static void nv_error_handler(struct ata_port *ap){	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,			   nv_hardreset, ata_std_postreset);}static void nv_adma_error_handler(struct ata_port *ap){	struct nv_adma_port_priv *pp = ap->private_data;	if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {		void __iomem *mmio = nv_adma_ctl_block(ap);		int i;		u16 tmp;		u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);		u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);		u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);		u32 status = readw(mmio + NV_ADMA_STAT);		ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "			"notifier_error 0x%X gen_ctl 0x%X status 0x%X\n",			notifier, notifier_error, gen_ctl, status);		for( i=0;i<NV_ADMA_MAX_CPBS;i++) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -