📄 bmac.c
字号:
}static voidbmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp){ void *vaddr; unsigned long baddr; unsigned long len; len = skb->len; vaddr = skb->data; baddr = virt_to_bus(vaddr); dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);}static voidbmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp){ unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf; dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0);}/* Bit-reverse one byte of an ethernet hardware address. */static unsigned charbitrev(unsigned char b){ int d = 0, i; for (i = 0; i < 8; ++i, b >>= 1) d = (d << 1) | (b & 1); return d;}static voidbmac_init_tx_ring(struct bmac_data *bp){ volatile struct dbdma_regs *td = bp->tx_dma; memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd)); bp->tx_empty = 0; bp->tx_fill = 0; bp->tx_fullup = 0; /* put a branch at the end of the tx command list */ dbdma_setcmd(&bp->tx_cmds[N_TX_RING], (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds)); /* reset tx dma */ dbdma_reset(td); out_le32(&td->wait_sel, 0x00200020); out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));}static intbmac_init_rx_ring(struct bmac_data *bp){ volatile struct dbdma_regs *rd = bp->rx_dma; int i; struct sk_buff *skb; /* initialize list of sk_buffs for receiving and set up recv dma */ memset((char *)bp->rx_cmds, 0, (N_RX_RING + 1) * sizeof(struct dbdma_cmd)); for (i = 0; i < N_RX_RING; i++) { if ((skb = bp->rx_bufs[i]) == NULL) { bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); if (skb != NULL) skb_reserve(skb, 2); } bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); } bp->rx_empty = 0; bp->rx_fill = i; /* Put a branch back to the beginning of the receive command list */ dbdma_setcmd(&bp->rx_cmds[N_RX_RING], (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds)); /* start rx dma */ dbdma_reset(rd); out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds)); return 1;}static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev){ struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *td = bp->tx_dma; int i; /* see if there's a free slot in the tx ring */ /* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */ /* bp->tx_empty, bp->tx_fill)); */ i = bp->tx_fill + 1; if (i >= N_TX_RING) i = 0; if (i == bp->tx_empty) { netif_stop_queue(dev); bp->tx_fullup = 1; XXDEBUG(("bmac_transmit_packet: tx ring full\n")); return -1; /* can't take it at the moment */ } dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0); bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill]); bp->tx_bufs[bp->tx_fill] = skb; bp->tx_fill = i; bp->stats.tx_bytes += skb->len; dbdma_continue(td); return 0;}static int rxintcount;static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_cmd *cp; int i, nb, stat; struct sk_buff *skb; unsigned int residual; int last; unsigned long flags; save_flags(flags); cli(); if (++rxintcount < 10) { XXDEBUG(("bmac_rxdma_intr\n")); } last = -1; i = bp->rx_empty; while (1) { cp = &bp->rx_cmds[i]; stat = ld_le16(&cp->xfer_status); residual = ld_le16(&cp->res_count); if ((stat & ACTIVE) == 0) break; nb = RX_BUFLEN - residual - 2; if (nb < (ETHERMINPACKET - ETHERCRC)) { skb = NULL; bp->stats.rx_length_errors++; bp->stats.rx_errors++; } else { skb = bp->rx_bufs[i]; bp->rx_bufs[i] = NULL; } if (skb != NULL) { nb -= ETHERCRC; skb_put(skb, nb); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; ++bp->stats.rx_packets; bp->stats.rx_bytes += nb; } else { ++bp->stats.rx_dropped; } dev->last_rx = jiffies; if ((skb = bp->rx_bufs[i]) == NULL) { bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); if (skb != NULL) skb_reserve(bp->rx_bufs[i], 2); } bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); st_le16(&cp->res_count, 0); st_le16(&cp->xfer_status, 0); last = i; if (++i >= N_RX_RING) i = 0; } if (last != -1) { bp->rx_fill = last; bp->rx_empty = i; } restore_flags(flags); dbdma_continue(rd); if (rxintcount < 10) { XXDEBUG(("bmac_rxdma_intr done\n")); }}static int txintcount;static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_cmd *cp; int stat; unsigned long flags; save_flags(flags); cli(); if (txintcount++ < 10) { XXDEBUG(("bmac_txdma_intr\n")); } /* del_timer(&bp->tx_timeout); */ /* bp->timeout_active = 0; */ while (1) { cp = &bp->tx_cmds[bp->tx_empty]; stat = ld_le16(&cp->xfer_status); if (txintcount < 10) { XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat)); } if (!(stat & ACTIVE)) { /* * status field might not have been filled by DBDMA */ if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr))) break; } if (bp->tx_bufs[bp->tx_empty]) { ++bp->stats.tx_packets; dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]); } bp->tx_bufs[bp->tx_empty] = NULL; bp->tx_fullup = 0; netif_wake_queue(dev); if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0; if (bp->tx_empty == bp->tx_fill) break; } restore_flags(flags); if (txintcount < 10) { XXDEBUG(("bmac_txdma_intr done->bmac_start\n")); } bmac_start(dev);}static struct net_device_stats *bmac_stats(struct net_device *dev){ struct bmac_data *p = (struct bmac_data *) dev->priv; return &p->stats;}#ifndef SUNHME_MULTICAST/* Real fast bit-reversal algorithm, 6-bit values */static int reverse6[64] = { 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38, 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c, 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a, 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e, 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39, 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d, 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b, 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f};static unsigned intcrc416(unsigned int curval, unsigned short nxtval){ register unsigned int counter, cur = curval, next = nxtval; register int high_crc_set, low_data_set; /* Swap bytes */ next = ((next & 0x00FF) << 8) | (next >> 8); /* Compute bit-by-bit */ for (counter = 0; counter < 16; ++counter) { /* is high CRC bit set? */ if ((cur & 0x80000000) == 0) high_crc_set = 0; else high_crc_set = 1; cur = cur << 1; if ((next & 0x0001) == 0) low_data_set = 0; else low_data_set = 1; next = next >> 1; /* do the XOR */ if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY; } return cur;}static unsigned intbmac_crc(unsigned short *address){ unsigned int newcrc; XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2])); newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */ newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */ newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */ return(newcrc);}/* * Add requested mcast addr to BMac's hash table filter. * */static voidbmac_addhash(struct bmac_data *bp, unsigned char *addr){ unsigned int crc; unsigned short mask; if (!(*addr)) return; crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ if (bp->hash_use_count[crc]++) return; /* This bit is already set */ mask = crc % 16; mask = (unsigned char)1 << mask; bp->hash_use_count[crc/16] |= mask;}static voidbmac_removehash(struct bmac_data *bp, unsigned char *addr){ unsigned int crc; unsigned char mask; /* Now, delete the address from the filter copy, as indicated */ crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */ if (--bp->hash_use_count[crc]) return; /* That bit is still in use */ mask = crc % 16; mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */ bp->hash_table_mask[crc/16] &= mask;}/* * Sync the adapter with the software copy of the multicast mask * (logical address filter). */static voidbmac_rx_off(struct net_device *dev){ unsigned short rx_cfg; rx_cfg = bmread(dev, RXCFG); rx_cfg &= ~RxMACEnable; bmwrite(dev, RXCFG, rx_cfg); do { rx_cfg = bmread(dev, RXCFG); } while (rx_cfg & RxMACEnable);}unsigned shortbmac_rx_on(struct net_device *dev, int hash_enable, int promisc_enable){ unsigned short rx_cfg; rx_cfg = bmread(dev, RXCFG); rx_cfg |= RxMACEnable; if (hash_enable) rx_cfg |= RxHashFilterEnable; else rx_cfg &= ~RxHashFilterEnable; if (promisc_enable) rx_cfg |= RxPromiscEnable; else rx_cfg &= ~RxPromiscEnable; bmwrite(dev, RXRST, RxResetValue); bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); bmwrite(dev, RXCFG, rx_cfg ); return rx_cfg;}static voidbmac_update_hash_table_mask(struct net_device *dev, struct bmac_data *bp){ bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */ bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */ bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */ bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */}#if 0static voidbmac_add_multi(struct net_device *dev, struct bmac_data *bp, unsigned char *addr){ /* XXDEBUG(("bmac: enter bmac_add_multi\n")); */ bmac_addhash(bp, addr); bmac_rx_off(dev); bmac_update_hash_table_mask(dev, bp); bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0); /* XXDEBUG(("bmac: exit bmac_add_multi\n")); */}static voidbmac_remove_multi(struct net_device *dev, struct bmac_data *bp, unsigned char *addr){ bmac_removehash(bp, addr); bmac_rx_off(dev); bmac_update_hash_table_mask(dev, bp); bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);}#endif/* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list num_addrs > 0 Multicast mode, receive normal and MC packets, and do best-effort filtering. */static void bmac_set_multicast(struct net_device *dev){ struct dev_mc_list *dmi; struct bmac_data *bp = (struct bmac_data *) dev->priv; int num_addrs = dev->mc_count; unsigned short rx_cfg; int i; if (bp->sleeping) return; XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs)); if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff; bmac_update_hash_table_mask(dev, bp); rx_cfg = bmac_rx_on(dev, 1, 0); XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n")); } else if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) { rx_cfg = bmread(dev, RXCFG); rx_cfg |= RxPromiscEnable; bmwrite(dev, RXCFG, rx_cfg); rx_cfg = bmac_rx_on(dev, 0, 1); XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg)); } else { for (i=0; i<4; i++) bp->hash_table_mask[i] = 0; for (i=0; i<64; i++) bp->hash_use_count[i] = 0; if (num_addrs == 0) { rx_cfg = bmac_rx_on(dev, 0, 0); XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg)); } else { for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) bmac_addhash(bp, dmi->dmi_addr); bmac_update_hash_table_mask(dev, bp); rx_cfg = bmac_rx_on(dev, 1, 0); XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg)); } } /* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */}#else /* ifdef SUNHME_MULTICAST *//* The version of set_multicast below was lifted from sunhme.c */#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */static void bmac_set_multicast(struct net_device *dev){ struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i, j, bit, byte; unsigned short rx_cfg; u32 crc, poly = CRC_POLYNOMIAL_LE; if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { bmwrite(dev, BHASH0, 0xffff); bmwrite(dev, BHASH1, 0xffff); bmwrite(dev, BHASH2, 0xffff); bmwrite(dev, BHASH3, 0xffff); } else if(dev->flags & IFF_PROMISC) { rx_cfg = bmread(dev, RXCFG); rx_cfg |= RxPromiscEnable; bmwrite(dev, RXCFG, rx_cfg); } else { u16 hash_table[4]; rx_cfg = bmread(dev, RXCFG); rx_cfg &= ~RxPromiscEnable; bmwrite(dev, RXCFG, rx_cfg); for(i = 0; i < 4; i++) hash_table[i] = 0; for(i = 0; i < dev->mc_count; i++) { addrs = dmi->dmi_addr; dmi = dmi->next; if(!(*addrs & 1)) continue; crc = 0xffffffffU; for(byte = 0; byte < 6; byte++) { for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { int test; test = ((bit ^ crc) & 0x01); crc >>= 1; if(test) crc = crc ^ poly; } } crc >>= 26; hash_table[crc >> 4] |= 1 << (crc & 0xf); } bmwrite(dev, BHASH0, hash_table[0]); bmwrite(dev, BHASH1, hash_table[1]); bmwrite(dev, BHASH2, hash_table[2]); bmwrite(dev, BHASH3, hash_table[3]); }}#endif /* SUNHME_MULTICAST */static int miscintcount;static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = (struct bmac_data *)dev->priv; unsigned int status = bmread(dev, STATUS); if (miscintcount++ < 10) { XXDEBUG(("bmac_misc_intr\n")); } /* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */ /* bmac_txdma_intr_inner(irq, dev_id, regs); */ /* if (status & FrameReceived) bp->stats.rx_dropped++; */ if (status & RxErrorMask) bp->stats.rx_errors++; if (status & RxCRCCntExp) bp->stats.rx_crc_errors++; if (status & RxLenCntExp) bp->stats.rx_length_errors++; if (status & RxOverFlow) bp->stats.rx_over_errors++; if (status & RxAlignCntExp) bp->stats.rx_frame_errors++; /* if (status & FrameSent) bp->stats.tx_dropped++; */ if (status & TxErrorMask) bp->stats.tx_errors++; if (status & TxUnderrun) bp->stats.tx_fifo_errors++; if (status & TxNormalCollExp) bp->stats.collisions++;}/* * Procedure for reading EEPROM */#define SROMAddressLength 5#define DataInOn 0x0008#define DataInOff 0x0000#define Clk 0x0002#define ChipSelect 0x0001#define SDIShiftCount 3#define SD0ShiftCount 2#define DelayValue 1000 /* number of microseconds */#define SROMStartOffset 10 /* this is in words */#define SROMReadCount 3 /* number of words to read from SROM */#define SROMAddressBits 6#define EnetAddressOffset 20static unsigned charbmac_clock_out_bit(struct net_device *dev){ unsigned short data; unsigned short val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -