📄 sata_nv.c
字号:
struct nv_adma_cpb *cpb = &pp->cpb[i]; if( cpb->ctl_flags || cpb->resp_flags ) ata_port_printk(ap, KERN_ERR, "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", i, cpb->ctl_flags, cpb->resp_flags); } /* Push us back into port register mode for error handling. */ nv_adma_register_mode(ap); ata_port_printk(ap, KERN_ERR, "Resetting port\n"); /* Mark all of the CPBs as invalid to prevent them from being executed */ for( i=0;i<NV_ADMA_MAX_CPBS;i++) pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; /* clear CPB fetch count */ writew(0, mmio + NV_ADMA_CPB_COUNT); /* Reset channel */ tmp = readw(mmio + NV_ADMA_CTL); writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); readl( mmio + NV_ADMA_CTL ); /* flush posted write */ udelay(1); writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); readl( mmio + NV_ADMA_CTL ); /* flush posted write */ } 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[2]; struct ata_probe_ent *probe_ent; int pci_dev_busy = 0; int rc; u32 bar; unsigned long base; unsigned long type = ent->driver_data; int mask_set = 0; // 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; } if(type >= CK804 && adma_enabled) { dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); type = ADMA; if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) mask_set = 1; } if(!mask_set) { 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[0] = ppi[1] = &nv_port_info[type]; 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_host; } 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 (type >= 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); if (type == ADMA) { rc = nv_adma_host_init(probe_ent); if (rc) goto err_out_iounmap; } 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_host: kfree(host);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 unsigned 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 *host){ struct nv_host *nv_host = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); u8 regval; /* disable SATA space for CK804 */ nv_sgpio_host_cleanup(nv_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);}static void nv_adma_host_stop(struct ata_host *host){ struct pci_dev *pdev = to_pci_dev(host->dev); int i; u32 tmp32; for (i = 0; i < host->n_ports; i++) { void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i); u16 tmp; /* disable interrupt */ tmp = readw(mmio + NV_ADMA_CTL); writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); } /* disable ADMA on the ports */ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | NV_MCP_SATA_CFG_20_PORT0_PWB_EN | NV_MCP_SATA_CFG_20_PORT1_EN | NV_MCP_SATA_CFG_20_PORT1_PWB_EN); pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); nv_ck804_host_stop(host);}static void nv_host_stop (struct ata_host *host){ struct nv_host *nv_host = host->private_data; nv_sgpio_host_cleanup(nv_host); kfree(nv_host); ata_pci_host_stop(host);}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 *host = 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; 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 *host_set = (struct ata_host *)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) return; if (!ap->host->private_data) return; host = ap->host->private_data; if (!host->host_sgpio.flags.sgpio_enabled) return; host_offset = nv_sgpio_tx_host_offset(ap->host); 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_register_driver(&nv_pci_driver);}static void __exit nv_exit(void){ pci_unregister_driver(&nv_pci_driver);}module_init(nv_init);module_exit(nv_exit);module_param_named(adma, adma_enabled, bool, 0444);MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -