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

📄 sata_fsl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		  ata_std_postreset);}static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc){	if (qc->flags & ATA_QCFLAG_FAILED)		qc->err_mask |= AC_ERR_OTHER;	if (qc->err_mask) {		/* make DMA engine forget about the failed command */	}}static void sata_fsl_irq_clear(struct ata_port *ap){	/* unused */}static void sata_fsl_error_intr(struct ata_port *ap){	struct ata_link *link = &ap->link;	struct ata_eh_info *ehi = &link->eh_info;	struct sata_fsl_host_priv *host_priv = ap->host->private_data;	void __iomem *hcr_base = host_priv->hcr_base;	u32 hstatus, dereg, cereg = 0, SError = 0;	unsigned int err_mask = 0, action = 0;	struct ata_queued_cmd *qc;	int freeze = 0;	hstatus = ioread32(hcr_base + HSTATUS);	cereg = ioread32(hcr_base + CE);	ata_ehi_clear_desc(ehi);	/*	 * Handle & Clear SError	 */	sata_fsl_scr_read(ap, SCR_ERROR, &SError);	if (unlikely(SError & 0xFFFF0000)) {		sata_fsl_scr_write(ap, SCR_ERROR, SError);		err_mask |= AC_ERR_ATA_BUS;	}	DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",		hstatus, cereg, ioread32(hcr_base + DE), SError);	/* handle single device errors */	if (cereg) {		/*		 * clear the command error, also clears queue to the device		 * in error, and we can (re)issue commands to this device.		 * When a device is in error all commands queued into the		 * host controller and at the device are considered aborted		 * and the queue for that device is stopped. Now, after		 * clearing the device error, we can issue commands to the		 * device to interrogate it to find the source of the error.		 */		dereg = ioread32(hcr_base + DE);		iowrite32(dereg, hcr_base + DE);		iowrite32(cereg, hcr_base + CE);		DPRINTK("single device error, CE=0x%x, DE=0x%x\n",			ioread32(hcr_base + CE), ioread32(hcr_base + DE));		/*		 * We should consider this as non fatal error, and TF must		 * be updated as done below.		 */		err_mask |= AC_ERR_DEV;	}	/* handle fatal errors */	if (hstatus & FATAL_ERROR_DECODE) {		err_mask |= AC_ERR_ATA_BUS;		action |= ATA_EH_SOFTRESET;		/* how will fatal error interrupts be completed ?? */		freeze = 1;	}	/* Handle PHYRDY change notification */	if (hstatus & INT_ON_PHYRDY_CHG) {		DPRINTK("SATA FSL: PHYRDY change indication\n");		/* Setup a soft-reset EH action */		ata_ehi_hotplugged(ehi);		freeze = 1;	}	/* record error info */	qc = ata_qc_from_tag(ap, link->active_tag);	if (qc) {		sata_fsl_cache_taskfile_from_d2h_fis(qc, qc->ap);		qc->err_mask |= err_mask;	} else		ehi->err_mask |= err_mask;	ehi->action |= action;	ehi->serror |= SError;	/* freeze or abort */	if (freeze)		ata_port_freeze(ap);	else		ata_port_abort(ap);}static void sata_fsl_qc_complete(struct ata_queued_cmd *qc){	if (qc->flags & ATA_QCFLAG_RESULT_TF) {		DPRINTK("xx_qc_complete called\n");		sata_fsl_cache_taskfile_from_d2h_fis(qc, qc->ap);	}}static void sata_fsl_host_intr(struct ata_port *ap){	struct ata_link *link = &ap->link;	struct sata_fsl_host_priv *host_priv = ap->host->private_data;	void __iomem *hcr_base = host_priv->hcr_base;	u32 hstatus, qc_active = 0;	struct ata_queued_cmd *qc;	u32 SError;	hstatus = ioread32(hcr_base + HSTATUS);	sata_fsl_scr_read(ap, SCR_ERROR, &SError);	if (unlikely(SError & 0xFFFF0000)) {		DPRINTK("serror @host_intr : 0x%x\n", SError);		sata_fsl_error_intr(ap);	}	if (unlikely(hstatus & INT_ON_ERROR)) {		DPRINTK("error interrupt!!\n");		sata_fsl_error_intr(ap);		return;	}	if (link->sactive) {	/* only true for NCQ commands */		int i;		/* Read command completed register */		qc_active = ioread32(hcr_base + CC);		/* clear CC bit, this will also complete the interrupt */		iowrite32(qc_active, hcr_base + CC);		DPRINTK("Status of all queues :\n");		DPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x\n",			qc_active, ioread32(hcr_base + CA),			ioread32(hcr_base + CE));		for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {			if (qc_active & (1 << i)) {				qc = ata_qc_from_tag(ap, i);				if (qc) {					sata_fsl_qc_complete(qc);					ata_qc_complete(qc);				}				DPRINTK				    ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",				     i, ioread32(hcr_base + CC),				     ioread32(hcr_base + CA));			}		}		return;	} else if (ap->qc_active) {		iowrite32(1, hcr_base + CC);		qc = ata_qc_from_tag(ap, link->active_tag);		DPRINTK("completing non-ncq cmd, tag=%d,CC=0x%x\n",			link->active_tag, ioread32(hcr_base + CC));		if (qc) {			sata_fsl_qc_complete(qc);			ata_qc_complete(qc);		}	} else {		/* Spurious Interrupt!! */		DPRINTK("spurious interrupt!!, CC = 0x%x\n",			ioread32(hcr_base + CC));		return;	}}static irqreturn_t sata_fsl_interrupt(int irq, void *dev_instance){	struct ata_host *host = dev_instance;	struct sata_fsl_host_priv *host_priv = host->private_data;	void __iomem *hcr_base = host_priv->hcr_base;	u32 interrupt_enables;	unsigned handled = 0;	struct ata_port *ap;	/* ack. any pending IRQs for this controller/port */	interrupt_enables = ioread32(hcr_base + HSTATUS);	interrupt_enables &= 0x3F;	DPRINTK("interrupt status 0x%x\n", interrupt_enables);	if (!interrupt_enables)		return IRQ_NONE;	spin_lock(&host->lock);	/* Assuming one port per host controller */	ap = host->ports[0];	if (ap) {		sata_fsl_host_intr(ap);	} else {		dev_printk(KERN_WARNING, host->dev,			   "interrupt on disabled port 0\n");	}	iowrite32(interrupt_enables, hcr_base + HSTATUS);	handled = 1;	spin_unlock(&host->lock);	return IRQ_RETVAL(handled);}/* * Multiple ports are represented by multiple SATA controllers with * one port per controller */static int sata_fsl_init_controller(struct ata_host *host){	struct sata_fsl_host_priv *host_priv = host->private_data;	void __iomem *hcr_base = host_priv->hcr_base;	u32 temp;	/*	 * NOTE : We cannot bring the controller online before setting	 * the CHBA, hence main controller initialization is done as	 * part of the port_start() callback	 */	/* ack. any pending IRQs for this controller/port */	temp = ioread32(hcr_base + HSTATUS);	if (temp & 0x3F)		iowrite32((temp & 0x3F), hcr_base + HSTATUS);	/* Keep interrupts disabled on the controller */	temp = ioread32(hcr_base + HCONTROL);	iowrite32((temp & ~0x3F), hcr_base + HCONTROL);	/* Disable interrupt coalescing control(icc), for the moment */	DPRINTK("icc = 0x%x\n", ioread32(hcr_base + ICC));	iowrite32(0x01000000, hcr_base + ICC);	/* clear error registers, SError is cleared by libATA  */	iowrite32(0x00000FFFF, hcr_base + CE);	iowrite32(0x00000FFFF, hcr_base + DE);	/* initially assuming no Port multiplier, set CQPMP to 0 */	iowrite32(0x0, hcr_base + CQPMP);	/*	 * host controller will be brought on-line, during xx_port_start()	 * callback, that should also initiate the OOB, COMINIT sequence	 */	DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));	DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));	return 0;}/* * scsi mid-layer and libata interface structures */static struct scsi_host_template sata_fsl_sht = {	.module = THIS_MODULE,	.name = "sata_fsl",	.ioctl = ata_scsi_ioctl,	.queuecommand = ata_scsi_queuecmd,	.change_queue_depth = ata_scsi_change_queue_depth,	.can_queue = SATA_FSL_QUEUE_DEPTH,	.this_id = ATA_SHT_THIS_ID,	.sg_tablesize = SATA_FSL_MAX_PRD_USABLE,	.cmd_per_lun = ATA_SHT_CMD_PER_LUN,	.emulated = ATA_SHT_EMULATED,	.use_clustering = ATA_SHT_USE_CLUSTERING,	.proc_name = "sata_fsl",	.dma_boundary = ATA_DMA_BOUNDARY,	.slave_configure = ata_scsi_slave_config,	.slave_destroy = ata_scsi_slave_destroy,	.bios_param = ata_std_bios_param,};static const struct ata_port_operations sata_fsl_ops = {	.check_status = sata_fsl_check_status,	.check_altstatus = sata_fsl_check_status,	.dev_select = ata_noop_dev_select,	.tf_read = sata_fsl_tf_read,	.qc_prep = sata_fsl_qc_prep,	.qc_issue = sata_fsl_qc_issue,	.irq_clear = sata_fsl_irq_clear,	.scr_read = sata_fsl_scr_read,	.scr_write = sata_fsl_scr_write,	.freeze = sata_fsl_freeze,	.thaw = sata_fsl_thaw,	.error_handler = sata_fsl_error_handler,	.post_internal_cmd = sata_fsl_post_internal_cmd,	.port_start = sata_fsl_port_start,	.port_stop = sata_fsl_port_stop,};static const struct ata_port_info sata_fsl_port_info[] = {	{	 .flags = SATA_FSL_HOST_FLAGS,	 .link_flags = SATA_FSL_HOST_LFLAGS,	 .pio_mask = 0x1f,	/* pio 0-4 */	 .udma_mask = 0x7f,	/* udma 0-6 */	 .port_ops = &sata_fsl_ops,	 },};static int sata_fsl_probe(struct of_device *ofdev,			const struct of_device_id *match){	int retval = 0;	void __iomem *hcr_base = NULL;	void __iomem *ssr_base = NULL;	void __iomem *csr_base = NULL;	struct sata_fsl_host_priv *host_priv = NULL;	struct resource *r;	int irq;	struct ata_host *host;	struct ata_port_info pi = sata_fsl_port_info[0];	const struct ata_port_info *ppi[] = { &pi, NULL };	dev_printk(KERN_INFO, &ofdev->dev,		   "Sata FSL Platform/CSB Driver init\n");	r = kmalloc(sizeof(struct resource), GFP_KERNEL);	hcr_base = of_iomap(ofdev->node, 0);	if (!hcr_base)		goto error_exit_with_cleanup;	ssr_base = hcr_base + 0x100;	csr_base = hcr_base + 0x140;	DPRINTK("@reset i/o = 0x%x\n", ioread32(csr_base + TRANSCFG));	DPRINTK("sizeof(cmd_desc) = %d\n", sizeof(struct command_desc));	DPRINTK("sizeof(#define cmd_desc) = %d\n", SATA_FSL_CMD_DESC_SIZE);	host_priv = kzalloc(sizeof(struct sata_fsl_host_priv), GFP_KERNEL);	if (!host_priv)		goto error_exit_with_cleanup;	host_priv->hcr_base = hcr_base;	host_priv->ssr_base = ssr_base;	host_priv->csr_base = csr_base;	irq = irq_of_parse_and_map(ofdev->node, 0);	if (irq < 0) {		dev_printk(KERN_ERR, &ofdev->dev, "invalid irq from platform\n");		goto error_exit_with_cleanup;	}	host_priv->irq = irq;	/* allocate host structure */	host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS);	/* host->iomap is not used currently */	host->private_data = host_priv;	/* setup port(s) */	host->ports[0]->ioaddr.cmd_addr = host_priv->hcr_base;	host->ports[0]->ioaddr.scr_addr = host_priv->ssr_base;	/* initialize host controller */	sata_fsl_init_controller(host);	/*	 * Now, register with libATA core, this will also initiate the	 * device discovery process, invoking our port_start() handler &	 * error_handler() to execute a dummy Softreset EH session	 */	ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG,			  &sata_fsl_sht);	dev_set_drvdata(&ofdev->dev, host);	return 0;error_exit_with_cleanup:	if (hcr_base)		iounmap(hcr_base);	if (host_priv)		kfree(host_priv);	return retval;}static int sata_fsl_remove(struct of_device *ofdev){	struct ata_host *host = dev_get_drvdata(&ofdev->dev);	struct sata_fsl_host_priv *host_priv = host->private_data;	ata_host_detach(host);	dev_set_drvdata(&ofdev->dev, NULL);	irq_dispose_mapping(host_priv->irq);	iounmap(host_priv->hcr_base);	kfree(host_priv);	return 0;}static struct of_device_id fsl_sata_match[] = {	{		.compatible = "fsl,mpc8315-sata",	},	{		.compatible = "fsl,mpc8379-sata",	},	{},};MODULE_DEVICE_TABLE(of, fsl_sata_match);static struct of_platform_driver fsl_sata_driver = {	.name		= "fsl-sata",	.match_table	= fsl_sata_match,	.probe		= sata_fsl_probe,	.remove		= sata_fsl_remove,};static int __init sata_fsl_init(void){	of_register_platform_driver(&fsl_sata_driver);	return 0;}static void __exit sata_fsl_exit(void){	of_unregister_platform_driver(&fsl_sata_driver);}MODULE_LICENSE("GPL");MODULE_AUTHOR("Ashish Kalra, Freescale Semiconductor");MODULE_DESCRIPTION("Freescale 3.0Gbps SATA controller low level driver");MODULE_VERSION("1.10");module_init(sata_fsl_init);module_exit(sata_fsl_exit);

⌨️ 快捷键说明

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