📄 sata_inic162x.c
字号:
static void inic_freeze(struct ata_port *ap){ void __iomem *port_base = inic_port_base(ap); __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE); ata_chk_status(ap); writeb(0xff, port_base + PORT_IRQ_STAT); readb(port_base + PORT_IRQ_STAT); /* flush */}static void inic_thaw(struct ata_port *ap){ void __iomem *port_base = inic_port_base(ap); ata_chk_status(ap); writeb(0xff, port_base + PORT_IRQ_STAT); __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER); readb(port_base + PORT_IRQ_STAT); /* flush */}/* * SRST and SControl hardreset don't give valid signature on this * controller. Only controller specific hardreset mechanism works. */static int inic_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline){ struct ata_port *ap = link->ap; void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); u16 val; int rc; /* hammer it into sane state */ inic_reset_port(port_base); val = readw(idma_ctl); writew(val | IDMA_CTL_RST_ATA, idma_ctl); readw(idma_ctl); /* flush */ msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); rc = sata_link_resume(link, timing, deadline); if (rc) { ata_link_printk(link, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); return rc; } *class = ATA_DEV_NONE; if (ata_link_online(link)) { struct ata_taskfile tf; /* wait a while before checking status */ ata_wait_after_reset(ap, deadline); rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { ata_link_printk(link, KERN_WARNING, "device not ready " "after hardreset (errno=%d)\n", rc); return rc; } ata_tf_read(ap, &tf); *class = ata_dev_classify(&tf); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; } return 0;}static void inic_error_handler(struct ata_port *ap){ void __iomem *port_base = inic_port_base(ap); struct inic_port_priv *pp = ap->private_data; unsigned long flags; /* reset PIO HSM and stop DMA engine */ inic_reset_port(port_base); spin_lock_irqsave(ap->lock, flags); ap->hsm_task_state = HSM_ST_IDLE; writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL); spin_unlock_irqrestore(ap->lock, flags); /* PIO and DMA engines have been stopped, perform recovery */ ata_do_eh(ap, ata_std_prereset, NULL, inic_hardreset, ata_std_postreset);}static void inic_post_internal_cmd(struct ata_queued_cmd *qc){ /* make DMA engine forget about the failed command */ if (qc->flags & ATA_QCFLAG_FAILED) inic_reset_port(inic_port_base(qc->ap));}static void inic_dev_config(struct ata_device *dev){ /* inic can only handle upto LBA28 max sectors */ if (dev->max_sectors > ATA_MAX_SECTORS) dev->max_sectors = ATA_MAX_SECTORS; if (dev->n_sectors >= 1 << 28) { ata_dev_printk(dev, KERN_ERR, "ERROR: This driver doesn't support LBA48 yet and may cause\n" " data corruption on such devices. Disabling.\n"); ata_dev_disable(dev); }}static void init_port(struct ata_port *ap){ void __iomem *port_base = inic_port_base(ap); /* Setup PRD address */ writel(ap->prd_dma, port_base + PORT_PRD_ADDR);}static int inic_port_resume(struct ata_port *ap){ init_port(ap); return 0;}static int inic_port_start(struct ata_port *ap){ void __iomem *port_base = inic_port_base(ap); struct inic_port_priv *pp; u8 tmp; int rc; /* alloc and initialize private data */ pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL); if (!pp) return -ENOMEM; ap->private_data = pp; /* default PRD_CTL value, DMAEN, WR and START off */ tmp = readb(port_base + PORT_PRD_CTL); tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START); pp->dfl_prdctl = tmp; /* Alloc resources */ rc = ata_port_start(ap); if (rc) { kfree(pp); return rc; } init_port(ap); return 0;}static struct ata_port_operations inic_port_ops = { .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, .scr_read = inic_scr_read, .scr_write = inic_scr_write, .bmdma_setup = inic_bmdma_setup, .bmdma_start = inic_bmdma_start, .bmdma_stop = inic_bmdma_stop, .bmdma_status = inic_bmdma_status, .irq_clear = inic_irq_clear, .irq_on = ata_irq_on, .qc_prep = ata_qc_prep, .qc_issue = inic_qc_issue, .data_xfer = ata_data_xfer, .freeze = inic_freeze, .thaw = inic_thaw, .error_handler = inic_error_handler, .post_internal_cmd = inic_post_internal_cmd, .dev_config = inic_dev_config, .port_resume = inic_port_resume, .port_start = inic_port_start,};static struct ata_port_info inic_port_info = { /* For some reason, ATA_PROT_ATAPI is broken on this * controller, and no, PIO_POLLING does't fix it. It somehow * manages to report the wrong ireason and ignoring ireason * results in machine lock up. Tell libata to always prefer * DMA. */ .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, .port_ops = &inic_port_ops};static int init_controller(void __iomem *mmio_base, u16 hctl){ int i; u16 val; hctl &= ~HCTL_KNOWN_BITS; /* Soft reset whole controller. Spec says reset duration is 3 * PCI clocks, be generous and give it 10ms. */ writew(hctl | HCTL_SOFTRST, mmio_base + HOST_CTL); readw(mmio_base + HOST_CTL); /* flush */ for (i = 0; i < 10; i++) { msleep(1); val = readw(mmio_base + HOST_CTL); if (!(val & HCTL_SOFTRST)) break; } if (val & HCTL_SOFTRST) return -EIO; /* mask all interrupts and reset ports */ for (i = 0; i < NR_PORTS; i++) { void __iomem *port_base = mmio_base + i * PORT_SIZE; writeb(0xff, port_base + PORT_IRQ_MASK); inic_reset_port(port_base); } /* port IRQ is masked now, unmask global IRQ */ writew(hctl & ~HCTL_IRQOFF, mmio_base + HOST_CTL); val = readw(mmio_base + HOST_IRQ_MASK); val &= ~(HIRQ_PORT0 | HIRQ_PORT1); writew(val, mmio_base + HOST_IRQ_MASK); return 0;}#ifdef CONFIG_PMstatic int inic_pci_device_resume(struct pci_dev *pdev){ struct ata_host *host = dev_get_drvdata(&pdev->dev); struct inic_host_priv *hpriv = host->private_data; void __iomem *mmio_base = host->iomap[MMIO_BAR]; int rc; rc = ata_pci_device_do_resume(pdev); if (rc) return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { rc = init_controller(mmio_base, hpriv->cached_hctl); if (rc) return rc; } ata_host_resume(host); return 0;}#endifstatic int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ static int printed_version; const struct ata_port_info *ppi[] = { &inic_port_info, NULL }; struct ata_host *host; struct inic_host_priv *hpriv; void __iomem * const *iomap; int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* alloc host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS); hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); if (!host || !hpriv) return -ENOMEM; host->private_data = hpriv; /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME); if (rc) return rc; host->iomap = iomap = pcim_iomap_table(pdev); for (i = 0; i < NR_PORTS; i++) { struct ata_port *ap = host->ports[i]; struct ata_ioports *port = &ap->ioaddr; unsigned int offset = i * PORT_SIZE; port->cmd_addr = iomap[2 * i]; port->altstatus_addr = port->ctl_addr = (void __iomem *) ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR; ata_std_ports(port); ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio"); ata_port_pbar_desc(ap, MMIO_BAR, offset, "port"); ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", (unsigned long long)pci_resource_start(pdev, 2 * i), (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) | ATA_PCI_CTL_OFS); } hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); /* Set dma_mask. This devices doesn't support 64bit addressing. */ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "32-bit DMA enable failed\n"); return rc; } rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "32-bit consistent DMA enable failed\n"); return rc; } rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "failed to initialize controller\n"); return rc; } pci_set_master(pdev); return ata_host_activate(host, pdev->irq, inic_interrupt, IRQF_SHARED, &inic_sht);}static const struct pci_device_id inic_pci_tbl[] = { { PCI_VDEVICE(INIT, 0x1622), }, { },};static struct pci_driver inic_pci_driver = { .name = DRV_NAME, .id_table = inic_pci_tbl,#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = inic_pci_device_resume,#endif .probe = inic_init_one, .remove = ata_pci_remove_one,};static int __init inic_init(void){ return pci_register_driver(&inic_pci_driver);}static void __exit inic_exit(void){ pci_unregister_driver(&inic_pci_driver);}MODULE_AUTHOR("Tejun Heo");MODULE_DESCRIPTION("low-level driver for Initio 162x SATA");MODULE_LICENSE("GPL v2");MODULE_DEVICE_TABLE(pci, inic_pci_tbl);MODULE_VERSION(DRV_VERSION);module_init(inic_init);module_exit(inic_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -