📄 madgemc.c
字号:
* * There's two ways we can check to see if the interrupt is ours, * both with their own disadvantages... * * 1) Read in the SIFSTS register from the TMS controller. This * is guarenteed to be accurate, however, there's a fairly * large performance penalty for doing so: the Madge chips * must request the register from the Eagle, the Eagle must * read them from its internal bus, and then take the route * back out again, for a 16bit read. * * 2) Use the MC_CONTROL_REG0_SINTR bit from the Madge ASICs. * The major disadvantage here is that the accuracy of the * bit is in question. However, it cuts out the extra read * cycles it takes to read the Eagle's SIF, as its only an * 8bit read, and theoretically the Madge bit is directly * connected to the interrupt latch coming out of the Eagle * hardware (that statement is not verified). * * I can't determine which of these methods has the best win. For now, * we make a compromise. Use the Madge way for the first interrupt, * which should be the fast-path, and then once we hit the first * interrupt, keep on trying using the SIF method until we've * exhausted all contiguous interrupts. * */static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs){ int pending,reg1; struct net_device *dev; if (!dev_id) { printk("madgemc_interrupt: was not passed a dev_id!\n"); return IRQ_NONE; } dev = (struct net_device *)dev_id; /* Make sure its really us. -- the Madge way */ pending = inb(dev->base_addr + MC_CONTROL_REG0); if (!(pending & MC_CONTROL_REG0_SINTR)) return IRQ_NONE; /* not our interrupt */ /* * Since we're level-triggered, we may miss the rising edge * of the next interrupt while we're off handling this one, * so keep checking until the SIF verifies that it has nothing * left for us to do. */ pending = STS_SYSTEM_IRQ; do { if (pending & STS_SYSTEM_IRQ) { /* Toggle the interrupt to reset the latch on card */ reg1 = inb(dev->base_addr + MC_CONTROL_REG1); outb(reg1 ^ MC_CONTROL_REG1_SINTEN, dev->base_addr + MC_CONTROL_REG1); outb(reg1, dev->base_addr + MC_CONTROL_REG1); /* Continue handling as normal */ tms380tr_interrupt(irq, dev_id, regs); pending = SIFREADW(SIFSTS); /* restart - the SIF way */ } else return IRQ_HANDLED; } while (1); return IRQ_HANDLED; /* not reachable */}/* * Set the card to the prefered ring speed. * * Unlike newer cards, the MC16/32 have their speed selection * circuit connected to the Madge ASICs and not to the TMS380 * NSELOUT pins. Set the ASIC bits correctly here, and return * zero to leave the TMS NSELOUT bits unaffected. * */unsigned short madgemc_setnselout_pins(struct net_device *dev){ unsigned char reg1; struct net_local *tp = netdev_priv(dev); reg1 = inb(dev->base_addr + MC_CONTROL_REG1); if(tp->DataRate == SPEED_16) reg1 |= MC_CONTROL_REG1_SPEED_SEL; /* add for 16mb */ else if (reg1 & MC_CONTROL_REG1_SPEED_SEL) reg1 ^= MC_CONTROL_REG1_SPEED_SEL; /* remove for 4mb */ outb(reg1, dev->base_addr + MC_CONTROL_REG1); return 0; /* no change */}/* * Set the register page. This equates to the SRSX line * on the TMS380Cx6. * * Register selection is normally done via three contiguous * bits. However, some boards (such as the MC16/32) use only * two bits, plus a separate bit in the glue chip. This * sets the SRSX bit (the top bit). See page 4-17 in the * Yellow Book for which registers are affected. * */static void madgemc_setregpage(struct net_device *dev, int page){ static int reg1; reg1 = inb(dev->base_addr + MC_CONTROL_REG1); if ((page == 0) && (reg1 & MC_CONTROL_REG1_SRSX)) { outb(reg1 ^ MC_CONTROL_REG1_SRSX, dev->base_addr + MC_CONTROL_REG1); } else if (page == 1) { outb(reg1 | MC_CONTROL_REG1_SRSX, dev->base_addr + MC_CONTROL_REG1); } reg1 = inb(dev->base_addr + MC_CONTROL_REG1); return;}/* * The SIF registers are not mapped into register space by default * Set this to 1 to map them, 0 to map the BIA ROM. * */static void madgemc_setsifsel(struct net_device *dev, int val){ unsigned int reg0; reg0 = inb(dev->base_addr + MC_CONTROL_REG0); if ((val == 0) && (reg0 & MC_CONTROL_REG0_SIFSEL)) { outb(reg0 ^ MC_CONTROL_REG0_SIFSEL, dev->base_addr + MC_CONTROL_REG0); } else if (val == 1) { outb(reg0 | MC_CONTROL_REG0_SIFSEL, dev->base_addr + MC_CONTROL_REG0); } reg0 = inb(dev->base_addr + MC_CONTROL_REG0); return;}/* * Enable SIF interrupts * * This does not enable interrupts in the SIF, but rather * enables SIF interrupts to be passed onto the host. * */static void madgemc_setint(struct net_device *dev, int val){ unsigned int reg1; reg1 = inb(dev->base_addr + MC_CONTROL_REG1); if ((val == 0) && (reg1 & MC_CONTROL_REG1_SINTEN)) { outb(reg1 ^ MC_CONTROL_REG1_SINTEN, dev->base_addr + MC_CONTROL_REG1); } else if (val == 1) { outb(reg1 | MC_CONTROL_REG1_SINTEN, dev->base_addr + MC_CONTROL_REG1); } return;}/* * Cable type is set via control register 7. Bit zero high * for UTP, low for STP. */static void madgemc_setcabletype(struct net_device *dev, int type){ outb((type==0)?MC_CONTROL_REG7_CABLEUTP:MC_CONTROL_REG7_CABLESTP, dev->base_addr + MC_CONTROL_REG7);}/* * Enable the functions of the Madge chipset needed for * full working order. */static int madgemc_chipset_init(struct net_device *dev){ outb(0, dev->base_addr + MC_CONTROL_REG1); /* pull SRESET low */ tms380tr_wait(100); /* wait for card to reset */ /* bring back into normal operating mode */ outb(MC_CONTROL_REG1_NSRESET, dev->base_addr + MC_CONTROL_REG1); /* map SIF registers */ madgemc_setsifsel(dev, 1); /* enable SIF interrupts */ madgemc_setint(dev, 1); return 0;}/* * Disable the board, and put back into power-up state. */static void madgemc_chipset_close(struct net_device *dev){ /* disable interrupts */ madgemc_setint(dev, 0); /* unmap SIF registers */ madgemc_setsifsel(dev, 0); return;}/* * Read the card type (MC16 or MC32) from the card. * * The configuration registers are stored in two separate * pages. Pages are flipped by clearing bit 3 of CONTROL_REG0 (PAGE) * for page zero, or setting bit 3 for page one. * * Page zero contains the following data: * Byte 0: Manufacturer ID (0x4D -- ASCII "M") * Byte 1: Card type: * 0x08 for MC16 * 0x0D for MC32 * Byte 2: Card revision * Byte 3: Mirror of POS config register 0 * Byte 4: Mirror of POS 1 * Byte 5: Mirror of POS 2 * * Page one contains the following data: * Byte 0: Unused * Byte 1-6: BIA, MSB to LSB. * * Note that to read the BIA, we must unmap the SIF registers * by clearing bit 2 of CONTROL_REG0 (SIFSEL), as the data * will reside in the same logical location. For this reason, * _never_ read the BIA while the Eagle processor is running! * The SIF will be completely inaccessible until the BIA operation * is complete. * */static void madgemc_read_rom(struct net_device *dev, struct card_info *card){ unsigned long ioaddr; unsigned char reg0, reg1, tmpreg0, i; ioaddr = dev->base_addr; reg0 = inb(ioaddr + MC_CONTROL_REG0); reg1 = inb(ioaddr + MC_CONTROL_REG1); /* Switch to page zero and unmap SIF */ tmpreg0 = reg0 & ~(MC_CONTROL_REG0_PAGE + MC_CONTROL_REG0_SIFSEL); outb(tmpreg0, ioaddr + MC_CONTROL_REG0); card->manid = inb(ioaddr + MC_ROM_MANUFACTURERID); card->cardtype = inb(ioaddr + MC_ROM_ADAPTERID); card->cardrev = inb(ioaddr + MC_ROM_REVISION); /* Switch to rom page one */ outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0); /* Read BIA */ dev->addr_len = 6; for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); /* Restore original register values */ outb(reg0, ioaddr + MC_CONTROL_REG0); outb(reg1, ioaddr + MC_CONTROL_REG1); return;}static int madgemc_open(struct net_device *dev){ /* * Go ahead and reinitialize the chipset again, just to * make sure we didn't get left in a bad state. */ madgemc_chipset_init(dev); tms380tr_open(dev); return 0;}static int madgemc_close(struct net_device *dev){ tms380tr_close(dev); madgemc_chipset_close(dev); return 0;}/* * Give some details available from /proc/mca/slotX */static int madgemc_mcaproc(char *buf, int slot, void *d) { struct net_device *dev = (struct net_device *)d; struct net_local *tp = dev->priv; struct card_info *curcard = tp->tmspriv; int len = 0; len += sprintf(buf+len, "-------\n"); if (curcard) { struct net_local *tp = netdev_priv(dev); int i; len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize); len += sprintf(buf+len, "Cable type: %s\n", (curcard->cabletype)?"STP/DB9":"UTP/RJ-45"); len += sprintf(buf+len, "Configured ring speed: %dMb/sec\n", (curcard->ringspeed)?16:4); len += sprintf(buf+len, "Running ring speed: %dMb/sec\n", (tp->DataRate==SPEED_16)?16:4); len += sprintf(buf+len, "Device: %s\n", dev->name); len += sprintf(buf+len, "IO Port: 0x%04lx\n", dev->base_addr); len += sprintf(buf+len, "IRQ: %d\n", dev->irq); len += sprintf(buf+len, "Arbitration Level: %d\n", curcard->arblevel); len += sprintf(buf+len, "Burst Mode: "); switch(curcard->burstmode) { case 0: len += sprintf(buf+len, "Cycle steal"); break; case 1: len += sprintf(buf+len, "Limited burst"); break; case 2: len += sprintf(buf+len, "Delayed release"); break; case 3: len += sprintf(buf+len, "Immediate release"); break; } len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); len += sprintf(buf+len, "Ring Station Address: "); len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]); for (i = 1; i < 6; i++) len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]); len += sprintf(buf+len, "\n"); } else len += sprintf(buf+len, "Card not configured\n"); return len;}static int __devexit madgemc_remove(struct device *device){ struct net_device *dev = dev_get_drvdata(device); struct net_local *tp; struct card_info *card; if (!dev) BUG(); tp = dev->priv; card = tp->tmspriv; kfree(card); tp->tmspriv = NULL; unregister_netdev(dev); release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); free_irq(dev->irq, dev); tmsdev_term(dev); free_netdev(dev); dev_set_drvdata(device, NULL); return 0;}static short madgemc_adapter_ids[] __initdata = { 0x002d, 0x0000};static struct mca_driver madgemc_driver = { .id_table = madgemc_adapter_ids, .driver = { .name = "madgemc", .bus = &mca_bus_type, .probe = madgemc_probe, .remove = __devexit_p(madgemc_remove), },};static int __init madgemc_init (void){ return mca_register_driver (&madgemc_driver);}static void __exit madgemc_exit (void){ mca_unregister_driver (&madgemc_driver);}module_init(madgemc_init);module_exit(madgemc_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -