📄 sata_sil.c
字号:
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 + -