📄 pcilynx.c
字号:
packet = lynx->iso_send.queue; lynx->iso_send.queue = packet->xnext; pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, packet->header_size, PCI_DMA_TODEVICE); if (packet->data_size) { pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, packet->data_size, PCI_DMA_TODEVICE); } if (lynx->iso_send.queue != NULL) { send_next(lynx, hpsb_iso); } spin_unlock(&lynx->iso_send.queue_lock); hpsb_packet_sent(host, packet, ACK_COMPLETE); } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { /* general receive DMA completed */ int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV)); PRINTD(KERN_DEBUG, lynx->id, "received packet size %d", stat & 0x1fff); if (stat & DMA_CHAN_STAT_SELFID) { lynx->selfid_size = stat & 0x1fff; handle_selfid(lynx, host); } else { quadlet_t *q_data = lynx->rcv_page; if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) { cpu_to_be32s(q_data + 3); } hpsb_packet_received(host, q_data, stat & 0x1fff, 0); } run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); }}static void iso_rcv_bh(struct ti_lynx *lynx){ unsigned int idx; quadlet_t *data; unsigned long flags; spin_lock_irqsave(&lynx->iso_rcv.lock, flags); while (lynx->iso_rcv.used) { idx = lynx->iso_rcv.last; spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE] + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE; if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) { PRINT(KERN_ERR, lynx->id, "iso length mismatch 0x%08x/0x%08x", *data, lynx->iso_rcv.stat[idx]); } if (lynx->iso_rcv.stat[idx] & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) { PRINT(KERN_INFO, lynx->id, "iso receive error on %d to 0x%p", idx, data); } else { hpsb_packet_received(lynx->host, data, lynx->iso_rcv.stat[idx] & 0x1fff, 0); } spin_lock_irqsave(&lynx->iso_rcv.lock, flags); lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL; lynx->iso_rcv.used--; } if (lynx->iso_rcv.chan_count) { reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), DMA_WORD1_CMP_ENABLE_MASTER); } spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);}static int __devinit add_card(struct pci_dev *dev, const struct pci_device_id *devid){#define FAIL(fmt, args...) do { \ PRINT_G(KERN_ERR, fmt , ## args); \ num_of_cards--; \ remove_card(dev); \ return -1; \ } while (0) struct ti_lynx *lynx; /* shortcut to currently handled device */ unsigned int i; if (num_of_cards == MAX_PCILYNX_CARDS) { PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " "Adjust MAX_PCILYNX_CARDS in pcilynx.h.", MAX_PCILYNX_CARDS); return -1; } lynx = &cards[num_of_cards++]; if (pci_set_dma_mask(dev, 0xffffffff)) FAIL("DMA address limits not supported for PCILynx hardware %d", lynx->id); if (pci_enable_device(dev)) FAIL("failed to enable PCILynx hardware %d", lynx->id); pci_set_master(dev); lynx->host = hpsb_get_host(&lynx_template, 0); if (!lynx->host) FAIL("failed to allocate host structure"); lynx->state = have_host_struct; lynx->host->hostdata = lynx; lynx->id = num_of_cards-1; lynx->dev = dev; lynx->host->pdev = dev; lynx->lock = SPIN_LOCK_UNLOCKED; lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE, &lynx->pcl_mem_dma); if (lynx->pcl_mem != NULL) { lynx->state = have_pcl_mem; PRINT(KERN_INFO, lynx->id, "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE, lynx->pcl_mem); } else { FAIL("failed to allocate PCL memory area"); }#endif#ifdef CONFIG_IEEE1394_PCILYNX_PORTS lynx->mem_dma_buffer = pci_alloc_consistent(dev, 65536, &lynx->mem_dma_buffer_dma); if (lynx->mem_dma_buffer == NULL) { FAIL("failed to allocate DMA buffer for aux"); } lynx->state = have_aux_buf;#endif lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE, &lynx->rcv_page_dma); if (lynx->rcv_page == NULL) { FAIL("failed to allocate receive buffer"); } lynx->state = have_1394_buffers; for (i = 0; i < ISORCV_PAGES; i++) { lynx->iso_rcv.page[i] = pci_alloc_consistent(dev, PAGE_SIZE, &lynx->iso_rcv.page_dma[i]); if (lynx->iso_rcv.page[i] == NULL) { FAIL("failed to allocate iso receive buffers"); } } lynx->registers = ioremap_nocache(pci_resource_start(dev,0), PCILYNX_MAX_REGISTER); lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY); lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY); lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE), PCILYNX_MAX_MEMORY); lynx->state = have_iomappings; if (lynx->registers == NULL) { FAIL("failed to remap registers - card not accessible"); }#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM if (lynx->local_ram == NULL) { FAIL("failed to remap local RAM which is required for " "operation"); }#endif reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, PCILYNX_DRIVER_NAME, lynx)) { PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); lynx->state = have_intr; } else { FAIL("failed to allocate shared interrupt %d", dev->irq); } /* alloc_pcl return values are not checked, it is expected that the * provided PCL space is sufficient for the initial allocations */#ifdef CONFIG_IEEE1394_PCILYNX_PORTS if (lynx->aux_port != NULL) { lynx->dmem_pcl = alloc_pcl(lynx); aux_setup_pcls(lynx); sema_init(&lynx->mem_dma_mutex, 1); }#endif lynx->rcv_pcl = alloc_pcl(lynx); lynx->rcv_pcl_start = alloc_pcl(lynx); lynx->async.pcl = alloc_pcl(lynx); lynx->async.pcl_start = alloc_pcl(lynx); lynx->iso_send.pcl = alloc_pcl(lynx); lynx->iso_send.pcl_start = alloc_pcl(lynx); for (i = 0; i < NUM_ISORCV_PCL; i++) { lynx->iso_rcv.pcl[i] = alloc_pcl(lynx); } lynx->iso_rcv.pcl_start = alloc_pcl(lynx); /* all allocations successful - simple init stuff follows */ reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);#ifdef CONFIG_IEEE1394_PCILYNX_PORTS reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT); init_waitqueue_head(&lynx->mem_dma_intr_wait); init_waitqueue_head(&lynx->aux_intr_wait);#endif tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh, (unsigned long)lynx); lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED; lynx->async.queue_lock = SPIN_LOCK_UNLOCKED; lynx->async.channel = CHANNEL_ASYNC_SEND; lynx->iso_send.queue_lock = SPIN_LOCK_UNLOCKED; lynx->iso_send.channel = CHANNEL_ISO_SEND; PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, " "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom, lynx->local_ram, lynx->aux_port); /* now, looking for PHY register set */ if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { lynx->phyic.reg_1394a = 1; PRINT(KERN_INFO, lynx->id, "found 1394a conform PHY (using extended register set)"); lynx->phyic.vendor = get_phy_vendorid(lynx); lynx->phyic.product = get_phy_productid(lynx); } else { lynx->phyic.reg_1394a = 0; PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); } /* Tell the highlevel this host is ready */ highlevel_add_one_host (lynx->host); return 0;#undef FAIL}static void remove_card(struct pci_dev *dev){ struct ti_lynx *lynx; int i; lynx = cards; while (lynx->dev != dev) lynx++; switch (lynx->state) { case have_intr: reg_write(lynx, PCI_INT_ENABLE, 0); free_irq(lynx->dev->irq, lynx); case have_iomappings: reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); iounmap(lynx->registers); iounmap(lynx->local_rom); iounmap(lynx->local_ram); iounmap(lynx->aux_port); case have_1394_buffers: for (i = 0; i < ISORCV_PAGES; i++) { if (lynx->iso_rcv.page[i]) { pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->iso_rcv.page[i], lynx->iso_rcv.page_dma[i]); } } pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page, lynx->rcv_page_dma); case have_aux_buf:#ifdef CONFIG_IEEE1394_PCILYNX_PORTS pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer, lynx->mem_dma_buffer_dma);#endif case have_pcl_mem:#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, lynx->pcl_mem_dma);#endif case have_host_struct: /* FIXME - verify host freeing */ case clear:; /* do nothing - already freed */ } tasklet_kill(&lynx->iso_rcv.tq); lynx->state = clear;}#if 0static int init_driver(){ struct pci_dev *dev = NULL; int success = 0; if (num_of_cards) { PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); return 0; } PRINT_G(KERN_INFO, "looking for PCILynx cards"); while ((dev = pci_find_device(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_PCILYNX, dev)) != NULL) { if (add_card(dev) == 0) { success = 1; } } if (success == 0) { PRINT_G(KERN_WARNING, "no operable PCILynx cards found"); return -ENXIO; }#ifdef CONFIG_IEEE1394_PCILYNX_PORTS if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) { PRINT_G(KERN_ERR, "allocation of char major number %d failed", PCILYNX_MAJOR); return -EBUSY; }#endif return 0;}#endifstatic size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr){ *ptr = lynx_csr_rom; return sizeof(lynx_csr_rom);}static struct hpsb_host_template lynx_template = { name: PCILYNX_DRIVER_NAME, initialize_host: lynx_initialize, release_host: lynx_release, get_rom: get_lynx_rom, transmit_packet: lynx_transmit, devctl: lynx_devctl};static struct pci_device_id pci_table[] __devinitdata = { { vendor: PCI_VENDOR_ID_TI, device: PCI_DEVICE_ID_TI_PCILYNX, subvendor: PCI_ANY_ID, subdevice: PCI_ANY_ID, }, { } /* Terminating entry */};static struct pci_driver lynx_pcidriver = { name: PCILYNX_DRIVER_NAME, id_table: pci_table, probe: add_card, remove: remove_card,};MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("pcilynx");MODULE_DEVICE_TABLE(pci, pci_table);static void __exit pcilynx_cleanup(void){ hpsb_unregister_lowlevel(&lynx_template); pci_unregister_driver(&lynx_pcidriver); PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");}static int __init pcilynx_init(void){ int ret; if (hpsb_register_lowlevel(&lynx_template)) { PRINT_G(KERN_ERR, "registering failed"); return -ENXIO; } ret = pci_module_init(&lynx_pcidriver); if (ret < 0) { PRINT_G(KERN_ERR, "PCI module init failed"); hpsb_unregister_lowlevel(&lynx_template); } return ret;}module_init(pcilynx_init);module_exit(pcilynx_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -