📄 depca.c
字号:
&lp->rx_ring[i].base); writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length); lp->rx_buff[i] = lp->sh_mem + offset; } for (i = 0; i <= lp->txRingMask; i++) { offset = lp->buffs_offset + (i + lp->rxRingMask+1)*TX_BUFF_SZ; writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base); lp->tx_buff[i] = lp->sh_mem + offset; } /* Set up the initialization block */ lp->init_block.rx_ring = (lp->device_ram_start + lp->rx_ring_offset) | lp->rx_rlen; lp->init_block.tx_ring = (lp->device_ram_start + lp->tx_ring_offset) | lp->tx_rlen; SetMulticastFilter(dev); for (i = 0; i < ETH_ALEN; i++) { lp->init_block.phys_addr[i] = dev->dev_addr[i]; } lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */}static void depca_tx_timeout (struct net_device *dev){ u_long ioaddr = dev->base_addr; printk ("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw (DEPCA_DATA)); STOP_DEPCA; depca_init_ring (dev); LoadCSRs (dev); dev->trans_start = jiffies; netif_wake_queue (dev); InitRestartDepca (dev);}/* ** Writes a socket buffer to TX descriptor ring and starts transmission */static int depca_start_xmit (struct sk_buff *skb, struct net_device *dev){ struct depca_private *lp = (struct depca_private *) dev->priv; u_long ioaddr = dev->base_addr; int status = 0; /* Transmitter timeout, serious problems. */ if (skb->len < 1) goto out; netif_stop_queue (dev); if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */ status = load_packet (dev, skb); if (!status) { /* Trigger an immediate send demand. */ outw (CSR0, DEPCA_ADDR); outw (INEA | TDMD, DEPCA_DATA); dev->trans_start = jiffies; dev_kfree_skb (skb); } if (TX_BUFFS_AVAIL) netif_start_queue (dev); } else status = -1;out: return status;}/*** The DEPCA interrupt handler. */static void depca_interrupt (int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id; struct depca_private *lp; s16 csr0, nicsr; u_long ioaddr; if (dev == NULL) { printk ("depca_interrupt(): irq %d for unknown device.\n", irq); return; } lp = (struct depca_private *) dev->priv; ioaddr = dev->base_addr; spin_lock (&lp->lock); /* mask the DEPCA board interrupts and turn on the LED */ nicsr = inb (DEPCA_NICSR); nicsr |= (IM | LED); outb (nicsr, DEPCA_NICSR); outw (CSR0, DEPCA_ADDR); csr0 = inw (DEPCA_DATA); /* Acknowledge all of the current interrupt sources ASAP. */ outw (csr0 & INTE, DEPCA_DATA); if (csr0 & RINT) /* Rx interrupt (packet arrived) */ depca_rx (dev); if (csr0 & TINT) /* Tx interrupt (packet sent) */ depca_tx (dev); /* Any resources available? */ if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) { netif_wake_queue (dev); } /* Unmask the DEPCA board interrupts and turn off the LED */ nicsr = (nicsr & ~IM & ~LED); outb (nicsr, DEPCA_NICSR); spin_unlock (&lp->lock);}static intdepca_rx(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int i, entry; s32 status; for (entry=lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry=lp->rx_new){ status = readl(&lp->rx_ring[entry].base) >> 16 ; if (status & R_STP) { /* Remember start of frame */ lp->rx_old = entry; } if (status & R_ENP) { /* Valid frame status */ if (status & R_ERR) { /* There was an error. */ lp->stats.rx_errors++; /* Update the error stats. */ if (status & R_FRAM) lp->stats.rx_frame_errors++; if (status & R_OFLO) lp->stats.rx_over_errors++; if (status & R_CRC) lp->stats.rx_crc_errors++; if (status & R_BUFF) lp->stats.rx_fifo_errors++; } else { short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4; struct sk_buff *skb; skb = dev_alloc_skb(pkt_len+2); if (skb != NULL) { unsigned char *buf; skb_reserve(skb,2); /* 16 byte align the IP header */ buf = skb_put(skb,pkt_len); skb->dev = dev; if (entry < lp->rx_old) { /* Wrapped buffer */ len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ; memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len); memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len-len); } else { /* Linear buffer */ memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len); } /* ** Notify the upper protocol layers that there is another ** packet to handle */ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* ** Update stats */ lp->stats.rx_packets++; for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) { if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) { lp->pktStats.bins[i]++; i = DEPCA_PKT_STAT_SZ; } } if (buf[0] & 0x01) { /* Multicast/Broadcast */ if ((*(s16 *)&buf[0] == -1) && (*(s16 *)&buf[2] == -1) && (*(s16 *)&buf[4] == -1)) { lp->pktStats.broadcast++; } else { lp->pktStats.multicast++; } } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) && (*(s16 *)&buf[2] == *(s16 *)&dev->dev_addr[2]) && (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { lp->pktStats.unicast++; } lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ if (lp->pktStats.bins[0] == 0) { /* Reset counters */ memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats)); } } else { printk("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; } } /* Change buffer ownership for this last frame, back to the adapter */ for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) { writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base); } writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base); } /* ** Update entry information */ lp->rx_new = (++lp->rx_new) & lp->rxRingMask; } return 0;}/*** Buffer sent - check for buffer errors.*/static intdepca_tx(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int entry; s32 status; u_long ioaddr = dev->base_addr; for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) { status = readl(&lp->tx_ring[entry].base) >> 16 ; if (status < 0) { /* Packet not yet sent! */ break; } else if (status & T_ERR) { /* An error occurred. */ status = readl(&lp->tx_ring[entry].misc); lp->stats.tx_errors++; if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++; if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++; if (status & TMD3_LCOL) lp->stats.tx_window_errors++; if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++; if (status & (TMD3_BUFF | TMD3_UFLO)) { /* Trigger an immediate send demand. */ outw(CSR0, DEPCA_ADDR); outw(INEA | TDMD, DEPCA_DATA); } } else if (status & (T_MORE | T_ONE)) { lp->stats.collisions++; } else { lp->stats.tx_packets++; } /* Update all the pointers */ lp->tx_old = (++lp->tx_old) & lp->txRingMask; } return 0;}static intdepca_close(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; s16 nicsr; u_long ioaddr = dev->base_addr; netif_stop_queue(dev); outw(CSR0, DEPCA_ADDR); if (depca_debug > 1) { printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA)); } /* ** We stop the DEPCA here -- it occasionally polls ** memory if we don't. */ outw(STOP, DEPCA_DATA); /* ** Give back the ROM in case the user wants to go to DOS */ if (lp->adapter != DEPCA) { nicsr = inb(DEPCA_NICSR); nicsr &= ~SHE; outb(nicsr, DEPCA_NICSR); } /* ** Free the associated irq */ free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return 0;}static void LoadCSRs(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ outw((u16)lp->device_ram_start, DEPCA_DATA); outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ outw((u16)(lp->device_ram_start >> 16), DEPCA_DATA); outw(CSR3, DEPCA_ADDR); /* ALE control */ outw(ACON, DEPCA_DATA); outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */ return;}static int InitRestartDepca(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; int i, status=0; /* Copy the shadow init_block to shared memory */ memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init)); outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ outw(INIT, DEPCA_DATA); /* initialize DEPCA */ /* wait for lance to complete initialisation */ for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); if (i!=100) { /* clear IDON by writing a "1", enable interrupts and start lance */ outw(IDON | INEA | STRT, DEPCA_DATA); if (depca_debug > 2) { printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA)); } } else { printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA)); status = -1; } return status;}static struct net_device_stats *depca_get_stats(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; /* Null body since there is no framing error counter */ return &lp->stats;}/*** Set or clear the multicast filter for this adaptor.*/static voidset_multicast_list(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; if (dev) { netif_stop_queue(dev); while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ STOP_DEPCA; /* Temporarily stop the depca. */ depca_init_ring(dev); /* Initialize the descriptor rings */ if (dev->flags & IFF_PROMISC) { /* Set promiscuous mode */ lp->init_block.mode |= PROM; } else { SetMulticastFilter(dev); lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ } LoadCSRs(dev); /* Reload CSR3 */ InitRestartDepca(dev); /* Resume normal operation. */ netif_start_queue(dev); /* Unlock the TX ring */ }}/*** Calculate the hash code and update the logical address filter** from a list of ethernet multicast addresses.** Big endian crc one liner is mine, all mine, ha ha ha ha!** LANCE calculates its hash codes big endian.*/static void SetMulticastFilter(struct net_device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; struct dev_mc_list *dmi=dev->mc_list; char *addrs; int i, j, bit, byte; u16 hashcode; s32 crc, poly = CRC_POLYNOMIAL_BE; if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */ for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -