📄 lance.c
字号:
}static voidlance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit){ struct lance_private *lp = dev->priv; if (must_reinit || (chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) { lance_purge_ring(dev); lance_init_ring(dev, GFP_ATOMIC); } outw(0x0000, dev->base_addr + LANCE_ADDR); outw(csr0_bits, dev->base_addr + LANCE_DATA);}static void lance_tx_timeout (struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; int ioaddr = dev->base_addr; 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 if (lance_debug > 3) { int i; printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (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->trans_start = jiffies; netif_wake_queue (dev);}static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct lance_private *lp = dev->priv; int ioaddr = dev->base_addr; int entry; unsigned long flags; spin_lock_irqsave(&lp->devlock, flags); 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); } /* 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; lp->stats.tx_bytes += skb->len; /* 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++; /* Trigger an immediate send poll. */ outw(0x0000, ioaddr+LANCE_ADDR); outw(0x0048, ioaddr+LANCE_DATA); dev->trans_start = jiffies; if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE) netif_stop_queue(dev); spin_unlock_irqrestore(&lp->devlock, flags); return 0;}/* The LANCE interrupt handler. */static voidlance_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct net_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 = dev->priv; spin_lock (&lp->devlock); 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_irq(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=%s.\n", dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? "yes" : "no"); dirty_tx += TX_RING_SIZE; }#endif /* if the ring is no longer full, accept more packets */ if (netif_queue_stopped(dev) && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) netif_wake_queue (dev); 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)); spin_unlock (&lp->devlock);}static intlance_rx(struct net_device *dev){ struct lance_private *lp = 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); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes+=pkt_len; } } /* 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 net_device *dev){ int ioaddr = dev->base_addr; struct lance_private *lp = dev->priv; netif_stop_queue (dev); 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); lance_purge_ring(dev); return 0;}static struct net_device_stats *lance_get_stats(struct net_device *dev){ struct lance_private *lp = dev->priv; if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { short ioaddr = dev->base_addr; short saved_addr; unsigned long flags; spin_lock_irqsave(&lp->devlock, flags); 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); spin_unlock_irqrestore(&lp->devlock, flags); } return &lp->stats;}/* Set or clear the multicast filter for this adaptor. */static void set_multicast_list(struct net_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 + -