📄 sunlance.c
字号:
unsigned long piobuf = (unsigned long) dest; if (piobuf & 1) { sbus_writeb(0, piobuf); piobuf += 1; len -= 1; if (len == 0) return; } if (len == 1) { sbus_writeb(0, piobuf); return; } if (piobuf & 2) { sbus_writew(0, piobuf); piobuf += 2; len -= 2; if (len == 0) return; } while (len >= 4) { sbus_writel(0, piobuf); piobuf += 4; len -= 4; } if (len >= 2) { sbus_writew(0, piobuf); piobuf += 2; len -= 2; } if (len >= 1) sbus_writeb(0, piobuf);}static void lance_tx_timeout(struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", dev->name, sbus_readw(lp->lregs + 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_init_block *ib = lp->init_block; int entry, skblen, len; skblen = skb->len; len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; spin_lock_irq(&lp->lock); lp->stats.tx_bytes += len; entry = lp->tx_new & TX_RING_MOD_MASK; if (lp->pio_buffer) { sbus_writew((-len) | 0xf000, &ib->btx_ring[entry].length); sbus_writew(0, &ib->btx_ring[entry].misc); lance_piocopy_from_skb(&ib->tx_buf[entry][0], skb->data, skblen); if (len != skblen) lance_piozero(&ib->tx_buf[entry][skblen], len - skblen); sbus_writeb(LE_T1_POK | LE_T1_OWN, &ib->btx_ring[entry].tmd1_bits); } else { ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; memcpy((char *)&ib->tx_buf [entry][0], skb->data, skblen); if (len != skblen) memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); ib->btx_ring [entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN); } lp->tx_new = TX_NEXT(entry); if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); /* Kick the lance: transmit now */ sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP); /* Read back CSR to invalidate the E-Cache. * This is needed, because DMA_DSBL_WR_INV is set. */ if (lp->dregs) sbus_readw(lp->lregs + RDP); 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;}/* taken from the depca driver */static void lance_load_multicast(struct net_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) { if (lp->pio_buffer) { sbus_writel(0xffffffff, &ib->filter[0]); sbus_writel(0xffffffff, &ib->filter[1]); } else { ib->filter [0] = 0xffffffff; ib->filter [1] = 0xffffffff; } return; } /* clear the multicast filter */ if (lp->pio_buffer) { sbus_writel(0, &ib->filter[0]); sbus_writel(0, &ib->filter[1]); } else { 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; if (lp->pio_buffer) { u16 tmp = sbus_readw(&mcast_table[crc>>4]); tmp |= 1 << (crc & 0xf); sbus_writew(tmp, &mcast_table[crc>>4]); } else { mcast_table [crc >> 4] |= 1 << (crc & 0xf); } }}static void lance_set_multicast(struct net_device *dev){ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; u16 mode; 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); STOP_LANCE(lp); lp->init_ring(dev); if (lp->pio_buffer) mode = sbus_readw(&ib->mode); else mode = ib->mode; if (dev->flags & IFF_PROMISC) { mode |= LE_MO_PROM; if (lp->pio_buffer) sbus_writew(mode, &ib->mode); else ib->mode = mode; } else { mode &= ~LE_MO_PROM; if (lp->pio_buffer) sbus_writew(mode, &ib->mode); else ib->mode = mode; 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 void lance_free_hwresources(struct lance_private *lp){ if (lp->lregs) sbus_iounmap(lp->lregs, LANCE_REG_SIZE); if (lp->init_block != NULL) { if (lp->pio_buffer) { sbus_iounmap((unsigned long)lp->init_block, sizeof(struct lance_init_block)); } else { sbus_free_consistent(lp->sdev, sizeof(struct lance_init_block), (void *)lp->init_block, lp->init_block_dvma); } }}static int __init sparc_lance_init(struct net_device *dev, struct sbus_dev *sdev, struct sbus_dma *ledma, struct sbus_dev *lebuffer){ static unsigned version_printed = 0; struct lance_private *lp = NULL; int i; 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 (KERN_INFO "%s", version); printk(KERN_INFO "%s: LANCE ", dev->name); /* 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; spin_lock_init(&lp->lock); /* 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 */ lp->lregs = sbus_ioremap(&sdev->resource[0], 0, LANCE_REG_SIZE, lancestr); if (lp->lregs == 0UL) { printk(KERN_ERR "%s: Cannot map SunLance registers.\n", dev->name); goto fail; } lp->sdev = sdev; if (lebuffer) { lp->init_block = (volatile struct lance_init_block *) sbus_ioremap(&lebuffer->resource[0], 0, sizeof(struct lance_init_block), "lebuffer"); if (lp->init_block == NULL) { printk(KERN_ERR "%s: Cannot map SunLance PIO buffer.\n", dev->name); goto fail; } lp->init_block_dvma = 0; lp->pio_buffer = 1; lp->init_ring = lance_init_ring_pio; lp->rx = lance_rx_pio; lp->tx = lance_tx_pio; } else { lp->init_block = (volatile struct lance_init_block *) sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), &lp->init_block_dvma); if (lp->init_block == NULL || lp->init_block_dvma == 0) { printk(KERN_ERR "%s: Cannot allocate consistent DMA memory.\n", dev->name); goto fail; } lp->pio_buffer = 0; lp->init_ring = lance_init_ring_dvma; lp->rx = lance_rx_dvma; lp->tx = lance_tx_dvma; } lp->busmaster_regval = prom_getintdefault(sdev->prom_node, "busmaster-regval", (LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON)); lp->name = lancestr; lp->ledma = ledma; lp->burst_sizes = 0; if (lp->ledma) { char prop[6]; unsigned int sbmask; u32 csr; /* Find burst-size property for ledma */ lp->burst_sizes = prom_getintdefault(ledma->sdev->prom_node, "burst-sizes", 0); /* ledma may be capable of fast bursts, but sbus may not. */ sbmask = prom_getintdefault(ledma->sdev->bus->prom_node, "burst-sizes", DMA_BURSTBITS); lp->burst_sizes &= sbmask; /* Get the cable-selection property */ memset(prop, 0, sizeof(prop)); prom_getstring(ledma->sdev->prom_node, "cable-selection", prop, sizeof(prop)); if (prop[0] == 0) { int topnd, nd; printk(KERN_INFO "%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(KERN_NOTICE "%s: warning: overriding option " "'tpe-link-test?'\n", dev->name); printk(KERN_NOTICE "%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; } lp->dregs = ledma->regs; /* Reset ledma */ csr = sbus_readl(lp->dregs + DMA_CSR); sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR); udelay(200); sbus_writel(csr & ~DMA_RST_ENET, lp->dregs + DMA_CSR); } else lp->dregs = 0; /* This should never happen. */ if ((unsigned long)(lp->init_block->brx_ring) & 0x07) { printk(KERN_ERR "%s: ERROR: Rx and Tx rings not on even boundary.\n", dev->name); goto fail; } 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; 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 = &lance_set_multicast_retry; dev->ifindex = dev_new_index(); lp->next_module = root_lance_dev; root_lance_dev = lp; return 0;fail: if (lp != NULL) lance_free_hwresources(lp); return -ENODEV;}/* On 4m, find the associated dma for the lance chip */static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev){ struct sbus_dma *p; for_each_dvma(p) { if (p->sdev == sdev) return p; } return NULL;}#ifdef CONFIG_SUN4#include <asm/sun4paddr.h>/* Find all the lance cards on the system and initialize them */static int __init sparc_lance_probe(void){ static struct sbus_dev sdev; static int called = 0; root_lance_dev = NULL; 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(NULL, &sdev, 0, 0); } return -ENODEV;}#else /* !CONFIG_SUN4 *//* Find all the lance cards on the system and initialize them */static int __init sparc_lance_probe(void){ struct sbus_bus *bus; struct sbus_dev *sdev = 0; struct net_device *dev = NULL; struct sbus_dma *ledma = 0; static int called = 0; int cards = 0, v; root_lance_dev = NULL; 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 */static void __exit sparc_lance_cleanup(void){ struct lance_private *lp; while (root_lance_dev) { lp = root_lance_dev->next_module; unregister_netdev(root_lance_dev->dev); lance_free_hwresources(root_lance_dev); kfree(root_lance_dev->dev); root_lance_dev = lp; }}module_init(sparc_lance_probe);module_exit(sparc_lance_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -