📄 sunlance.c
字号:
ib->btx_ring [entry].misc = 0; memcpy ((char *)&ib->tx_buf [entry][0], 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); /* 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; /* Kick the lance: transmit now */ ll->rdp = LE_C0_INEA | LE_C0_TDMD; dev->trans_start = jiffies; dev_kfree_skb (skb); if (TX_BUFFS_AVAIL) dev->tbusy = 0; /* Read back CSR to invalidate the E-Cache. * This is needed, because DMA_DSBL_WR_INV is set. */ if (lp->ledma) flush = ll->rdp; restore_flags(flags); return 0;}static struct net_device_stats *lance_get_stats (struct device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; return &lp->stats;}/* taken from the depca driver */static void lance_load_multicast (struct device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; 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_LE; /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { ib->filter [0] = 0xffffffff; ib->filter [1] = 0xffffffff; return; } /* clear the multicast filter */ ib->filter [0] = 0; ib->filter [1] = 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 >> 4] |= 1 << (crc & 0xf); }}static void lance_set_multicast (struct device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; if (!dev->start) return; if (dev->tbusy) { mod_timer(&lp->multicast_timer, jiffies + 2); return; } /* This CANNOT be correct. Chip is running and dev->tbusy may change any moment. It is useless to set it. Generally, usage of dev->tbusy in this driver is completely wrong. I protected calls to this function with start_bh_atomic, so that set_multicast_list and hard_start_xmit are serialized now by top level. --ANK The same is true about a2065. */ set_bit (0, (void *) &dev->tbusy); if (lp->tx_old != lp->tx_new) { mod_timer(&lp->multicast_timer, jiffies + 4); dev->tbusy = 0; return; } ll->rap = LE_CSR0; 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); dev->tbusy = 0; mark_bh(NET_BH);}__initfunc(static int sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev, struct Linux_SBus_DMA *ledma, struct linux_sbus_device *lebuffer)){ static unsigned version_printed = 0; int i; struct lance_private *lp; volatile struct lance_regs *ll; if (dev == NULL) { dev = init_etherdev (0, sizeof (struct lance_private) + 8); } else { dev->priv = kmalloc (sizeof (struct lance_private) + 8, GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof (struct lance_private) + 8); } if (sparc_lance_debug && version_printed++ == 0) printk (version); printk ("%s: LANCE ", dev->name); /* Fill the dev fields */ dev->base_addr = (long) sdev; /* Copy the IDPROM ethernet address to the device structure, later we * will copy the address in the device structure to the lance * initialization block. */ for (i = 0; i < 6; i++) printk ("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i], i == 5 ? ' ': ':'); printk("\n"); /* Get the IO region */ prom_apply_sbus_ranges (sdev->my_bus, &sdev->reg_addrs [0], sdev->num_registers, sdev); ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, sizeof (struct lance_regs), lancestr, sdev->reg_addrs[0].which_io, 0x0); /* Make certain the data structures used by the LANCE are aligned. */ dev->priv = (void *)(((unsigned long)dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; lp->sbus = sdev->my_bus; if (lebuffer){ prom_apply_sbus_ranges (lebuffer->my_bus, &lebuffer->reg_addrs [0], lebuffer->num_registers, lebuffer); lp->init_block = (void *) sparc_alloc_io (lebuffer->reg_addrs [0].phys_addr, 0, sizeof (struct lance_init_block), "lebuffer", lebuffer->reg_addrs [0].which_io, 0); lp->init_block_dvma = 0; lp->pio_buffer = 1; } else { lp->init_block = (void *) sparc_dvma_malloc (sizeof (struct lance_init_block), lancedma, &lp->init_block_dvma); lp->pio_buffer = 0; } lp->busmaster_regval = prom_getintdefault(sdev->prom_node, "busmaster-regval", (LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON)); lp->ll = ll; lp->name = lancestr; lp->ledma = ledma; lp->burst_sizes = 0; if (lp->ledma) { char prop[6]; unsigned int sbmask; /* Find burst-size property for ledma */ lp->burst_sizes = prom_getintdefault(ledma->SBus_dev->prom_node, "burst-sizes", 0); /* ledma may be capable of fast bursts, but sbus may not. */ sbmask = prom_getintdefault(ledma->SBus_dev->my_bus->prom_node, "burst-sizes", DMA_BURSTBITS); lp->burst_sizes &= sbmask; /* Get the cable-selection property */ memset(prop, 0, sizeof(prop)); prom_getstring(ledma->SBus_dev->prom_node, "cable-selection", prop, sizeof(prop)); if (prop[0] == 0) { int topnd, nd; printk("%s: using auto-carrier-detection.\n", dev->name); /* Is this found at /options .attributes in all * Prom versions? XXX */ topnd = prom_getchild(prom_root_node); nd = prom_searchsiblings(topnd, "options"); if (!nd) goto no_link_test; if (!prom_node_has_property(nd, "tpe-link-test?")) goto no_link_test; memset(prop, 0, sizeof(prop)); prom_getstring(nd, "tpe-link-test?", prop, sizeof(prop)); if (strcmp(prop, "true")) { printk("%s: warning: overriding option " "'tpe-link-test?'\n", dev->name); printk("%s: warning: mail any problems " "to ecd@skynet.be\n", dev->name); set_auxio(AUXIO_LINK_TEST, 0); }no_link_test: lp->auto_select = 1; lp->tpe = 0; } else if (!strcmp(prop, "aui")) { lp->auto_select = 0; lp->tpe = 0; } else { lp->auto_select = 0; lp->tpe = 1; } /* Reset ledma */ lp->ledma->regs->cond_reg |= DMA_RST_ENET; udelay (200); lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; } /* This should never happen. */ if ((unsigned long)(lp->init_block->brx_ring) & 0x07) { printk("%s: ERROR: Rx and Tx rings not on even boundary.\n", dev->name); return ENODEV; } lp->dev = dev; dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->irq = sdev->irqs[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 = (void (*)(unsigned long)) &lance_set_multicast;#ifdef MODULE dev->ifindex = dev_new_index(); lp->next_module = root_lance_dev; root_lance_dev = lp;#endif return 0;}/* On 4m, find the associated dma for the lance chip */static inline struct Linux_SBus_DMA *find_ledma (struct linux_sbus_device *dev){ struct Linux_SBus_DMA *p; for_each_dvma(p) if (p->SBus_dev == dev) return p; return 0;}#ifdef CONFIG_SUN4#include <asm/sun4paddr.h>/* Find all the lance cards on the system and initialize them */__initfunc(int sparc_lance_probe (struct device *dev)){ static struct linux_sbus_device sdev; static int called = 0; if(called) return ENODEV; called++; if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || (idprom->id_machtype == (SM_SUN4|SM_4_470))) { memset (&sdev, 0, sizeof(sdev)); sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr; sdev.irqs[0] = 6; return sparc_lance_init(dev, &sdev, 0, 0); } return ENODEV;}#else /* !CONFIG_SUN4 *//* Find all the lance cards on the system and initialize them */__initfunc(int sparc_lance_probe (struct device *dev)){ struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; struct Linux_SBus_DMA *ledma = 0; static int called = 0; int cards = 0, v; if(called) return ENODEV; called++; for_each_sbus (bus) { for_each_sbusdev (sdev, bus) { if (cards) dev = NULL; if (strcmp (sdev->prom_name, "le") == 0) { cards++; if ((v = sparc_lance_init(dev, sdev, 0, 0))) return v; continue; } if (strcmp (sdev->prom_name, "ledma") == 0) { cards++; ledma = find_ledma (sdev); if ((v = sparc_lance_init(dev, sdev->child, ledma, 0))) return v; continue; } if (strcmp (sdev->prom_name, "lebuffer") == 0){ cards++; if ((v = sparc_lance_init(dev, sdev->child, 0, sdev))) return v; continue; } } /* for each sbusdev */ } /* for each sbus */ if (!cards) return ENODEV; return 0;}#endif /* !CONFIG_SUN4 */#ifdef MODULEintinit_module(void){ root_lance_dev = NULL; return sparc_lance_probe(NULL);}voidcleanup_module(void){ 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -