📄 eexpress.c
字号:
} } if (test_and_set_bit(0,(void *)&dev->tbusy)) { lp->stats.tx_dropped++; } else { unsigned short length = (ETH_ZLEN < buf->len) ? buf->len : ETH_ZLEN; unsigned short *data = (unsigned short *)buf->data; lp->stats.tx_bytes += length; eexp_hw_tx_pio(dev,data,length); } dev_kfree_skb(buf); enable_irq(dev->irq); return 0;}/* * Handle an EtherExpress interrupt * If we've finished initializing, start the RU and CU up. * If we've already started, reap tx buffers, handle any received packets, * check to make sure we've not become wedged. *//* * Handle an EtherExpress interrupt * If we've finished initializing, start the RU and CU up. * If we've already started, reap tx buffers, handle any received packets, * check to make sure we've not become wedged. */static unsigned short eexp_start_irq(struct device *dev, unsigned short status){ unsigned short ack_cmd = SCB_ack(status); struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) { short diag_status, tdr_status; while (SCB_CUstat(status)==2) status = scb_status(dev);#if NET_DEBUG > 4 printk("%s: CU went non-active (status %04x)\n", dev->name, status);#endif outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR); diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT)); if (diag_status & 1<<11) { printk(KERN_WARNING "%s: 82586 failed self-test\n", dev->name); } else if (!(diag_status & 1<<13)) { printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name); } outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR); tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT)); if (tdr_status & (TDR_SHORT|TDR_OPEN)) { printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : ""); } else if (tdr_status & TDR_XCVRPROBLEM) { printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name); } else if (tdr_status & TDR_LINKOK) {#if NET_DEBUG > 4 printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);#endif } else { printk("%s: TDR is ga-ga (status %04x)\n", dev->name, tdr_status); } lp->started |= STARTED_CU; scb_wrcbl(dev, lp->tx_link); /* if the RU isn't running, start it now */ if (!(lp->started & STARTED_RU)) { ack_cmd |= SCB_RUstart; scb_wrrfa(dev, lp->rx_buf_start); lp->rx_ptr = lp->rx_buf_start; } ack_cmd |= SCB_CUstart | 0x2000; } if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4) lp->started|=STARTED_RU; return ack_cmd;}static void eexp_cmd_clear(struct device *dev){ unsigned long int oldtime = jiffies; while (scb_rdcmd(dev) && ((jiffies-oldtime)<10)); if (scb_rdcmd(dev)) { printk("%s: command didn't clear\n", dev->name); }} static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs){ struct device *dev = dev_info; struct net_local *lp; unsigned short ioaddr,status,ack_cmd; unsigned short old_read_ptr, old_write_ptr; if (dev==NULL) { printk(KERN_WARNING "eexpress: irq %d for unknown device\n", irq); return; } lp = (struct net_local *)dev->priv; ioaddr = dev->base_addr; old_read_ptr = inw(ioaddr+READ_PTR); old_write_ptr = inw(ioaddr+WRITE_PTR); outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ); dev->interrupt = 1; status = scb_status(dev);#if NET_DEBUG > 4 printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);#endif if (lp->started == (STARTED_CU | STARTED_RU)) { do { eexp_cmd_clear(dev); ack_cmd = SCB_ack(status); scb_command(dev, ack_cmd); outb(0,ioaddr+SIGNAL_CA); eexp_cmd_clear(dev); if (SCB_complete(status)) { if (!eexp_hw_lasttxstat(dev)) { printk("%s: tx interrupt but no status\n", dev->name); } } if (SCB_rxdframe(status)) eexp_hw_rx_pio(dev); status = scb_status(dev); } while (status & 0xc000); if (SCB_RUdead(status)) { printk(KERN_WARNING "%s: RU stopped: status %04x\n", dev->name,status);#if 0 printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd); outw(lp->cur_rfd, ioaddr+READ_PTR); printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT)); outw(lp->cur_rfd+6, ioaddr+READ_PTR); printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT)); outw(rbd, ioaddr+READ_PTR); printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT)); outw(rbd+8, ioaddr+READ_PTR); printk("[%04x]\n", inw(ioaddr+DATAPORT));#endif lp->stats.rx_errors++;#if 1 eexp_hw_rxinit(dev);#else lp->cur_rfd = lp->first_rfd;#endif scb_wrrfa(dev, lp->rx_buf_start); scb_command(dev, SCB_RUstart); outb(0,ioaddr+SIGNAL_CA); } } else { if (status & 0x8000) ack_cmd = eexp_start_irq(dev, status); else ack_cmd = SCB_ack(status); scb_command(dev, ack_cmd); outb(0,ioaddr+SIGNAL_CA); } eexp_cmd_clear(dev); outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ); dev->interrupt = 0;#if NET_DEBUG > 6 printk("%s: leaving eexp_irq()\n", dev->name);#endif outw(old_read_ptr, ioaddr+READ_PTR); outw(old_write_ptr, ioaddr+WRITE_PTR); return;}/* * Hardware access functions *//* * Set the cable type to use. */static void eexp_hw_set_interface(struct device *dev){ unsigned char oldval = inb(dev->base_addr + 0x300e); oldval &= ~0x82; switch (dev->if_port) { case TPE: oldval |= 0x2; case BNC: oldval |= 0x80; break; } outb(oldval, dev->base_addr+0x300e); mdelay(20);}/* * Check all the receive buffers, and hand any received packets * to the upper levels. Basic sanity check on each frame * descriptor, though we don't bother trying to fix broken ones. */static void eexp_hw_rx_pio(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short rx_block = lp->rx_ptr; unsigned short boguscount = lp->num_rx_bufs; unsigned short ioaddr = dev->base_addr; unsigned short status;#if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);#endif do { unsigned short rfd_cmd, rx_next, pbuf, pkt_len; outw(rx_block, ioaddr + READ_PTR); status = inw(ioaddr + DATAPORT); if (FD_Done(status)) { rfd_cmd = inw(ioaddr + DATAPORT); rx_next = inw(ioaddr + DATAPORT); pbuf = inw(ioaddr + DATAPORT); outw(pbuf, ioaddr + READ_PTR); pkt_len = inw(ioaddr + DATAPORT); if (rfd_cmd!=0x0000) { printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n", dev->name, rfd_cmd); continue; } else if (pbuf!=rx_block+0x16) { printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n", dev->name, rx_block+0x16, pbuf); continue; } else if ((pkt_len & 0xc000)!=0xc000) { printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n", dev->name, pkt_len & 0xc000); continue; } else if (!FD_OK(status)) { lp->stats.rx_errors++; if (FD_CRC(status)) lp->stats.rx_crc_errors++; if (FD_Align(status)) lp->stats.rx_frame_errors++; if (FD_Resrc(status)) lp->stats.rx_fifo_errors++; if (FD_DMA(status)) lp->stats.rx_over_errors++; if (FD_Short(status)) lp->stats.rx_length_errors++; } else { struct sk_buff *skb; pkt_len &= 0x3fff; skb = dev_alloc_skb(pkt_len+16); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name); lp->stats.rx_dropped++; break; } skb->dev = dev; skb_reserve(skb, 2); outw(pbuf+10, ioaddr+READ_PTR); insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1); skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } outw(rx_block, ioaddr+WRITE_PTR); outw(0, ioaddr+DATAPORT); outw(0, ioaddr+DATAPORT); rx_block = rx_next; } } while (FD_Done(status) && boguscount--); lp->rx_ptr = rx_block;}/* * Hand a packet to the card for transmission * If we get here, we MUST have already checked * to make sure there is room in the transmit * buffer region. */static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf, unsigned short len){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; if (lp->width) { /* Stop the CU so that there is no chance that it jumps off to a bogus address while we are writing the pointer to the next transmit packet in 8-bit mode -- this eliminates the "CU wedged" errors in 8-bit mode. (Zoltan Szilagyi 10-12-96) */ scb_command(dev, SCB_CUsuspend); outw(0xFFFF, ioaddr+SIGNAL_CA); } outw(lp->tx_head, ioaddr + WRITE_PTR); outw(0x0000, ioaddr + DATAPORT); outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT); outw(lp->tx_head+0x08, ioaddr + DATAPORT); outw(lp->tx_head+0x0e, ioaddr + DATAPORT); outw(0x0000, ioaddr + DATAPORT); outw(0x0000, ioaddr + DATAPORT); outw(lp->tx_head+0x08, ioaddr + DATAPORT); outw(0x8000|len, ioaddr + DATAPORT); outw(-1, ioaddr + DATAPORT); outw(lp->tx_head+0x16, ioaddr + DATAPORT); outw(0, ioaddr + DATAPORT); outsw(ioaddr + DATAPORT, buf, (len+1)>>1); outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR); outw(lp->tx_head, ioaddr + DATAPORT); dev->trans_start = jiffies; lp->tx_tail = lp->tx_head; if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) lp->tx_head = TX_BUF_START; else lp->tx_head += TX_BUF_SIZE; if (lp->tx_head != lp->tx_reap) dev->tbusy = 0; if (lp->width) { /* Restart the CU so that the packet can actually be transmitted. (Zoltan Szilagyi 10-12-96) */ scb_command(dev, SCB_CUresume); outw(0xFFFF, ioaddr+SIGNAL_CA); } lp->stats.tx_packets++; lp->last_tx = jiffies;}/* * Sanity check the suspected EtherExpress card * Read hardware address, reset card, size memory and initialize buffer * memory pointers. These are held in dev->priv, in case someone has more * than one card in a machine. */__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)){ unsigned short hw_addr[3]; unsigned char buswidth; unsigned int memory_size; int i; unsigned short xsum = 0; struct net_local *lp; printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr); outb(ASIC_RST, ioaddr+EEPROM_Ctrl); outb(0, ioaddr+EEPROM_Ctrl); udelay(500); outb(i586_RST, ioaddr+EEPROM_Ctrl); hw_addr[0] = eexp_hw_readeeprom(ioaddr,2); hw_addr[1] = eexp_hw_readeeprom(ioaddr,3); hw_addr[2] = eexp_hw_readeeprom(ioaddr,4); /* Standard Address or Compaq LTE Address */ if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) || (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00)))) { printk(" rejected: invalid address %04x%04x%04x\n", hw_addr[2],hw_addr[1],hw_addr[0]); return -ENODEV; } /* Calculate the EEPROM checksum. Carry on anyway if it's bad, * though. */ for (i = 0; i < 64; i++) xsum += eexp_hw_readeeprom(ioaddr, i); if (xsum != 0xbaba) printk(" (bad EEPROM xsum 0x%02x)", xsum); dev->base_addr = ioaddr; for ( i=0 ; i<6 ; i++ ) dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i]; { static char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0}; unsigned short setupval = eexp_hw_readeeprom(ioaddr,0); /* Use the IRQ from EEPROM if none was given */ if (!dev->irq) dev->irq = irqmap[setupval>>13]; dev->if_port = !(setupval & 0x1000) ? AUI : eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC; buswidth = !((setupval & 0x400) >> 10); } dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (!dev->priv) return ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); printk("(IRQ %d, %s connector, %d-bit bus", dev->irq, eexp_ifmap[dev->if_port], buswidth?8:16); eexp_hw_set_interface(dev); /* Find out how much RAM we have on the card */ outw(0, dev->base_addr + WRITE_PTR); for (i = 0; i < 32768; i++) outw(0, dev->base_addr + DATAPORT); for (memory_size = 0; memory_size < 64; memory_size++) { outw(memory_size<<10, dev->base_addr + READ_PTR); if (inw(dev->base_addr+DATAPORT)) break; outw(memory_size<<10, dev->base_addr + WRITE_PTR); outw(memory_size | 0x5000, dev->base_addr+DATAPORT); outw(memory_size<<10, dev->base_addr + READ_PTR); if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000)) break; } /* Sort out the number of buffers. We may have 16, 32, 48 or 64k * of RAM to play with. */ lp->num_tx_bufs = 4; lp->rx_buf_end = 0x3ff6; switch (memory_size) { case 64: lp->rx_buf_end += 0x4000; case 48: lp->num_tx_bufs += 4; lp->rx_buf_end += 0x4000; case 32: lp->rx_buf_end += 0x4000; case 16: printk(", %dk RAM)\n", memory_size); break; default: printk(") bad memory size (%dk).\n", memory_size); kfree(dev->priv); return ENODEV; break; } lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE); lp->width = buswidth; dev->open = eexp_open; dev->stop = eexp_close; dev->hard_start_xmit = eexp_xmit; dev->get_stats = eexp_stats; dev->set_multicast_list = &eexp_set_multicast; ether_setup(dev); return 0;}/* * Read a word from the EtherExpress on-board serial EEPROM. * The EEPROM contains 64 words of 16 bits. */__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location)){ unsigned short cmd = 0x180|(location&0x7f); unsigned short rval = 0,wval = EC_CS|i586_RST; int i; outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl); for (i=0x100 ; i ; i>>=1 ) { if (cmd&i) wval |= EC_Wr; else wval &= ~EC_Wr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -