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

📄 sata_sil24.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	void __iomem *port = dev->link->ap->ioaddr.cmd_addr;	if (dev->cdb_len == 16)		writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);	else		writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);}static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf){	void __iomem *port = ap->ioaddr.cmd_addr;	struct sil24_prb __iomem *prb;	u8 fis[6 * 4];	prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;	memcpy_fromio(fis, prb->fis, sizeof(fis));	ata_tf_from_fis(fis, tf);}static u8 sil24_check_status(struct ata_port *ap){	struct sil24_port_priv *pp = ap->private_data;	return pp->tf.command;}static int sil24_scr_map[] = {	[SCR_CONTROL]	= 0,	[SCR_STATUS]	= 1,	[SCR_ERROR]	= 2,	[SCR_ACTIVE]	= 3,};static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val){	void __iomem *scr_addr = ap->ioaddr.scr_addr;	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {		void __iomem *addr;		addr = scr_addr + sil24_scr_map[sc_reg] * 4;		*val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);		return 0;	}	return -EINVAL;}static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val){	void __iomem *scr_addr = ap->ioaddr.scr_addr;	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {		void __iomem *addr;		addr = scr_addr + sil24_scr_map[sc_reg] * 4;		writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);		return 0;	}	return -EINVAL;}static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf){	struct sil24_port_priv *pp = ap->private_data;	*tf = pp->tf;}static void sil24_config_port(struct ata_port *ap){	void __iomem *port = ap->ioaddr.cmd_addr;	/* configure IRQ WoC */	if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);	else		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);	/* zero error counters. */	writel(0x8000, port + PORT_DECODE_ERR_THRESH);	writel(0x8000, port + PORT_CRC_ERR_THRESH);	writel(0x8000, port + PORT_HSHK_ERR_THRESH);	writel(0x0000, port + PORT_DECODE_ERR_CNT);	writel(0x0000, port + PORT_CRC_ERR_CNT);	writel(0x0000, port + PORT_HSHK_ERR_CNT);	/* always use 64bit activation */	writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);	/* clear port multiplier enable and resume bits */	writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);}static void sil24_config_pmp(struct ata_port *ap, int attached){	void __iomem *port = ap->ioaddr.cmd_addr;	if (attached)		writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);	else		writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);}static void sil24_clear_pmp(struct ata_port *ap){	void __iomem *port = ap->ioaddr.cmd_addr;	int i;	writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);	for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {		void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;		writel(0, pmp_base + PORT_PMP_STATUS);		writel(0, pmp_base + PORT_PMP_QACTIVE);	}}static int sil24_init_port(struct ata_port *ap){	void __iomem *port = ap->ioaddr.cmd_addr;	struct sil24_port_priv *pp = ap->private_data;	u32 tmp;	/* clear PMP error status */	if (ap->nr_pmp_links)		sil24_clear_pmp(ap);	writel(PORT_CS_INIT, port + PORT_CTRL_STAT);	ata_wait_register(port + PORT_CTRL_STAT,			  PORT_CS_INIT, PORT_CS_INIT, 10, 100);	tmp = ata_wait_register(port + PORT_CTRL_STAT,				PORT_CS_RDY, 0, 10, 100);	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {		pp->do_port_rst = 1;		ap->link.eh_context.i.action |= ATA_EH_HARDRESET;		return -EIO;	}	return 0;}static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,				 const struct ata_taskfile *tf,				 int is_cmd, u32 ctrl,				 unsigned long timeout_msec){	void __iomem *port = ap->ioaddr.cmd_addr;	struct sil24_port_priv *pp = ap->private_data;	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;	dma_addr_t paddr = pp->cmd_block_dma;	u32 irq_enabled, irq_mask, irq_stat;	int rc;	prb->ctrl = cpu_to_le16(ctrl);	ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);	/* temporarily plug completion and error interrupts */	irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);	writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);	writel((u32)paddr, port + PORT_CMD_ACTIVATE);	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);	irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,				     10, timeout_msec);	writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */	irq_stat >>= PORT_IRQ_RAW_SHIFT;	if (irq_stat & PORT_IRQ_COMPLETE)		rc = 0;	else {		/* force port into known state */		sil24_init_port(ap);		if (irq_stat & PORT_IRQ_ERROR)			rc = -EIO;		else			rc = -EBUSY;	}	/* restore IRQ enabled */	writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);	return rc;}static int sil24_do_softreset(struct ata_link *link, unsigned int *class,			      int pmp, unsigned long deadline){	struct ata_port *ap = link->ap;	unsigned long timeout_msec = 0;	struct ata_taskfile tf;	const char *reason;	int rc;	DPRINTK("ENTER\n");	if (ata_link_offline(link)) {		DPRINTK("PHY reports no device\n");		*class = ATA_DEV_NONE;		goto out;	}	/* put the port into known state */	if (sil24_init_port(ap)) {		reason = "port not ready";		goto err;	}	/* do SRST */	if (time_after(deadline, jiffies))		timeout_msec = jiffies_to_msecs(deadline - jiffies);	ata_tf_init(link->device, &tf);	/* doesn't really matter */	rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,				   timeout_msec);	if (rc == -EBUSY) {		reason = "timeout";		goto err;	} else if (rc) {		reason = "SRST command error";		goto err;	}	sil24_read_tf(ap, 0, &tf);	*class = ata_dev_classify(&tf);	if (*class == ATA_DEV_UNKNOWN)		*class = ATA_DEV_NONE; out:	DPRINTK("EXIT, class=%u\n", *class);	return 0; err:	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);	return -EIO;}static int sil24_softreset(struct ata_link *link, unsigned int *class,			   unsigned long deadline){	return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);}static int sil24_hardreset(struct ata_link *link, unsigned int *class,			   unsigned long deadline){	struct ata_port *ap = link->ap;	void __iomem *port = ap->ioaddr.cmd_addr;	struct sil24_port_priv *pp = ap->private_data;	int did_port_rst = 0;	const char *reason;	int tout_msec, rc;	u32 tmp; retry:	/* Sometimes, DEV_RST is not enough to recover the controller.	 * This happens often after PM DMA CS errata.	 */	if (pp->do_port_rst) {		ata_port_printk(ap, KERN_WARNING, "controller in dubious "				"state, performing PORT_RST\n");		writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);		msleep(10);		writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);		ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,				  10, 5000);		/* restore port configuration */		sil24_config_port(ap);		sil24_config_pmp(ap, ap->nr_pmp_links);		pp->do_port_rst = 0;		did_port_rst = 1;	}	/* sil24 does the right thing(tm) without any protection */	sata_set_spd(link);	tout_msec = 100;	if (ata_link_online(link))		tout_msec = 5000;	writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);	tmp = ata_wait_register(port + PORT_CTRL_STAT,				PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10,				tout_msec);	/* SStatus oscillates between zero and valid status after	 * DEV_RST, debounce it.	 */	rc = sata_link_debounce(link, sata_deb_timing_long, deadline);	if (rc) {		reason = "PHY debouncing failed";		goto err;	}	if (tmp & PORT_CS_DEV_RST) {		if (ata_link_offline(link))			return 0;		reason = "link not ready";		goto err;	}	/* Sil24 doesn't store signature FIS after hardreset, so we	 * can't wait for BSY to clear.  Some devices take a long time	 * to get ready and those devices will choke if we don't wait	 * for BSY clearance here.  Tell libata to perform follow-up	 * softreset.	 */	return -EAGAIN; err:	if (!did_port_rst) {		pp->do_port_rst = 1;		goto retry;	}	ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);	return -EIO;}static inline void sil24_fill_sg(struct ata_queued_cmd *qc,				 struct sil24_sge *sge){	struct scatterlist *sg;	struct sil24_sge *last_sge = NULL;	ata_for_each_sg(sg, qc) {		sge->addr = cpu_to_le64(sg_dma_address(sg));		sge->cnt = cpu_to_le32(sg_dma_len(sg));		sge->flags = 0;		last_sge = sge;		sge++;	}	if (likely(last_sge))		last_sge->flags = cpu_to_le32(SGE_TRM);}static int sil24_qc_defer(struct ata_queued_cmd *qc){	struct ata_link *link = qc->dev->link;	struct ata_port *ap = link->ap;	u8 prot = qc->tf.protocol;	/*	 * There is a bug in the chip:	 * Port LRAM Causes the PRB/SGT Data to be Corrupted	 * If the host issues a read request for LRAM and SActive registers	 * while active commands are available in the port, PRB/SGT data in	 * the LRAM can become corrupted. This issue applies only when	 * reading from, but not writing to, the LRAM.	 *	 * Therefore, reading LRAM when there is no particular error [and	 * other commands may be outstanding] is prohibited.	 *	 * To avoid this bug there are two situations where a command must run	 * exclusive of any other commands on the port:	 *	 * - ATAPI commands which check the sense data	 * - Passthrough ATA commands which always have ATA_QCFLAG_RESULT_TF	 *   set.	 * 	 */	int is_excl = (prot == ATA_PROT_ATAPI ||		       prot == ATA_PROT_ATAPI_NODATA ||		       prot == ATA_PROT_ATAPI_DMA ||		       (qc->flags & ATA_QCFLAG_RESULT_TF));	if (unlikely(ap->excl_link)) {		if (link == ap->excl_link) {			if (ap->nr_active_links)				return ATA_DEFER_PORT;			qc->flags |= ATA_QCFLAG_CLEAR_EXCL;		} else			return ATA_DEFER_PORT;	} else if (unlikely(is_excl)) {		ap->excl_link = link;		if (ap->nr_active_links)			return ATA_DEFER_PORT;		qc->flags |= ATA_QCFLAG_CLEAR_EXCL;	}	return ata_std_qc_defer(qc);}static void sil24_qc_prep(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct sil24_port_priv *pp = ap->private_data;	union sil24_cmd_block *cb;	struct sil24_prb *prb;	struct sil24_sge *sge;	u16 ctrl = 0;	cb = &pp->cmd_block[sil24_tag(qc->tag)];	switch (qc->tf.protocol) {	case ATA_PROT_PIO:	case ATA_PROT_DMA:	case ATA_PROT_NCQ:	case ATA_PROT_NODATA:		prb = &cb->ata.prb;		sge = cb->ata.sge;		break;	case ATA_PROT_ATAPI:	case ATA_PROT_ATAPI_DMA:	case ATA_PROT_ATAPI_NODATA:		prb = &cb->atapi.prb;		sge = cb->atapi.sge;		memset(cb->atapi.cdb, 0, 32);		memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);		if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {			if (qc->tf.flags & ATA_TFLAG_WRITE)				ctrl = PRB_CTRL_PACKET_WRITE;			else				ctrl = PRB_CTRL_PACKET_READ;		}		break;	default:		prb = NULL;	/* shut up, gcc */		sge = NULL;		BUG();	}	prb->ctrl = cpu_to_le16(ctrl);	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);	if (qc->flags & ATA_QCFLAG_DMAMAP)		sil24_fill_sg(qc, sge);}static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc){	struct ata_port *ap = qc->ap;	struct sil24_port_priv *pp = ap->private_data;	void __iomem *port = ap->ioaddr.cmd_addr;	unsigned int tag = sil24_tag(qc->tag);	dma_addr_t paddr;	void __iomem *activate;	paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);	activate = port + PORT_CMD_ACTIVATE + tag * 8;	writel((u32)paddr, activate);	writel((u64)paddr >> 32, activate + 4);	return 0;}static void sil24_irq_clear(struct ata_port *ap){	/* unused */}static void sil24_pmp_attach(struct ata_port *ap){	sil24_config_pmp(ap, 1);	sil24_init_port(ap);}static void sil24_pmp_detach(struct ata_port *ap){	sil24_init_port(ap);	sil24_config_pmp(ap, 0);}static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,			       unsigned long deadline){	return sil24_do_softreset(link, class, link->pmp, deadline);}static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,			       unsigned long deadline){	int rc;	rc = sil24_init_port(link->ap);

⌨️ 快捷键说明

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