📄 sata_nv.c
字号:
handled += nv_host_intr(ap, irq_stat); irq_stat >>= NV_INT_PORT_SHIFT; } return IRQ_RETVAL(handled);}static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct ata_host_set *host_set = dev_instance; u8 irq_stat; irqreturn_t ret; spin_lock(&host_set->lock); irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); ret = nv_do_interrupt(host_set, irq_stat); spin_unlock(&host_set->lock); return ret;}static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct ata_host_set *host_set = dev_instance; u8 irq_stat; irqreturn_t ret; spin_lock(&host_set->lock); irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804); ret = nv_do_interrupt(host_set, irq_stat); spin_unlock(&host_set->lock); return ret;}static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg){ if (sc_reg > SCR_CONTROL) return 0xffffffffU; return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));}static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val){ if (sc_reg > SCR_CONTROL) return; iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));}static void nv_nf2_freeze(struct ata_port *ap){ unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; mask = inb(scr_addr + NV_INT_ENABLE); mask &= ~(NV_INT_ALL << shift); outb(mask, scr_addr + NV_INT_ENABLE);}static void nv_nf2_thaw(struct ata_port *ap){ unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS); mask = inb(scr_addr + NV_INT_ENABLE); mask |= (NV_INT_MASK << shift); outb(mask, scr_addr + NV_INT_ENABLE);}static void nv_ck804_freeze(struct ata_port *ap){ void __iomem *mmio_base = ap->host_set->mmio_base; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; mask = readb(mmio_base + NV_INT_ENABLE_CK804); mask &= ~(NV_INT_ALL << shift); writeb(mask, mmio_base + NV_INT_ENABLE_CK804);}static void nv_ck804_thaw(struct ata_port *ap){ void __iomem *mmio_base = ap->host_set->mmio_base; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804); mask = readb(mmio_base + NV_INT_ENABLE_CK804); mask |= (NV_INT_MASK << shift); writeb(mask, mmio_base + NV_INT_ENABLE_CK804);}static int nv_hardreset(struct ata_port *ap, unsigned int *class){ unsigned int dummy; /* SATA hardreset fails to retrieve proper device signature on * some controllers. Don't classify on hardreset. For more * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 */ return sata_std_hardreset(ap, &dummy);}static void nv_error_handler(struct ata_port *ap){ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, nv_hardreset, ata_std_postreset);}static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ static int printed_version = 0; struct nv_host *host; struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; int pci_dev_busy = 0; int rc; u32 bar; unsigned long base; // Make sure this is a SATA controller by counting the number of bars // (NVIDIA SATA controllers will always have six bars). Otherwise, // it's an IDE controller and we ignore it. for (bar=0; bar<6; bar++) if (pci_resource_start(pdev, bar) == 0) return -ENODEV; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) goto err_out; rc = pci_request_regions(pdev, DRV_NAME); if (rc) { pci_dev_busy = 1; goto err_out_disable; } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; rc = -ENOMEM; ppi = &nv_port_info[ent->driver_data]; probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; host = kmalloc(sizeof(struct nv_host), GFP_KERNEL); if (!host) goto err_out_free_ent; memset(host, 0, sizeof(struct nv_host)); probe_ent->private_data = host; probe_ent->mmio_base = pci_iomap(pdev, 5, 0); if (!probe_ent->mmio_base) { rc = -EIO; goto err_out_free_ent; } base = (unsigned long)probe_ent->mmio_base; probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; /* enable SATA space for CK804 */ if (ent->driver_data == CK804) { u8 regval; pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN; pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); } pci_set_master(pdev); rc = ata_device_add(probe_ent); if (rc != NV_PORTS) goto err_out_iounmap; if (nv_sgpio_capable(ent)) nv_sgpio_init(pdev, host); kfree(probe_ent); return 0;err_out_iounmap: pci_iounmap(pdev, probe_ent->mmio_base);err_out_free_ent: kfree(probe_ent);err_out_regions: pci_release_regions(pdev);err_out_disable: if (!pci_dev_busy) pci_disable_device(pdev);err_out: return rc;}static int nv_port_start(struct ata_port *ap){ int stat; struct nv_port *port; stat = ata_port_start(ap); if (stat) { return stat; } port = kmalloc(sizeof(struct nv_port), GFP_KERNEL); if (!port) goto err_out_no_free; memset(port, 0, sizeof(struct nv_port)); ap->private_data = port; return 0;err_out_no_free: return 1;}static void nv_port_stop(struct ata_port *ap){ nv_sgpio_clear_all_leds(ap); if (ap->private_data) { kfree(ap->private_data); ap->private_data = NULL; } ata_port_stop(ap);}static int nv_qc_issue(struct ata_queued_cmd *qc){ struct nv_port *port = qc->ap->private_data; if (port) port->port_sgpio.activity.flags.recent_activity = 1; return (ata_qc_issue_prot(qc));}static void nv_ck804_host_stop(struct ata_host_set *host_set){ struct nv_host *host = host_set->private_data; struct pci_dev *pdev = to_pci_dev(host_set->dev); u8 regval; /* disable SATA space for CK804 */ nv_sgpio_host_cleanup(host); pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN; pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); ata_pci_host_stop(host_set);}static void nv_host_stop (struct ata_host_set *host_set){ struct nv_host *host = host_set->private_data; nv_sgpio_host_cleanup(host); kfree(host); ata_pci_host_stop(host_set);}static void nv_sgpio_init(struct pci_dev *pdev, struct nv_host *phost){ u16 csr_add; u32 cb_add, temp32; struct device *dev = pci_dev_to_dev(pdev); struct ata_host_set *host_set = dev_get_drvdata(dev); u8 pro=0; pci_read_config_word(pdev, NV_SGPIO_PCI_CSR_OFFSET, &csr_add); pci_read_config_dword(pdev, NV_SGPIO_PCI_CB_OFFSET, &cb_add); pci_read_config_byte(pdev, 0xA4, &pro); if (csr_add == 0 || cb_add == 0) return; if (!(pro&0x40)) return; temp32 = csr_add; phost->host_sgpio.pcsr = (void *)temp32; phost->host_sgpio.pcb = phys_to_virt(cb_add); if (phost->host_sgpio.pcb->nvcr.bit.init_cnt!=0x2 || phost->host_sgpio.pcb->nvcr.bit.cbver!=0x0) return; if (temp32 <=0x200 || temp32 >=0xFFFE ) return; if (cb_add<=0x80000 || cb_add>=0x9FC00) return; if (phost->host_sgpio.pcb->scratch_space == 0) { spin_lock_init(&nv_sgpio_lock); phost->host_sgpio.share.plock = &nv_sgpio_lock; phost->host_sgpio.share.ptstamp = &nv_sgpio_tstamp; phost->host_sgpio.pcb->scratch_space = (unsigned long)&phost->host_sgpio.share; spin_lock(phost->host_sgpio.share.plock); nv_sgpio_reset(phost->host_sgpio.pcsr); phost->host_sgpio.pcb->cr0 = SET_ENABLE(phost->host_sgpio.pcb->cr0); spin_unlock(phost->host_sgpio.share.plock); } phost->host_sgpio.share = *(struct nv_sgpio_host_share *)(unsigned long) phost->host_sgpio.pcb->scratch_space; phost->host_sgpio.flags.sgpio_enabled = 1; init_timer(&phost->host_sgpio.sgpio_timer); phost->host_sgpio.sgpio_timer.data = (unsigned long)host_set; nv_sgpio_set_timer(&phost->host_sgpio.sgpio_timer, NV_SGPIO_UPDATE_TICK);}static void nv_sgpio_set_timer(struct timer_list *ptimer, unsigned int timeout_msec){ if (!ptimer) return; ptimer->function = nv_sgpio_timer_handler; ptimer->expires = msecs_to_jiffies(timeout_msec) + jiffies; add_timer(ptimer);}static void nv_sgpio_timer_handler(unsigned long context){ struct ata_host_set *host_set = (struct ata_host_set *)context; struct nv_host *host; u8 count, host_offset, port_offset; union nv_sgpio_tx tx; bool on_off; unsigned long mask = 0xFFFF; struct nv_port *port; if (!host_set) goto err_out; else host = (struct nv_host *)host_set->private_data; if (!host->host_sgpio.flags.sgpio_enabled) goto err_out; host_offset = nv_sgpio_tx_host_offset(host_set); spin_lock(host->host_sgpio.share.plock); tx = host->host_sgpio.pcb->tx[host_offset]; spin_unlock(host->host_sgpio.share.plock); for (count = 0; count < host_set->n_ports; count++) { struct ata_port *ap; ap = host_set->ports[count]; if (!(ap && !(ap->flags & ATA_FLAG_DISABLED))) continue; port = (struct nv_port *)ap->private_data; if (!port) continue; port_offset = nv_sgpio_tx_port_offset(ap); on_off = GET_ACTIVITY(tx.tx_port[port_offset]); if (nv_sgpio_update_led(&port->port_sgpio.activity, &on_off)) { tx.tx_port[port_offset] = SET_ACTIVITY(tx.tx_port[port_offset], on_off); host->host_sgpio.flags.need_update = 1; } } if (host->host_sgpio.flags.need_update) { spin_lock(host->host_sgpio.share.plock); if (nv_sgpio_get_func(host_set) % NV_CNTRLR_SHARE_INIT == 0) { host->host_sgpio.pcb->tx[host_offset].all &= mask; mask = mask << 16; tx.all &= mask; } else { tx.all &= mask; mask = mask << 16; host->host_sgpio.pcb->tx[host_offset].all &= mask; } host->host_sgpio.pcb->tx[host_offset].all |= tx.all; spin_unlock(host->host_sgpio.share.plock); if (nv_sgpio_send_cmd(host, NV_SGPIO_CMD_WRITE_DATA)) { host->host_sgpio.flags.need_update = 0; return; } } else { nv_sgpio_set_timer(&host->host_sgpio.sgpio_timer, NV_SGPIO_UPDATE_TICK); }err_out: return;}static bool nv_sgpio_send_cmd(struct nv_host *host, u8 cmd){ u8 csr; unsigned long *ptstamp; spin_lock(host->host_sgpio.share.plock); ptstamp = host->host_sgpio.share.ptstamp; if (jiffies_to_msecs(jiffies - *ptstamp) >= NV_SGPIO_MIN_UPDATE_DELTA) { csr = nv_sgpio_get_csr((unsigned long)host->host_sgpio.pcsr); if ((GET_SGPIO_STATUS(csr) != NV_SGPIO_STATE_OPERATIONAL) || (GET_CMD_STATUS(csr) == NV_SGPIO_CMD_ACTIVE)) { } else { host->host_sgpio.pcb->cr0 = SET_ENABLE(host->host_sgpio.pcb->cr0); csr = 0; csr = SET_CMD(csr, cmd); nv_sgpio_set_csr(csr, (unsigned long)host->host_sgpio.pcsr); *ptstamp = jiffies; } spin_unlock(host->host_sgpio.share.plock); nv_sgpio_set_timer(&host->host_sgpio.sgpio_timer, NV_SGPIO_UPDATE_TICK); return 1; } else { spin_unlock(host->host_sgpio.share.plock); nv_sgpio_set_timer(&host->host_sgpio.sgpio_timer, (NV_SGPIO_MIN_UPDATE_DELTA - jiffies_to_msecs(jiffies - *ptstamp))); return 0; }}static bool nv_sgpio_update_led(struct nv_sgpio_led *led, bool *on_off){ bool need_update = 0; if (led->force_off > 0) { led->force_off--; } else if (led->flags.recent_activity ^ led->flags.last_state) { *on_off = led->flags.recent_activity; led->flags.last_state = led->flags.recent_activity; need_update = 1; } else if ((led->flags.recent_activity & led->flags.last_state) && (led->last_cons_active >= NV_SGPIO_MAX_ACTIVITY_ON)) { *on_off = NV_OFF; led->flags.last_state = NV_OFF; led->force_off = NV_SGPIO_MIN_FORCE_OFF; need_update = 1; } if (*on_off) led->last_cons_active++; else led->last_cons_active = 0; led->flags.recent_activity = 0; return need_update;}static void nv_sgpio_reset(u8 *pcsr){ u8 csr; csr = nv_sgpio_get_csr((unsigned long)pcsr); if (GET_SGPIO_STATUS(csr) == NV_SGPIO_STATE_RESET) { csr = 0; csr = SET_CMD(csr, NV_SGPIO_CMD_RESET); nv_sgpio_set_csr(csr, (unsigned long)pcsr); } csr = 0; csr = SET_CMD(csr, NV_SGPIO_CMD_READ_PARAMS); nv_sgpio_set_csr(csr, (unsigned long)pcsr);}static void nv_sgpio_host_cleanup(struct nv_host *host){ u8 csr; if (!host) return; if (host->host_sgpio.flags.sgpio_enabled) { spin_lock(host->host_sgpio.share.plock); host->host_sgpio.pcb->cr0 = SET_ENABLE(host->host_sgpio.pcb->cr0); csr = 0; csr = SET_CMD(csr, NV_SGPIO_CMD_WRITE_DATA); nv_sgpio_set_csr(csr,(unsigned long)host->host_sgpio.pcsr); spin_unlock(host->host_sgpio.share.plock); if (timer_pending(&host->host_sgpio.sgpio_timer)) del_timer(&host->host_sgpio.sgpio_timer); host->host_sgpio.flags.sgpio_enabled = 0; host->host_sgpio.pcb->scratch_space = 0; }}static void nv_sgpio_clear_all_leds(struct ata_port *ap){ struct nv_port *port = ap->private_data; struct nv_host *host; u8 host_offset, port_offset; if (!port || !ap->host_set) return; if (!ap->host_set->private_data) return; host = ap->host_set->private_data; if (!host->host_sgpio.flags.sgpio_enabled) return; host_offset = nv_sgpio_tx_host_offset(ap->host_set); port_offset = nv_sgpio_tx_port_offset(ap); spin_lock(host->host_sgpio.share.plock); host->host_sgpio.pcb->tx[host_offset].tx_port[port_offset] = 0; host->host_sgpio.flags.need_update = 1; spin_unlock(host->host_sgpio.share.plock);}static int __init nv_init(void){ return pci_module_init(&nv_pci_driver);}static void __exit nv_exit(void){ pci_unregister_driver(&nv_pci_driver);}module_init(nv_init);module_exit(nv_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -