📄 sata_nv.c
字号:
struct nv_adma_cpb *cpb = &pp->cpb[i]; if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) || ap->sactive & (1 << i) ) 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); /* 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); readw( mmio + NV_ADMA_CTL ); /* flush posted write */ udelay(1); writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); readw( 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 rc; u32 bar; void __iomem *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 = pcim_enable_device(pdev); if (rc) return rc; rc = pci_request_regions(pdev, DRV_NAME); if (rc) { pcim_pin_device(pdev); return rc; } 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) return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; } 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) return -ENOMEM; if (!pcim_iomap(pdev, NV_MMIO_BAR, 0)) return -EIO; probe_ent->iomap = pcim_iomap_table(pdev); //host = kmalloc(sizeof(struct nv_host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev,sizeof(struct nv_host), GFP_KERNEL); if (!host) return -ENOMEM; memset(host, 0, sizeof(struct nv_host)); probe_ent->private_data = host; host->type = type; base = probe_ent->iomap[NV_MMIO_BAR]; 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) return rc; } rc = ata_device_add(probe_ent); if (rc != NV_PORTS) return -ENODEV; if (nv_sgpio_capable(ent)) nv_sgpio_init(pdev, host); devm_kfree(&pdev->dev, probe_ent); return 0;}static void nv_remove_one (struct pci_dev *pdev){ struct ata_host *host = dev_get_drvdata(&pdev->dev); struct nv_host *hpriv = host->private_data; //devm_kfree(&pdev->dev,hpriv); ata_pci_remove_one(pdev); //kfree(hpriv);}#ifdef CONFIG_PMstatic int nv_pci_device_resume(struct pci_dev *pdev){ struct ata_host *host = dev_get_drvdata(&pdev->dev); struct nv_host *hpriv = host->private_data; int rc; rc = ata_pci_device_do_resume(pdev); if(rc) return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { if(hpriv->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); } if(hpriv->type == ADMA) { u32 tmp32; struct nv_adma_port_priv *pp; /* enable/disable ADMA on the ports appropriately */ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); pp = host->ports[0]->private_data; if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | NV_MCP_SATA_CFG_20_PORT0_PWB_EN); else tmp32 |= (NV_MCP_SATA_CFG_20_PORT0_EN | NV_MCP_SATA_CFG_20_PORT0_PWB_EN); pp = host->ports[1]->private_data; if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN | NV_MCP_SATA_CFG_20_PORT1_PWB_EN); else tmp32 |= (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); } } ata_host_resume(host); return 0;}#endifstatic 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; }}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);}static void nv_adma_host_stop(struct ata_host *host){ struct pci_dev *pdev = to_pci_dev(host->dev); u32 tmp32; /* 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);}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 + -