📄 pcilynx.c
字号:
if (ack & DMA_CHAN_STAT_SPECIALACK) { ack = (ack >> 15) & 0xf; PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); } else { ack = (ack >> 15) & 0xf; } hpsb_packet_sent(host, packet, ack); } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { struct hpsb_packet *packet; spin_lock(&lynx->iso_send.queue_lock); 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, 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) { handle_selfid(lynx, host, stat & 0x1fff); reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN); } 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 add_card(struct pci_dev *dev){#define FAIL(fmt, args...) do { \ PRINT_G(KERN_ERR, fmt , ## args); \ num_of_cards--; \ remove_card(lynx); \ 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++]; lynx->id = num_of_cards-1; lynx->dev = dev; if (!pci_dma_supported(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);#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 */ lynx->lock = SPIN_LOCK_UNLOCKED; reg_write(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT | PCI_INT_DMA_ALL);#ifdef CONFIG_IEEE1394_PCILYNX_PORTS init_waitqueue_head(&lynx->mem_dma_intr_wait); init_waitqueue_head(&lynx->aux_intr_wait);#endif lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh; lynx->iso_rcv.tq.data = 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"); } return 0;#undef FAIL}static void remove_card(struct ti_lynx *lynx){ int i; 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 clear: /* do nothing - already freed */ } lynx->state = clear;}static 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;}static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr){ *ptr = lynx_csr_rom; return sizeof(lynx_csr_rom);}struct hpsb_host_template *get_lynx_template(void){ static struct hpsb_host_template tmpl = { name: "pcilynx", detect_hosts: lynx_detect, initialize_host: lynx_initialize, release_host: lynx_release, get_rom: get_lynx_rom, transmit_packet: lynx_transmit, devctl: lynx_devctl }; return &tmpl;}#ifdef MODULE/* EXPORT_NO_SYMBOLS; */MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");MODULE_SUPPORTED_DEVICE("pcilynx");void cleanup_module(void){ hpsb_unregister_lowlevel(get_lynx_template()); PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");}int init_module(void){ if (hpsb_register_lowlevel(get_lynx_template())) { PRINT_G(KERN_ERR, "registering failed"); return -ENXIO; } else { return 0; }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -