📄 sata_nv.c
字号:
u8 regval; intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804); intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804); 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);}static void nv_check_hotplug_ck804(struct ata_host_set *host_set){ u8 intr_status; intr_status = readb(host_set->mmio_base + NV_INT_STATUS_CK804); // Clear interrupt status. writeb(0xff, host_set->mmio_base + NV_INT_STATUS_CK804); if (intr_status & NV_INT_STATUS_HOTPLUG) { if (intr_status & NV_INT_STATUS_PDEV_ADDED) printk(KERN_WARNING "nv_sata: " "Primary device added\n"); if (intr_status & NV_INT_STATUS_PDEV_REMOVED) printk(KERN_WARNING "nv_sata: " "Primary device removed\n"); if (intr_status & NV_INT_STATUS_SDEV_ADDED) printk(KERN_WARNING "nv_sata: " "Secondary device added\n"); if (intr_status & NV_INT_STATUS_SDEV_REMOVED) printk(KERN_WARNING "nv_sata: " "Secondary device removed\n"); }}static void nv_enable_hotplug_mcp55(struct ata_probe_ent *probe_ent){ struct pci_dev *pdev = to_pci_dev(probe_ent->dev); u8 intr_mask; 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); writeb(0x0c, probe_ent->mmio_base + NV_INT_STATUS_MCP55); writeb(0x0c, probe_ent->mmio_base + NV_INT_STATUS_MCP55+2); intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_MCP55); intr_mask |= 0x0c; writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_MCP55); intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_MCP55+2); intr_mask |= 0x0c; writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_MCP55+2);}static void nv_disable_hotplug_mcp55(struct ata_host_set *host_set){ struct pci_dev *pdev = to_pci_dev(host_set->dev); u8 intr_mask; u8 regval; intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_MCP55); intr_mask &= ~(0x0C); writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_MCP55); intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_MCP55+2); intr_mask &= ~(0x0C); writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_MCP55+2); 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);}static void nv_check_hotplug_mcp55(struct ata_host_set *host_set){ u8 intr_status,intr_status1; intr_status = readb(host_set->mmio_base + NV_INT_STATUS_MCP55); intr_status1 = readb(host_set->mmio_base + NV_INT_STATUS_MCP55+2); // Clear interrupt status. writeb(0xff, host_set->mmio_base + NV_INT_STATUS_MCP55); writeb(0xff, host_set->mmio_base + NV_INT_STATUS_MCP55+2); if ((intr_status & 0x0c) || (intr_status1&0x0c)) { if (intr_status & 0x04) printk(KERN_WARNING "nv_sata: " "Primary device added\n"); if (intr_status & 0x08) printk(KERN_WARNING "nv_sata: " "Primary device removed\n"); if (intr_status1 & 0x04) printk(KERN_WARNING "nv_sata: " "Secondary device added\n"); if (intr_status1 & 0x08) printk(KERN_WARNING "nv_sata: " "Secondary device removed\n"); }}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; phost->pdev = pdev; init_timer(&phost->host_sgpio.sgpio_timer); phost->host_sgpio.sgpio_timer.data = (unsigned long)phost; nv_sgpio_set_timer(&phost->host_sgpio.sgpio_timer, NV_SGPIO_UPDATE_TICK);}static void __nv_sgpio_timer_handler(unsigned long context);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 nv_host *phost = (struct nv_host*)context; struct device *dev = pci_dev_to_dev(phost->pdev); struct ata_host_set *host_set = dev_get_drvdata(dev); if (!host_set) nv_sgpio_set_timer(&phost->host_sgpio.sgpio_timer, NV_SGPIO_UPDATE_TICK); else nv_sgpio_timer_handler(host_set); }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_PORT_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_msecs1(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)) { //nv_sgpio_reset(host->host_sgpio.pcsr); } 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_msecs1(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){#ifdef RHAS3U7 int rc; rc = pci_module_init(&nv_pci_driver); if (rc) return rc; rc = scsi_register_module(MODULE_SCSI_HA, &nv_sht); if (rc) { pci_unregister_driver(&nv_pci_driver); /* TODO: does scsi_register_module return errno val? */ return -ENODEV; } return 0;#else return pci_module_init(&nv_pci_driver);#endif}static void __exit nv_exit(void){#ifdef RHAS3U7 scsi_unregister_module(MODULE_SCSI_HA, &nv_sht);#endif pci_unregister_driver(&nv_pci_driver);}module_init(nv_init);module_exit(nv_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -