📄 epic100.c
字号:
#ifndef final_version if (epic_debug > 1) printk("%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus);#endif ep->stats.tx_errors++; if (txstatus & 0x1050) ep->stats.tx_aborted_errors++; if (txstatus & 0x0008) ep->stats.tx_carrier_errors++; if (txstatus & 0x0040) ep->stats.tx_window_errors++; if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;#ifdef ETHER_STATS if (txstatus & 0x1000) ep->stats.collisions16++;#endif } else {#ifdef ETHER_STATS if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++;#endif ep->stats.collisions += (txstatus >> 8) & 15; ep->stats.tx_packets++; } /* Free the original skb. */ DEV_FREE_SKB(ep->tx_skbuff[entry]); ep->tx_skbuff[entry] = 0; }#ifndef final_version if (ep->cur_tx - dirty_tx > TX_RING_SIZE) { printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, ep->cur_tx, ep->tx_full); dirty_tx += TX_RING_SIZE; }#endif if (ep->tx_full && dev->tbusy && dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; clear_bit(0, (void*)&dev->tbusy); mark_bh(NET_BH); } ep->dirty_tx = dirty_tx; } /* Check uncommon events all at once. */ if (status & (CntFull | TxUnderrun | RxOverflow | PCIBusErr170 | PCIBusErr175)) { if (status == 0xffffffff) /* Chip failed or removed (CardBus). */ break; /* Always update the error counts to avoid overhead later. */ ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); if (status & TxUnderrun) { /* Tx FIFO underflow. */ ep->stats.tx_fifo_errors++; outl(1536, ioaddr + TxThresh); /* Restart the transmit process. */ outl(0x0080, ioaddr + COMMAND); } if (status & RxOverflow) { /* Missed a Rx frame. */ ep->stats.rx_errors++; } if (status & PCIBusErr170) { printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n", dev->name, status); epic_pause(dev); epic_restart(dev); } /* Clear all error sources. */ outl(status & 0x7f18, ioaddr + INTSTAT); } if (--boguscnt < 0) { printk(KERN_ERR "%s: Too much work at interrupt, " "IntrStatus=0x%8.8x.\n", dev->name, status); /* Clear all interrupt sources. */ outl(0x0001ffff, ioaddr + INTSTAT); break; } } while (1); if (epic_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, inl(ioaddr + INTSTAT));#if defined(__i386__) clear_bit(0, (void*)&dev->interrupt);#else dev->interrupt = 0;#endif return;}static int epic_rx(struct device *dev){ struct epic_private *ep = (struct epic_private *)dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; int work_done = 0; if (epic_debug > 4) printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].status); /* If we own the next entry, it's a new packet. Send it up. */ while (ep->rx_ring[entry].status >= 0 && ep->rx_skbuff[entry]) { int status = ep->rx_ring[entry].status; if (epic_debug > 4) printk(KERN_DEBUG " epic_rx() status was %8.8x.\n", status); if (status & 0x2006) { if (status & 0x2000) { printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " "multiple buffers, status %4.4x!\n", dev->name, status); ep->stats.rx_length_errors++; } else if (status & 0x0006) /* Rx Frame errors are counted in hardware. */ ep->stats.rx_errors++; } else { /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ short pkt_len = ep->rx_ring[entry].rxlength - 4; struct sk_buff *skb; /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */#if 1 /* USE_IP_COPYSUM */ eth_copy_and_sum(skb, bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len, 0); skb_put(skb, pkt_len);#else memcpy(skb_put(skb, pkt_len), bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len);#endif } else { skb_put(skb = ep->rx_skbuff[entry], pkt_len); ep->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); ep->stats.rx_packets++; /* rx_bytes counting -- Nolan Leake */ ep->stats.rx_bytes += pkt_len; } work_done++; entry = (++ep->cur_rx) % RX_RING_SIZE; } /* Refill the Rx ring buffers. */ for (; ep->cur_rx - ep->dirty_rx > 0; ep->dirty_rx++) { entry = ep->dirty_rx % RX_RING_SIZE; if (ep->rx_skbuff[entry] == NULL) { struct sk_buff *skb; skb = ep->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ ep->rx_ring[entry].bufaddr = virt_to_bus(skb->tail); work_done++; } ep->rx_ring[entry].status = 0x8000; } return work_done;}static int epic_close(struct device *dev){ long ioaddr = dev->base_addr; struct epic_private *ep = (struct epic_private *)dev->priv; int i; dev->start = 0; dev->tbusy = 1; if (epic_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + INTSTAT)); /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + INTMASK); /* Stop the chip's Tx and Rx DMA processes. */ outw(0x0061, ioaddr + COMMAND); /* Update the error counts. */ ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); del_timer(&ep->timer); free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = ep->rx_skbuff[i]; ep->rx_skbuff[i] = 0; ep->rx_ring[i].status = 0; /* Not owned by Epic chip. */ ep->rx_ring[i].buflength = 0; ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ if (skb) {#if LINUX_VERSION_CODE < 0x20100 skb->free = 1;#endif DEV_FREE_SKB(skb); } } for (i = 0; i < TX_RING_SIZE; i++) { if (ep->tx_skbuff[i]) DEV_FREE_SKB(ep->tx_skbuff[i]); ep->tx_skbuff[i] = 0; } /* Green! Leave the chip in low-power mode. */ outl(0x0008, ioaddr + GENCTL); MOD_DEC_USE_COUNT; return 0;}static struct net_device_stats *epic_get_stats(struct device *dev){ struct epic_private *ep = (struct epic_private *)dev->priv; long ioaddr = dev->base_addr; if (dev->start) { /* Update the error counts. */ ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); } return &ep->stats;}/* Set or clear the multicast filter for this adaptor. Note that we only use exclusion around actually queueing the new frame, not around filling ep->setup_frame. This is non-deterministic when re-entered but still correct. *//* The little-endian AUTODIN II ethernet CRC calculation. N.B. Do not use for bulk data, use a table-based routine instead. This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){ unsigned int crc = 0xffffffff; /* Initial value. */ while(--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 8; --bit >= 0; current_octet >>= 1) { if ((crc ^ current_octet) & 1) { crc >>= 1; crc ^= ethernet_polynomial_le; } else crc >>= 1; } } return crc;}static void set_rx_mode(struct device *dev){ long ioaddr = dev->base_addr; struct epic_private *ep = (struct epic_private *)dev->priv; unsigned char mc_filter[8]; /* Multicast hash filter */ int i; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ outl(0x002C, ioaddr + RxCtrl); /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); memset(mc_filter, 0xff, sizeof(mc_filter)); } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) { /* There is apparently a chip bug, so the multicast filter is never enabled. */ /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outl(0x000C, ioaddr + RxCtrl); } else if (dev->mc_count == 0) { outl(0x0004, ioaddr + RxCtrl); return; } else { /* Never executed, for now. */ struct dev_mc_list *mclist; memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, mc_filter); } /* ToDo: perhaps we need to stop the Tx and Rx process here? */ if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) { for (i = 0; i < 4; i++) outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4); memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter)); } return;}static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd){ long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ if (! dev->start) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); if (! dev->start) {#ifdef notdef outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);#endif } return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!suser()) return -EPERM; if (! dev->start) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); if (! dev->start) {#ifdef notdef outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);#endif } return 0; default: return -EOPNOTSUPP; }}#ifdef CARDBUS#include <pcmcia/driver_ops.h>static dev_node_t *epic_attach(dev_locator_t *loc){ struct device *dev; u16 dev_id; u32 io; u8 bus, devfn, irq; if (loc->bus != LOC_PCI) return NULL; bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn); pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); io &= ~3; if (io == 0 || irq == 0) { printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not " "assigned an %s.\n" KERN_ERR " It will not be activated.\n", io == 0 ? "I/O address" : "IRQ"); return NULL; } dev = epic_probe1(bus, devfn, NULL, io, irq, 2, -1); if (dev) { dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); strcpy(node->dev_name, dev->name); node->major = node->minor = 0; node->next = NULL; MOD_INC_USE_COUNT; return node; } return NULL;}static void epic_suspend(dev_node_t *node){ struct device **devp, **next; printk(KERN_INFO "epic_suspend(%s)\n", node->dev_name); for (devp = &root_epic_dev; *devp; devp = next) { next = &((struct epic_private *)(*devp)->priv)->next_module; if (strcmp((*devp)->name, node->dev_name) == 0) break; } if (*devp) { long ioaddr = (*devp)->base_addr; epic_pause(*devp); /* Put the chip into low-power mode. */ outl(0x0008, ioaddr + GENCTL); }}static void epic_resume(dev_node_t *node){ struct device **devp, **next; printk(KERN_INFO "epic_resume(%s)\n", node->dev_name); for (devp = &root_epic_dev; *devp; devp = next) { next = &((struct epic_private *)(*devp)->priv)->next_module; if (strcmp((*devp)->name, node->dev_name) == 0) break; } if (*devp) { epic_restart(*devp); }}static void epic_detach(dev_node_t *node){ struct device **devp, **next; printk(KERN_INFO "epic_detach(%s)\n", node->dev_name); for (devp = &root_epic_dev; *devp; devp = next) { next = &((struct epic_private *)(*devp)->priv)->next_module; if (strcmp((*devp)->name, node->dev_name) == 0) break; } if (*devp) { unregister_netdev(*devp); kfree(*devp); *devp = *next; kfree(node); MOD_DEC_USE_COUNT; }}struct driver_operations epic_ops = { "epic_cb", epic_attach, epic_suspend, epic_resume, epic_detach};#endif /* Cardbus support */#ifdef MODULEint init_module(void){ if (epic_debug) printk(KERN_INFO "%s", version);#ifdef CARDBUS register_driver(&epic_ops); return 0;#else return epic100_probe(0);#endif}void cleanup_module(void){ struct device *next_dev;#ifdef CARDBUS unregister_driver(&epic_ops);#endif /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_epic_dev) { struct epic_private *ep = (struct epic_private *)root_epic_dev->priv; next_dev = ep->next_module; unregister_netdev(root_epic_dev); release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE); kfree(root_epic_dev); root_epic_dev = next_dev; kfree(ep); }}#endif /* MODULE *//* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -