📄 eexpress.c
字号:
{ if ((jiffies-lp->init_time)>10) { unsigned short status = inw(ioaddr+SCB_STATUS); printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n", dev->name, status); eexp_hw_init586(dev); dev->tbusy = 0; mark_bh(NET_BH); } } } if (buf==NULL) { unsigned short status = inw(ioaddr+SCB_STATUS); unsigned short txstatus = eexp_hw_lasttxstat(dev); if (SCB_CUdead(status)) { printk(KERN_WARNING "%s: CU has died! status %04x %04x, attempting to restart...\n", dev->name, status, txstatus); lp->stats.tx_errors++; eexp_hw_txrestart(dev); } dev_tint(dev); outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ); dev_kfree_skb(buf, FREE_WRITE); return 0; } if (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; outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); eexp_hw_tx(dev,data,length); outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ); } dev_kfree_skb(buf, FREE_WRITE); outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_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. */static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs){ struct device *dev = irq2dev_map[irq]; struct net_local *lp; unsigned short ioaddr,status,ack_cmd; unsigned short old_rp,old_wp; if (dev==NULL) { printk(KERN_WARNING "net_interrupt(): irq %d for unknown device caught by EExpress\n",irq); return; }#if NET_DEBUG > 6 printk(KERN_DEBUG "%s: interrupt\n", dev->name);#endif dev->interrupt = 1; /* should this be reset on exit? */ lp = (struct net_local *)dev->priv; ioaddr = dev->base_addr; outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ); old_rp = inw(ioaddr+READ_PTR); old_wp = inw(ioaddr+WRITE_PTR); status = inw(ioaddr+SCB_STATUS); ack_cmd = SCB_ack(status); if (PRIV(dev)->started==0 && SCB_complete(status)) {#if NET_DEBUG > 4 printk(KERN_DEBUG "%s: SCBcomplete event received\n", dev->name);#endif while (SCB_CUstat(status)==2) status = inw_p(ioaddr+SCB_STATUS);#if NET_DEBUG > 4 printk(KERN_DEBUG "%s: CU went non-active (status = %08x)\n", dev->name, status);#endif PRIV(dev)->started=1; outw_p(lp->tx_link,ioaddr+SCB_CBL); outw_p(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA); ack_cmd |= SCB_CUstart | SCB_RUstart; } else if (PRIV(dev)->started) { unsigned short txstatus; txstatus = eexp_hw_lasttxstat(dev); } if (SCB_rxdframe(status)) { eexp_hw_rx(dev); } if ((PRIV(dev)->started&2)!=0 && SCB_RUstat(status)!=4) { printk(KERN_WARNING "%s: RU stopped status %04x, restarting...\n", dev->name,status); lp->stats.rx_errors++; eexp_hw_rxinit(dev); outw(PRIV(dev)->rx_buf_start,ioaddr+SCB_RFA); ack_cmd |= SCB_RUstart; } else if (PRIV(dev)->started==1 && SCB_RUstat(status)==4) PRIV(dev)->started|=2; outw(ack_cmd,ioaddr+SCB_CMD); outb(0,ioaddr+SIGNAL_CA); outw(old_rp,ioaddr+READ_PTR); outw(old_wp,ioaddr+WRITE_PTR); outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ); dev->interrupt = 0;#if NET_DEBUG > 6 printk(KERN_DEBUG "%s: leaving eexp_irq()\n", dev->name);#endif return;}/* * Hardware access functions *//* * Check all the receive buffers, and hand any received packets * to the upper levels. Basic sanity check on each frame * descriptor */ static void eexp_hw_rx(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; unsigned short old_wp = inw(ioaddr+WRITE_PTR); unsigned short old_rp = inw(ioaddr+READ_PTR); unsigned short rx_block = lp->rx_first; unsigned short boguscount = lp->num_rx_bufs;#if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);#endif while (outw(rx_block,ioaddr+READ_PTR),boguscount--) { unsigned short status = inw(ioaddr); unsigned short rfd_cmd = inw(ioaddr); unsigned short rx_next = inw(ioaddr); unsigned short pbuf = inw(ioaddr); unsigned short pkt_len; if (FD_Done(status)) { outw(pbuf,ioaddr+READ_PTR); pkt_len = inw(ioaddr); if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16 || (pkt_len & 0xc000)!=0xc000) { printk(KERN_WARNING "%s: Rx frame at %04x corrupted, status %04x, cmd %04x, " "next %04x, pbuf %04x, len %04x\n",dev->name,rx_block, status,rfd_cmd,rx_next,pbuf,pkt_len); boguscount++; 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,skb_put(skb,pkt_len),(pkt_len+1)>>1); skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; } outw(rx_block,ioaddr+WRITE_PTR); outw(0x0000,ioaddr); outw(0x0000,ioaddr); } rx_block = rx_next; } outw(old_rp,ioaddr+READ_PTR); outw(old_wp,ioaddr+WRITE_PTR);}/* * 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(struct device *dev, unsigned short *buf, unsigned short len){ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; unsigned short old_wp = inw(ioaddr+WRITE_PTR); outw(lp->tx_head,ioaddr+WRITE_PTR); outw(0x0000,ioaddr); outw(Cmd_INT|Cmd_Xmit,ioaddr); outw(lp->tx_head+0x08,ioaddr); outw(lp->tx_head+0x0e,ioaddr); outw(0x0000,ioaddr); outw(0x0000,ioaddr); outw(lp->tx_head+0x08,ioaddr); outw(0x8000|len,ioaddr); outw(-1,ioaddr); outw(lp->tx_head+0x16,ioaddr); outw(0,ioaddr); outsw(ioaddr,buf,(len+1)>>1); outw(lp->tx_tail+0x0c,ioaddr+WRITE_PTR); outw(lp->tx_head,ioaddr); 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; outw(old_wp,ioaddr+WRITE_PTR);}/* * Sanity check the suspected EtherExpress card * Read hardware address, reset card, size memory and * initialize buffer memory pointers. These should * probably be held in dev->priv, in case someone has 2 * differently configured cards in their box (Arghhh!) */static int eexp_hw_probe(struct device *dev, unsigned short ioaddr){ unsigned short hw_addr[3]; int i; unsigned char *chw_addr = (unsigned char *)hw_addr; printk("%s: EtherExpress at %#x, ",dev->name,ioaddr); 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; } dev->base_addr = ioaddr; for ( i=0 ; i<6 ; i++ ) dev->dev_addr[i] = chw_addr[5-i]; { char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0}; char *ifmap[]={"AUI", "BNC", "10baseT"}; enum iftype {AUI=0, BNC=1, TP=2}; unsigned short setupval = eexp_hw_readeeprom(ioaddr,0); dev->irq = irqmap[setupval>>13]; dev->if_port = !(setupval & 0x1000) ? AUI : eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TP : BNC; printk("IRQ %d, Interface %s, ",dev->irq,ifmap[dev->if_port]); outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ); outb(0,ioaddr+SET_IRQ); } dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (!dev->priv) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); eexp_hw_ASICrst(dev); { unsigned short i586mso = 0x023e; unsigned short old_wp,old_rp,old_a0,old_a1; unsigned short a0_0,a1_0,a0_1,a1_1; old_wp = inw(ioaddr+WRITE_PTR); old_rp = inw(ioaddr+READ_PTR); outw(0x8000+i586mso,ioaddr+READ_PTR); old_a1 = inw(ioaddr); outw(i586mso,ioaddr+READ_PTR); old_a0 = inw(ioaddr); outw(i586mso,ioaddr+WRITE_PTR); outw(0x55aa,ioaddr); outw(i586mso,ioaddr+READ_PTR); a0_0 = inw(ioaddr); outw(0x8000+i586mso,ioaddr+WRITE_PTR); outw(0x5a5a,ioaddr); outw(0x8000+i586mso,ioaddr+READ_PTR); a1_0 = inw(ioaddr); outw(i586mso,ioaddr+READ_PTR); a0_1 = inw(ioaddr); outw(i586mso,ioaddr+WRITE_PTR); outw(0x1234,ioaddr); outw(0x8000+i586mso,ioaddr+READ_PTR); a1_1 = inw(ioaddr); if ((a0_0 != a0_1) || (a1_0 != a1_1) || (a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) { printk("32k\n"); PRIV(dev)->rx_buf_end = 0x7ff6; PRIV(dev)->num_tx_bufs = 4; } else { printk("64k\n"); PRIV(dev)->num_tx_bufs = 8; PRIV(dev)->rx_buf_start = TX_BUF_START + (PRIV(dev)->num_tx_bufs*TX_BUF_SIZE); PRIV(dev)->rx_buf_end = 0xfff6; } outw(0x8000+i586mso,ioaddr+WRITE_PTR); outw(old_a1,ioaddr); outw(i586mso,ioaddr+WRITE_PTR); outw(old_a0,ioaddr); outw(old_wp,ioaddr+WRITE_PTR); outw(old_rp,ioaddr+READ_PTR); } if (net_debug) printk(version); 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 eeprom location (0-63?) */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; outb(wval,ioaddr+EEPROM_Ctrl); outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl); eeprom_delay(); outb(wval,ioaddr+EEPROM_Ctrl); eeprom_delay(); } wval &= ~EC_Wr; outb(wval,ioaddr+EEPROM_Ctrl); for ( i=0x8000 ; i ; i>>=1 ) { outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl); eeprom_delay(); if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd) rval |= i; outb(wval,ioaddr+EEPROM_Ctrl); eeprom_delay(); } wval &= ~EC_CS; outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl); eeprom_delay(); outb(wval,ioaddr+EEPROM_Ctrl); eeprom_delay(); return rval;}/* * Reap tx buffers and return last transmit status. * if ==0 then either: * a) we're not transmitting anything, so why are we here? * b) we've died. * otherwise, Stat_Busy(return) means we've still got some packets * to transmit, Stat_Done(return) means our buffers should be empty * again */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -