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

📄 sata_sil.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		writel(val, mmio);		return 0;	}	return -EINVAL;}static void sil_host_intr(struct ata_port *ap, u32 bmdma2){	struct ata_eh_info *ehi = &ap->link.eh_info;	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);	u8 status;	if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {		u32 serror;		/* SIEN doesn't mask SATA IRQs on some 3112s.  Those		 * controllers continue to assert IRQ as long as		 * SError bits are pending.  Clear SError immediately.		 */		sil_scr_read(ap, SCR_ERROR, &serror);		sil_scr_write(ap, SCR_ERROR, serror);		/* Sometimes spurious interrupts occur, double check		 * it's PHYRDY CHG.		 */		if (serror & SERR_PHYRDY_CHG) {			ap->link.eh_info.serror |= serror;			goto freeze;		}		if (!(bmdma2 & SIL_DMA_COMPLETE))			return;	}	if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {		/* this sometimes happens, just clear IRQ */		ata_chk_status(ap);		return;	}	/* Check whether we are expecting interrupt in this state */	switch (ap->hsm_task_state) {	case HSM_ST_FIRST:		/* Some pre-ATAPI-4 devices assert INTRQ		 * at this state when ready to receive CDB.		 */		/* Check the ATA_DFLAG_CDB_INTR flag is enough here.		 * The flag was turned on only for atapi devices.		 * No need to check is_atapi_taskfile(&qc->tf) again.		 */		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))			goto err_hsm;		break;	case HSM_ST_LAST:		if (qc->tf.protocol == ATA_PROT_DMA ||		    qc->tf.protocol == ATA_PROT_ATAPI_DMA) {			/* clear DMA-Start bit */			ap->ops->bmdma_stop(qc);			if (bmdma2 & SIL_DMA_ERROR) {				qc->err_mask |= AC_ERR_HOST_BUS;				ap->hsm_task_state = HSM_ST_ERR;			}		}		break;	case HSM_ST:		break;	default:		goto err_hsm;	}	/* check main status, clearing INTRQ */	status = ata_chk_status(ap);	if (unlikely(status & ATA_BUSY))		goto err_hsm;	/* ack bmdma irq events */	ata_bmdma_irq_clear(ap);	/* kick HSM in the ass */	ata_hsm_move(ap, qc, status, 0);	if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||				       qc->tf.protocol == ATA_PROT_ATAPI_DMA))		ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2);	return; err_hsm:	qc->err_mask |= AC_ERR_HSM; freeze:	ata_port_freeze(ap);}static irqreturn_t sil_interrupt(int irq, void *dev_instance){	struct ata_host *host = dev_instance;	void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];	int handled = 0;	int i;	spin_lock(&host->lock);	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap = host->ports[i];		u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);		if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))			continue;		/* turn off SATA_IRQ if not supported */		if (ap->flags & SIL_FLAG_NO_SATA_IRQ)			bmdma2 &= ~SIL_DMA_SATA_IRQ;		if (bmdma2 == 0xffffffff ||		    !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))			continue;		sil_host_intr(ap, bmdma2);		handled = 1;	}	spin_unlock(&host->lock);	return IRQ_RETVAL(handled);}static void sil_freeze(struct ata_port *ap){	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];	u32 tmp;	/* global IRQ mask doesn't block SATA IRQ, turn off explicitly */	writel(0, mmio_base + sil_port[ap->port_no].sien);	/* plug IRQ */	tmp = readl(mmio_base + SIL_SYSCFG);	tmp |= SIL_MASK_IDE0_INT << ap->port_no;	writel(tmp, mmio_base + SIL_SYSCFG);	readl(mmio_base + SIL_SYSCFG);	/* flush */}static void sil_thaw(struct ata_port *ap){	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];	u32 tmp;	/* clear IRQ */	ata_chk_status(ap);	ata_bmdma_irq_clear(ap);	/* turn on SATA IRQ if supported */	if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))		writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);	/* turn on IRQ */	tmp = readl(mmio_base + SIL_SYSCFG);	tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);	writel(tmp, mmio_base + SIL_SYSCFG);}/** *	sil_dev_config - Apply device/host-specific errata fixups *	@dev: Device to be examined * *	After the IDENTIFY [PACKET] DEVICE step is complete, and a *	device is known to be present, this function is called. *	We apply two errata fixups which are specific to Silicon Image, *	a Seagate and a Maxtor fixup. * *	For certain Seagate devices, we must limit the maximum sectors *	to under 8K. * *	For certain Maxtor devices, we must not program the drive *	beyond udma5. * *	Both fixups are unfairly pessimistic.  As soon as I get more *	information on these errata, I will create a more exhaustive *	list, and apply the fixups to only the specific *	devices/hosts/firmwares that need it. * *	20040111 - Seagate drives affected by the Mod15Write bug are blacklisted *	The Maxtor quirk is in the blacklist, but I'm keeping the original *	pessimistic fix for the following reasons... *	- There seems to be less info on it, only one device gleaned off the *	Windows	driver, maybe only one is affected.  More info would be greatly *	appreciated. *	- But then again UDMA5 is hardly anything to complain about */static void sil_dev_config(struct ata_device *dev){	struct ata_port *ap = dev->link->ap;	int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;	unsigned int n, quirks = 0;	unsigned char model_num[ATA_ID_PROD_LEN + 1];	ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));	for (n = 0; sil_blacklist[n].product; n++)		if (!strcmp(sil_blacklist[n].product, model_num)) {			quirks = sil_blacklist[n].quirk;			break;		}	/* limit requests to 15 sectors */	if (slow_down ||	    ((ap->flags & SIL_FLAG_MOD15WRITE) &&	     (quirks & SIL_QUIRK_MOD15WRITE))) {		if (print_info)			ata_dev_printk(dev, KERN_INFO, "applying Seagate "				       "errata fix (mod15write workaround)\n");		dev->max_sectors = 15;		return;	}	/* limit to udma5 */	if (quirks & SIL_QUIRK_UDMA5MAX) {		if (print_info)			ata_dev_printk(dev, KERN_INFO, "applying Maxtor "				       "errata fix %s\n", model_num);		dev->udma_mask &= ATA_UDMA5;		return;	}}static void sil_init_controller(struct ata_host *host){	struct pci_dev *pdev = to_pci_dev(host->dev);	void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];	u8 cls;	u32 tmp;	int i;	/* Initialize FIFO PCI bus arbitration */	cls = sil_get_device_cache_line(pdev);	if (cls) {		cls >>= 3;		cls++;  /* cls = (line_size/8)+1 */		for (i = 0; i < host->n_ports; i++)			writew(cls << 8 | cls,			       mmio_base + sil_port[i].fifo_cfg);	} else		dev_printk(KERN_WARNING, &pdev->dev,			   "cache line size not set.  Driver may not function\n");	/* Apply R_ERR on DMA activate FIS errata workaround */	if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {		int cnt;		for (i = 0, cnt = 0; i < host->n_ports; i++) {			tmp = readl(mmio_base + sil_port[i].sfis_cfg);			if ((tmp & 0x3) != 0x01)				continue;			if (!cnt)				dev_printk(KERN_INFO, &pdev->dev,					   "Applying R_ERR on DMA activate "					   "FIS errata fix\n");			writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);			cnt++;		}	}	if (host->n_ports == 4) {		/* flip the magic "make 4 ports work" bit */		tmp = readl(mmio_base + sil_port[2].bmdma);		if ((tmp & SIL_INTR_STEERING) == 0)			writel(tmp | SIL_INTR_STEERING,			       mmio_base + sil_port[2].bmdma);	}}static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	static int printed_version;	int board_id = ent->driver_data;	const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };	struct ata_host *host;	void __iomem *mmio_base;	int n_ports, rc;	unsigned int i;	if (!printed_version++)		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");	/* allocate host */	n_ports = 2;	if (board_id == sil_3114)		n_ports = 4;	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);	if (!host)		return -ENOMEM;	/* acquire resources and fill host */	rc = pcim_enable_device(pdev);	if (rc)		return rc;	rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME);	if (rc == -EBUSY)		pcim_pin_device(pdev);	if (rc)		return rc;	host->iomap = pcim_iomap_table(pdev);	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		return rc;	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);	if (rc)		return rc;	mmio_base = host->iomap[SIL_MMIO_BAR];	for (i = 0; i < host->n_ports; i++) {		struct ata_port *ap = host->ports[i];		struct ata_ioports *ioaddr = &ap->ioaddr;		ioaddr->cmd_addr = mmio_base + sil_port[i].tf;		ioaddr->altstatus_addr =		ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;		ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;		ioaddr->scr_addr = mmio_base + sil_port[i].scr;		ata_std_ports(ioaddr);		ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");		ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");	}	/* initialize and activate */	sil_init_controller(host);	pci_set_master(pdev);	return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED,				 &sil_sht);}#ifdef CONFIG_PMstatic int sil_pci_device_resume(struct pci_dev *pdev){	struct ata_host *host = dev_get_drvdata(&pdev->dev);	int rc;	rc = ata_pci_device_do_resume(pdev);	if (rc)		return rc;	sil_init_controller(host);	ata_host_resume(host);	return 0;}#endifstatic int __init sil_init(void){	return pci_register_driver(&sil_pci_driver);}static void __exit sil_exit(void){	pci_unregister_driver(&sil_pci_driver);}module_init(sil_init);module_exit(sil_exit);

⌨️ 快捷键说明

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