📄 lance.c
字号:
int entry; unsigned long flags; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) return 1; outw(0, ioaddr+LANCE_ADDR); printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, inw(ioaddr+LANCE_DATA)); outw(0x0004, ioaddr+LANCE_DATA); lp->stats.tx_errors++;#ifndef final_version { int i; printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", lp->cur_rx); for (i = 0 ; i < RX_RING_SIZE; i++) printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, lp->rx_ring[i].msg_length); for (i = 0 ; i < TX_RING_SIZE; i++) printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", lp->tx_ring[i].base, -lp->tx_ring[i].length, lp->tx_ring[i].misc); printk("\n"); }#endif lance_restart(dev, 0x0043, 1); dev->tbusy=0; dev->trans_start = jiffies; return 0; } if (lance_debug > 3) { outw(0x0000, ioaddr+LANCE_ADDR); printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, inw(ioaddr+LANCE_DATA)); outw(0x0000, ioaddr+LANCE_DATA); } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } if (test_and_set_bit(0, (void*)&lp->lock) != 0) { if (lance_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ return 1; } /* Fill in a Tx ring entry */ /* Mask to ring buffer boundary. */ entry = lp->cur_tx & TX_RING_MOD_MASK; /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ /* The old LANCE chips doesn't automatically pad buffers to min. size. */ if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) { lp->tx_ring[entry].length = -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); } else lp->tx_ring[entry].length = -skb->len; lp->tx_ring[entry].misc = 0x0000; /* If any part of this buffer is >16M we must copy it to a low-memory buffer. */ if ((u32)virt_to_bus(skb->data) + skb->len > 0x01000000) { if (lance_debug > 5) printk("%s: bouncing a high-memory packet (%#x).\n", dev->name, (u32)virt_to_bus(skb->data)); memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); lp->tx_ring[entry].base = ((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000; dev_kfree_skb(skb); } else { lp->tx_skbuff[entry] = skb; lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000; } lp->cur_tx++; lp->stats.tx_bytes += skb->len; /* Trigger an immediate send poll. */ outw(0x0000, ioaddr+LANCE_ADDR); outw(0x0048, ioaddr+LANCE_DATA); dev->trans_start = jiffies; save_flags(flags); cli(); lp->lock = 0; if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) dev->tbusy=0; else lp->tx_full = 1; restore_flags(flags); return 0;}/* The LANCE interrupt handler. */static voidlance_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct device *dev = dev_id; struct lance_private *lp; int csr0, ioaddr, boguscnt=10; int must_restart; if (dev == NULL) { printk ("lance_interrupt(): irq %d for unknown device.\n", irq); return; } ioaddr = dev->base_addr; lp = (struct lance_private *)dev->priv; if (dev->interrupt) printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; outw(0x00, dev->base_addr + LANCE_ADDR); while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600 && --boguscnt >= 0) { /* Acknowledge all of the current interrupt sources ASAP. */ outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA); must_restart = 0; if (lance_debug > 5) printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", dev->name, csr0, inw(dev->base_addr + LANCE_DATA)); if (csr0 & 0x0400) /* Rx interrupt */ lance_rx(dev); if (csr0 & 0x0200) { /* Tx-done interrupt */ int dirty_tx = lp->dirty_tx; while (dirty_tx < lp->cur_tx) { int entry = dirty_tx & TX_RING_MOD_MASK; int status = lp->tx_ring[entry].base; if (status < 0) break; /* It still hasn't been Txed */ lp->tx_ring[entry].base = 0; if (status & 0x40000000) { /* There was an major error, log it. */ int err_status = lp->tx_ring[entry].misc; lp->stats.tx_errors++; if (err_status & 0x0400) lp->stats.tx_aborted_errors++; if (err_status & 0x0800) lp->stats.tx_carrier_errors++; if (err_status & 0x1000) lp->stats.tx_window_errors++; if (err_status & 0x4000) { /* Ackk! On FIFO errors the Tx unit is turned off! */ lp->stats.tx_fifo_errors++; /* Remove this verbosity later! */ printk("%s: Tx FIFO error! Status %4.4x.\n", dev->name, csr0); /* Restart the chip. */ must_restart = 1; } } else { if (status & 0x18000000) lp->stats.collisions++; lp->stats.tx_packets++; } /* We must free the original skb if it's not a data-only copy in the bounce buffer. */ if (lp->tx_skbuff[entry]) { dev_kfree_skb(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; } dirty_tx++; }#ifndef final_version if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += TX_RING_SIZE; }#endif if (lp->tx_full && dev->tbusy && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; dev->tbusy = 0; mark_bh(NET_BH); } lp->dirty_tx = dirty_tx; } /* Log misc errors. */ if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & 0x0800) { printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); /* Restart the chip. */ must_restart = 1; } if (must_restart) { /* stop the chip to clear the error condition, then restart */ outw(0x0000, dev->base_addr + LANCE_ADDR); outw(0x0004, dev->base_addr + LANCE_DATA); lance_restart(dev, 0x0002, 0); } } /* Clear any other interrupt, and set interrupt enable. */ outw(0x0000, dev->base_addr + LANCE_ADDR); outw(0x7940, dev->base_addr + LANCE_DATA); if (lance_debug > 4) printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, inw(ioaddr + LANCE_ADDR), inw(dev->base_addr + LANCE_DATA)); dev->interrupt = 0; return;}static intlance_rx(struct device *dev){ struct lance_private *lp = (struct lance_private *)dev->priv; int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; /* If we own the next entry, it's a new packet. Send it up. */ while (lp->rx_ring[entry].base >= 0) { int status = lp->rx_ring[entry].base >> 24; if (status != 0x03) { /* There was an error. */ /* There is a tricky error noted by John Murphy, <murf@perftech.com> to Russ Nelson: Even with full-sized buffers it's possible for a jabber packet to use two buffers, with only the last correctly noting the error. */ if (status & 0x01) /* Only count a general error at the */ lp->stats.rx_errors++; /* end of a packet.*/ if (status & 0x20) lp->stats.rx_frame_errors++; if (status & 0x10) lp->stats.rx_over_errors++; if (status & 0x08) lp->stats.rx_crc_errors++; if (status & 0x04) lp->stats.rx_fifo_errors++; lp->rx_ring[entry].base &= 0x03ffffff; } else { /* Malloc up new buffer, compatible with net3. */ short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4; struct sk_buff *skb; if(pkt_len<60) { printk("%s: Runt packet!\n",dev->name); lp->stats.rx_errors++; } else { skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); for (i=0; i < RX_RING_SIZE; i++) if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0) break; if (i > RX_RING_SIZE -2) { lp->stats.rx_dropped++; lp->rx_ring[entry].base |= 0x80000000; lp->cur_rx++; } break; } skb->dev = dev; skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)), pkt_len,0); lp->stats.rx_bytes+=skb->len; skb->protocol=eth_type_trans(skb,dev); lp->stats.rx_packets++; netif_rx(skb); } } /* The docs say that the buffer length isn't touched, but Andrew Boyd of QNX reports that some revs of the 79C965 clear it. */ lp->rx_ring[entry].buf_length = -PKT_BUF_SZ; lp->rx_ring[entry].base |= 0x80000000; entry = (++lp->cur_rx) & RX_RING_MOD_MASK; } /* We should check that at least two ring entries are free. If not, we should free one and mark stats->rx_dropped++. */ return 0;}static intlance_close(struct device *dev){ int ioaddr = dev->base_addr; struct lance_private *lp = (struct lance_private *)dev->priv; int i; dev->start = 0; dev->tbusy = 1; if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { outw(112, ioaddr+LANCE_ADDR); lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA); } outw(0, ioaddr+LANCE_ADDR); if (lance_debug > 1) printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(ioaddr+LANCE_DATA)); /* We stop the LANCE here -- it occasionally polls memory if we don't. */ outw(0x0004, ioaddr+LANCE_DATA); if (dev->dma != 4) { unsigned long flags=claim_dma_lock(); disable_dma(dev->dma); release_dma_lock(flags); } free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx and Tx queues. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = lp->rx_skbuff[i]; lp->rx_skbuff[i] = 0; lp->rx_ring[i].base = 0; /* Not owned by LANCE chip. */ if (skb) dev_kfree_skb(skb); } for (i = 0; i < TX_RING_SIZE; i++) { if (lp->tx_skbuff[i]) dev_kfree_skb(lp->tx_skbuff[i]); lp->tx_skbuff[i] = 0; } MOD_DEC_USE_COUNT; return 0;}static struct net_device_stats *lance_get_stats(struct device *dev){ struct lance_private *lp = (struct lance_private *)dev->priv; short ioaddr = dev->base_addr; short saved_addr; unsigned long flags; if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { save_flags(flags); cli(); saved_addr = inw(ioaddr+LANCE_ADDR); outw(112, ioaddr+LANCE_ADDR); lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA); outw(saved_addr, ioaddr+LANCE_ADDR); restore_flags(flags); } return &lp->stats;}/* Set or clear the multicast filter for this adaptor. */static void set_multicast_list(struct device *dev){ short ioaddr = dev->base_addr; outw(0, ioaddr+LANCE_ADDR); outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */ if (dev->flags&IFF_PROMISC) { /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); outw(15, ioaddr+LANCE_ADDR); outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */ } else { short multicast_table[4]; int i; int num_addrs=dev->mc_count; if(dev->flags&IFF_ALLMULTI) num_addrs=1; /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */ memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table)); for (i = 0; i < 4; i++) { outw(8 + i, ioaddr+LANCE_ADDR); outw(multicast_table[i], ioaddr+LANCE_DATA); } outw(15, ioaddr+LANCE_ADDR); outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */ } lance_restart(dev, 0x0142, 0); /* Resume normal operation */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -