📄 declance.c
字号:
static void lance_tx_timeout(struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_regs *ll = lp->ll; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", dev->name, ll->rdp); lance_reset(dev); netif_wake_queue(dev);}static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); int entry, skblen, len; skblen = skb->len; len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; lp->stats.tx_bytes += len; entry = lp->tx_new & TX_RING_MOD_MASK; ib->btx_ring[entry].length = (-len); ib->btx_ring[entry].misc = 0; cp_to_buf((char *) lp->tx_buf_ptr_cpu[entry], skb->data, skblen); /* Clear the slack of the packet, do I need this? */ /* For a firewall its a good idea - AC *//* if (len != skblen) memset ((char *) &ib->tx_buf [entry][skblen], 0, (len - skblen) << 1); */ /* Now, give the packet to the lance */ ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN); lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK; if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); /* Kick the lance: transmit now */ writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD); spin_unlock_irq(&lp->lock); dev->trans_start = jiffies; dev_kfree_skb(skb); return 0;}static struct net_device_stats *lance_get_stats(struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; return &lp->stats;}static void lance_load_multicast(struct net_device *dev){ volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); volatile u16 *mcast_table = (u16 *) & ib->filter; struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i, j, bit, byte; u32 crc, poly = CRC_POLYNOMIAL_BE; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { ib->filter[0] = 0xffff; ib->filter[2] = 0xffff; ib->filter[4] = 0xffff; ib->filter[6] = 0xffff; return; } /* clear the multicast filter */ ib->filter[0] = 0; ib->filter[2] = 0; ib->filter[4] = 0; ib->filter[6] = 0; /* Add addresses */ for (i = 0; i < dev->mc_count; i++) { addrs = dmi->dmi_addr; dmi = dmi->next; /* multicast address? */ if (!(*addrs & 1)) continue; crc = 0xffffffff; 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 = crc >> 26; mcast_table[crc >> 3] |= 1 << (crc & 0xf); } return;}static void lance_set_multicast(struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib; volatile struct lance_regs *ll = lp->ll; ib = (struct lance_init_block *) (dev->mem_start); if (!netif_running(dev)) return; if (lp->tx_old != lp->tx_new) { mod_timer(&lp->multicast_timer, jiffies + 4); netif_wake_queue(dev); return; } netif_stop_queue(dev); writereg(&ll->rap, LE_CSR0); writereg(&ll->rdp, LE_C0_STOP); lance_init_ring(dev); if (dev->flags & IFF_PROMISC) { ib->mode |= LE_MO_PROM; } else { ib->mode &= ~LE_MO_PROM; lance_load_multicast(dev); } load_csrs(lp); init_restart_lance(lp); netif_wake_queue(dev);}static void lance_set_multicast_retry(unsigned long _opaque){ struct net_device *dev = (struct net_device *) _opaque; lance_set_multicast(dev);}static int __init dec_lance_init(struct net_device *dev, const int type){ static unsigned version_printed; struct net_device *dev; struct lance_private *lp; volatile struct lance_regs *ll; int i, ret; unsigned long esar_base; unsigned char *esar;#ifndef CONFIG_TC system_base = KN01_LANCE_BASE;#else int slot;#endif if (dec_lance_debug && version_printed++ == 0) printk(version); dev = init_etherdev(0, sizeof(struct lance_private)); if (!dev) return -ENOMEM; /* init_etherdev ensures the data structures used by the LANCE are aligned. */ lp = (struct lance_private *) dev->priv; spin_lock_init(&lp->lock); switch (type) {#ifdef CONFIG_TC case ASIC_LANCE: dev->base_addr = system_base + LANCE; /* buffer space for the on-board LANCE shared memory */ /* * FIXME: ugly hack! */ dev->mem_start = KSEG1ADDR(0x00020000); dev->mem_end = dev->mem_start + 0x00020000; dev->irq = ETHER; esar_base = system_base + ESAR; /* Workaround crash with booting KN04 2.1k from Disk */ memset(dev->mem_start, 0, dev->mem_end - dev->mem_start); /* * setup the pointer arrays, this sucks [tm] :-( */ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU + 2 * i * RX_BUFF_SIZE); lp->rx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + i * RX_BUFF_SIZE); } for (i = 0; i < TX_RING_SIZE; i++) { lp->tx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU + 2 * RX_RING_SIZE * RX_BUFF_SIZE + 2 * i * TX_BUFF_SIZE); lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + RX_RING_SIZE * RX_BUFF_SIZE + i * TX_BUFF_SIZE); } /* * setup and enable IOASIC LANCE DMA */ lp->dma_ptr_reg = (unsigned long *) (system_base + IOCTL + LANCE_DMA_P); *(lp->dma_ptr_reg) = PHYSADDR(dev->mem_start) << 3; *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16); wbflush(); break; case PMAD_LANCE: slot = search_tc_card("PMAD-AA"); claim_tc_card(slot); dev->mem_start = get_tc_base_addr(slot); dev->base_addr = dev->mem_start + 0x100000; dev->irq = get_tc_irq_nr(slot); esar_base = dev->mem_start + 0x1c0002; break;#endif case PMAX_LANCE: dev->irq = ETHER; dev->base_addr = KN01_LANCE_BASE; dev->mem_start = KN01_LANCE_BASE + 0x01000000; esar_base = KN01_RTC_BASE + 1; /* * setup the pointer arrays, this sucks [tm] :-( */ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU + 2 * i * RX_BUFF_SIZE); lp->rx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + i * RX_BUFF_SIZE); } for (i = 0; i < TX_RING_SIZE; i++) { lp->tx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU + 2 * RX_RING_SIZE * RX_BUFF_SIZE + 2 * i * TX_BUFF_SIZE); lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + RX_RING_SIZE * RX_BUFF_SIZE + i * TX_BUFF_SIZE); } break; default: printk("declance_init called with unknown type\n"); ret = -ENODEV; goto err_out; } ll = (struct lance_regs *) dev->base_addr; esar = (unsigned char *) esar_base; /* prom checks */ /* First, check for test pattern */ if (esar[0x60] != 0xff && esar[0x64] != 0x00 && esar[0x68] != 0x55 && esar[0x6c] != 0xaa) { printk("Ethernet station address prom not found!\n"); ret = -ENODEV; goto err_out; } /* Check the prom contents */ for (i = 0; i < 8; i++) { if (esar[i * 4] != esar[0x3c - i * 4] && esar[i * 4] != esar[0x40 + i * 4] && esar[0x3c - i * 4] != esar[0x40 + i * 4]) { printk("Something is wrong with the ethernet " "station address prom!\n"); ret = -ENODEV; goto err_out; } } /* Copy the ethernet address to the device structure, later to the * lance initialization block so the lance gets it every time it's * (re)initialized. */ switch (type) { case ASIC_LANCE: printk("%s: IOASIC onboard LANCE, addr = ", dev->name); break; case PMAD_LANCE: printk("%s: PMAD-AA, addr = ", dev->name); break; case PMAX_LANCE: printk("%s: PMAX onboard LANCE, addr = ", dev->name); break; } for (i = 0; i < 6; i++) { dev->dev_addr[i] = esar[i * 4]; printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':'); } printk(" irq = %d\n", dev->irq); lp->dev = dev; dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; /* lp->ll is the location of the registers for lance card */ lp->ll = ll; lp->name = lancestr; /* busmaster_regval (CSR3) should be zero according to the PMAD-AA * specification. */ lp->busmaster_regval = 0; dev->dma = 0; ether_setup(dev); /* We cannot sleep if the chip is busy during a * multicast list update event, because such events * can occur from interrupts (ex. IPv6). So we * use a timer to try again later when necessary. -DaveM */ init_timer(&lp->multicast_timer); lp->multicast_timer.data = (unsigned long) dev; lp->multicast_timer.function = &lance_set_multicast_retry;#ifdef MODULE dev->ifindex = dev_new_index(); lp->next_module = root_lance_dev; root_lance_dev = lp;#endif return 0;err_out: unregister_netdev(dev); kfree(dev); return ret;}/* Find all the lance cards on the system and initialize them */static int __init dec_lance_probe(void){ struct net_device *dev = NULL; static int called;#ifdef MODULE root_lance_dev = NULL;#endif#ifdef CONFIG_TC int slot = -1; if (TURBOCHANNEL) { if (IOASIC && !called) { called = 1; type = ASIC_LANCE; } else { if ((slot = search_tc_card("PMAD-AA")) >= 0) { type = PMAD_LANCE; } else { return -ENODEV; } } } else { if (!called) { called = 1; type = PMAX_LANCE; } else { return -ENODEV; } }#else if (!called && !TURBOCHANNEL) { called = 1; type = PMAX_LANCE; } else { return -ENODEV; }#endif return dec_lance_init(dev, type);}static void __exit dec_lance_cleanup(void){#ifdef MODULE struct lance_private *lp; while (root_lance_dev) { lp = root_lance_dev->next_module; unregister_netdev(root_lance_dev->dev); kfree(root_lance_dev->dev); root_lance_dev = lp; }#endif /* MODULE */}module_init(dec_lance_probe);module_exit(dec_lance_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -