📄 aic5800.c
字号:
spin_lock_irqsave(&aic->async_queue_lock, flags); if (aic->async_queue == NULL) { aic->async_queue = packet; send_next_async(aic); } else { p = aic->async_queue; while (p->xnext != NULL) { p = p->xnext; } p->xnext = packet; } spin_unlock_irqrestore(&aic->async_queue_lock, flags); return 1;}static int get_phy_reg(struct aic5800 *aic, int addr){ int retval; int i = 0; /* sanity check */ if (addr > 15) { PRINT(KERN_ERR, aic->id, __FUNCTION__ ": PHY register address %d out of range", addr); return -1; } /* request data from PHY */ reg_write(aic, misc_PhyControl, LINK_PHY_READ | LINK_PHY_ADDR(addr)); /* read data from PhyControl register */ /* note that we have to wait until the register is updated */ do { retval = reg_read(aic, misc_PhyControl); if (i > 10000) { PRINT(KERN_ERR, aic->id, __FUNCTION__ ": runaway loop, aborting"); retval = -1; break; } i++; } while ((retval & 0xf000000) != LINK_PHY_RADDR(addr)); /* we don't want a PhyInt interrupt */ reg_write(aic, misc_InterruptClear, INT_PhyInt); if (retval != -1) { return ((retval & 0xff0000)>>16); } else { return -1; }}static quadlet_t generate_own_selfid(struct aic5800 *aic, int phyid){ quadlet_t lsid; char phyreg[7]; int i; for (i = 1; i < 7; i++) { phyreg[i] = get_phy_reg(aic, i); } /* Standard PHY register map */ lsid = 0x80400000 | (phyid << 24); lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dep) */ lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */ if (phyreg[3 + i] & 0x4) { lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) << (6 - i*2); } else { lsid |= 1 << (6 - i*2); } } return lsid;};/* moved out to make interrupt routine more readable */inline static void handle_selfid(struct aic5800 *aic, struct hpsb_host *host, int phyid, int isroot, size_t size){ quadlet_t *q = aic->rcv_page; quadlet_t lsid; /* we need our own self-id packet */ lsid = generate_own_selfid(aic, phyid); /* unconnected state? only begin and end marker in rcv_page */ if (size==8) { hpsb_selfid_received(host, lsid); } /* process buffer... AIC's FIFO often contains some strangenesses */ while (size > 0) { if (q[0] == 0xe0) { /* marker */ q += 1; size -= 4; continue; }; if (q[0] == 0x1) { /* marker */ q += 1; size -= 4; break; }; if (q[0] == ~q[1]) { /* correct self-id */ if ((q[0] & 0x3f800000) == ((phyid + 1) << 24)) { /* its our turn now! */ //PRINT(KERN_INFO, // aic->id, "selfid packet 0x%x included", lsid); hpsb_selfid_received(host, lsid); } //PRINT(KERN_INFO, aic->id, "selfid packet 0x%x rcvd", q[0]); hpsb_selfid_received(host, q[0]); q += 2; size -= 8; continue; }; } /* if we are root, our self-id packet is last */ if (isroot && phyid != 0) { hpsb_selfid_received(host, lsid); } hpsb_selfid_complete(host, phyid, isroot);}static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs){ struct aic5800 *aic = (struct aic5800 *)dev_id; struct hpsb_host *host = aic->host; quadlet_t *q = aic->rcv_page; int phyid = -1, isroot = 0; u32 interruptEvent = reg_read(aic, misc_InterruptEvents); reg_write(aic, misc_InterruptClear, interruptEvent); //printk("InterruptEvent 0x%x\n", interruptEvent); if ( (interruptEvent & 0x3f) == 0x3f ) { PRINT(KERN_INFO, aic->id, "Dma Engine Error"); }; if ( interruptEvent & INT_DmaAT ) { if (aic->AT_program[0].status & 0xFFFF) PRINT(KERN_INFO, aic->id, "AT: could not transfer %d bytes", aic->AT_program[0].status & 0xFFFF); }; if ( interruptEvent & INT_PhyInt) { PRINT(KERN_INFO, aic->id, "PhyInt"); }; if ( interruptEvent & INT_DmaAR ) { int rcv_bytes; int i; /* we calculate the number of received bytes from the residual count field */ rcv_bytes = AIC5800_ARFIFO_SIZE - (aic->AR_program->status & 0xFFFF); //PRINT(KERN_INFO, aic->id, "AR_status 0x%x, %d bytes read", aic->AR_program->status, rcv_bytes); if ((aic->AR_program->status & 0x84000000) && (aic->AR_program->status & 0xFFFF) >= 8 ) {#ifndef __BIG_ENDIAN /* we have to do byte-swapping on non-bigendian architectures */ for (i=0; i< (rcv_bytes / sizeof(quadlet_t)); i++) { *q = be32_to_cpu(*q); q++; }; q = aic->rcv_page;#endif if (*q == 0xe0) { phyid = reg_read(aic, misc_NodeID); isroot = phyid & 0x800000; phyid = phyid & 0x3F; handle_selfid(aic, host, phyid, isroot, rcv_bytes); } else { hpsb_packet_received(host, aic->rcv_page, rcv_bytes, 0); }; } else { PRINT(KERN_ERR, aic->id, "AR DMA program status value 0x%x is incorrect!", aic->AR_program->status); }; } if ( interruptEvent & INT_BusReset ) { PRINT(KERN_INFO, aic->id, "bus reset occured"); if (!host->in_bus_reset) { hpsb_bus_reset(host); } reg_set_bits(aic, misc_Control, 0x1); aic->NumBusResets++; }; if (interruptEvent & INT_RcvData ) { aic->RxPackets++; }; if (interruptEvent & INT_TxRdy) { /* async packet sent - transmitter ready */ u32 ack; struct hpsb_packet *packet; if (aic->async_queue) { spin_lock(&aic->async_queue_lock); ack = reg_read(aic, AT_ChannelStatus) & 0xF; packet = aic->async_queue; aic->async_queue = packet->xnext; if (aic->async_queue != NULL) { send_next_async(aic); } spin_unlock(&aic->async_queue_lock); PRINT(KERN_INFO,aic->id,"packet sent with ack code %d",ack); hpsb_packet_sent(host, packet, ack); } // else //PRINT(KERN_INFO,aic->id,"packet sent without async_queue (self-id?)"); aic->TxRdy++; }; if (interruptEvent & INT_ATError ) { PRINT(KERN_INFO,aic->id,"ATError"); aic->ATError++; }; if (interruptEvent & INT_SendRej ) { aic->SendRej++; }; if (interruptEvent & INT_HdrErr ) { aic->HdrErr++; }; if (interruptEvent & INT_TCodeErr ) { PRINT(KERN_INFO,aic->id,"TCodeErr"); aic->TCodeErr++; }; aic->NumInterrupts++;}inline static void * quadquadalign(void *buf){ if ((unsigned int) buf % 0x10 != 0) { return (void *)(((unsigned int)buf + 0x10) & 0xFFFFFFF0); } else { return buf; };}static int add_card(struct pci_dev *dev){#define FAIL(fmt, args...) do {\ PRINT_G(KERN_ERR, fmt , ## args); \ num_of_cards--; \ remove_card(aic); \ return 1; } while (0) struct aic5800 *aic; /* shortcut to currently handled device */ unsigned long page; if (pci_enable_device(dev)) return 1; if (num_of_cards == MAX_AIC5800_CARDS) { PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " "Adjust MAX_AIC5800_CARDS in aic5800.h.", MAX_AIC5800_CARDS); return 1; } aic = &cards[num_of_cards++]; aic->id = num_of_cards-1; aic->dev = dev; if (!request_irq(dev->irq, aic_irq_handler, SA_SHIRQ, AIC5800_DRIVER_NAME, aic)) { PRINT(KERN_INFO, aic->id, "allocated interrupt %d", dev->irq); } else { FAIL("failed to allocate shared interrupt %d", dev->irq); } page = get_free_page(GFP_KERNEL); if (page != 0) { aic->rcv_page = phys_to_virt(page); } else { FAIL("failed to allocate receive buffer"); }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) aic->registers = ioremap_nocache(dev->base_address[0], AIC5800_REGSPACE_SIZE);#else aic->registers = ioremap_nocache(dev->resource[0].start, AIC5800_REGSPACE_SIZE);#endif if (aic->registers == NULL) { FAIL("failed to remap registers - card not accessible"); } PRINT(KERN_INFO, aic->id, "remapped memory space reg 0x%p", aic->registers); aic->pbuf = kmalloc(AIC5800_PBUF_SIZE, GFP_KERNEL); if (!aic->pbuf) { FAIL("failed to allocate program buffer"); } aic->AT_program = quadquadalign(aic->pbuf); aic->AT_program[2].control = DMA_CMD_STOP; aic->AR_program = aic->AT_program + MAX_AT_PROGRAM_SIZE * sizeof(struct dma_cmd); return 0;#undef FAIL}static void remove_card(struct aic5800 *aic){ /* Disable interrupts of this controller */ reg_write(aic, misc_InterruptMask, 0); /* Free AR buffer */ free_page(virt_to_phys(aic->rcv_page)); /* Free channel program buffer */ kfree(aic->pbuf); /* Free interrupt request */ free_irq(aic->dev->irq, aic); /* Unmap register space */ iounmap(aic->registers);}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; } while ((dev = pci_find_device(PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_5800, dev)) != NULL) { if (add_card(dev) == 0) { success = 1; } } if (success == 0) { PRINT_G(KERN_WARNING, "no operable AIC-5800 based cards found"); return -ENXIO; } return 0;}/** Prepare our local CSR ROM. This is done by using the software-stored ROM and inserting the GUID read from the EEPROM */static size_t get_aic_rom(struct hpsb_host *host, const quadlet_t **ptr){ struct aic5800 *aic = host -> hostdata; u64 guid; /* Read the GUID from the card's EEPROM and put it into the right place in the CONFIG ROM. */ guid = read_guid(aic); aic5800_csr_rom[15] = (u32) (guid >> 32); aic5800_csr_rom[16] = (u32) (guid & 0xFFFF); *ptr = aic5800_csr_rom; return sizeof(aic5800_csr_rom);}struct hpsb_host_template *get_aic_template(void){ static struct hpsb_host_template tmpl; static int initialized = 0; if (!initialized) { /* Initialize by field names so that a template structure * reorganization does not influence this code. */ tmpl.name = "aic5800"; tmpl.detect_hosts = aic_detect; tmpl.initialize_host = aic_initialize; tmpl.release_host = aic_release; tmpl.get_rom = get_aic_rom; tmpl.transmit_packet = aic_transmit; tmpl.devctl = aic_devctl; initialized = 1; } return &tmpl;}#ifdef MODULE/* EXPORT_NO_SYMBOLS; */MODULE_AUTHOR("Emanuel Pirker <epirker@edu.uni-klu.ac.at>");MODULE_DESCRIPTION("Adaptec AIC-5800 PCI-to-IEEE1394 controller driver");MODULE_SUPPORTED_DEVICE("aic5800");void cleanup_module(void){ hpsb_unregister_lowlevel(get_aic_template()); PRINT_G(KERN_INFO, "removed " AIC5800_DRIVER_NAME " module");}int init_module(void){ if (hpsb_register_lowlevel(get_aic_template())) { PRINT_G(KERN_ERR, "registering failed"); return -ENXIO; } else { return 0; }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -