📄 bmac.c
字号:
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; bmwrite(dev, SROMCSR, ChipSelect | Clk); udelay(DelayValue); data = bmread(dev, SROMCSR); udelay(DelayValue); val = (data >> SD0ShiftCount) & 1; bmwrite(dev, SROMCSR, ChipSelect); udelay(DelayValue); return val;}static voidbmac_clock_in_bit(struct net_device *dev, unsigned int val){ unsigned short data; if (val != 0 && val != 1) return; data = (val << SDIShiftCount); bmwrite(dev, SROMCSR, data | ChipSelect ); udelay(DelayValue); bmwrite(dev, SROMCSR, data | ChipSelect | Clk ); udelay(DelayValue); bmwrite(dev, SROMCSR, data | ChipSelect); udelay(DelayValue);}static voidreset_and_select_srom(struct net_device *dev){ /* first reset */ bmwrite(dev, SROMCSR, 0); udelay(DelayValue); /* send it the read command (110) */ bmac_clock_in_bit(dev, 1); bmac_clock_in_bit(dev, 1); bmac_clock_in_bit(dev, 0);}static unsigned shortread_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len){ unsigned short data, val; int i; /* send out the address we want to read from */ for (i = 0; i < addr_len; i++) { val = addr >> (addr_len-i-1); bmac_clock_in_bit(dev, val & 1); } /* Now read in the 16-bit data */ data = 0; for (i = 0; i < 16; i++) { val = bmac_clock_out_bit(dev); data <<= 1; data |= val; } bmwrite(dev, SROMCSR, 0); return data;}/* * It looks like Cogent and SMC use different methods for calculating * checksums. What a pain.. */static intbmac_verify_checksum(struct net_device *dev){ unsigned short data, storedCS; reset_and_select_srom(dev); data = read_srom(dev, 3, SROMAddressBits); storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00); return 0;}static voidbmac_get_station_address(struct net_device *dev, unsigned char *ea){ int i; unsigned short data; for (i = 0; i < 6; i++) { reset_and_select_srom(dev); data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits); ea[2*i] = bitrev(data & 0x0ff); ea[2*i+1] = bitrev((data >> 8) & 0x0ff); }}static int bmac_reset_and_enable(struct net_device *dev, int enable){ struct bmac_data *bp = dev->priv; unsigned long flags; struct sk_buff *skb; unsigned char *data; save_flags(flags); cli(); bp->reset_and_enabled = 0; bmac_reset_chip(dev); if (enable) { if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0; if (!bmac_init_chip(dev)) return 0; bmac_start_chip(dev); bmwrite(dev, INTDISABLE, EnableNormal); bp->reset_and_enabled = 1; /* * It seems that the bmac can't receive until it's transmitted * a packet. So we give it a dummy packet to transmit. */ skb = dev_alloc_skb(ETHERMINPACKET); data = skb_put(skb, ETHERMINPACKET); memset(data, 0, ETHERMINPACKET); memcpy(data, dev->dev_addr, 6); memcpy(data+6, dev->dev_addr, 6); bmac_transmit_packet(skb, dev); } restore_flags(flags); return 1;}static int __init bmac_probe(void){ struct device_node *bmac; for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next) bmac_probe1(bmac, 0); for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0; bmac = bmac->next) bmac_probe1(bmac, 1); if (bmac_devs != 0) { proc_net_create ("bmac", 0, bmac_proc_info);#ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&bmac_sleep_notifier);#endif } return 0;}static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus){ int j, rev, ret; struct bmac_data *bp; unsigned char *addr; struct net_device *dev; if (bmac->n_addrs != 3 || bmac->n_intrs != 3) { printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n", bmac->full_name); return; } addr = get_property(bmac, "mac-address", NULL); if (addr == NULL) { addr = get_property(bmac, "local-mac-address", NULL); if (addr == NULL) { printk(KERN_ERR "Can't get mac-address for BMAC %s\n", bmac->full_name); return; } } dev = init_etherdev(NULL, PRIV_BYTES); if (!dev) { printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", bmac->full_name); return; } SET_MODULE_OWNER(dev); dev->base_addr = (unsigned long) ioremap(bmac->addrs[0].address, bmac->addrs[0].size); if (!dev->base_addr) goto err_out; dev->irq = bmac->intrs[0].line; bmwrite(dev, INTDISABLE, DisableAll); printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": "")); rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) { dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); } XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); dev->open = bmac_open; dev->stop = bmac_close; dev->hard_start_xmit = bmac_output; dev->get_stats = bmac_stats; dev->set_multicast_list = bmac_set_multicast; dev->set_mac_address = bmac_set_address; bmac_get_station_address(dev, addr); if (bmac_verify_checksum(dev) != 0) goto err_out_iounmap; bp = (struct bmac_data *) dev->priv; bp->is_bmac_plus = is_bmac_plus; bp->tx_dma = (volatile struct dbdma_regs *) ioremap(bmac->addrs[1].address, bmac->addrs[1].size); if (!bp->tx_dma) goto err_out_iounmap; bp->tx_dma_intr = bmac->intrs[1].line; bp->rx_dma = (volatile struct dbdma_regs *) ioremap(bmac->addrs[2].address, bmac->addrs[2].size); if (!bp->rx_dma) goto err_out_iounmap_tx; bp->rx_dma_intr = bmac->intrs[2].line; bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1); bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1; bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1); skb_queue_head_init(bp->queue); bp->node = bmac; memset((char *) bp->tx_cmds, 0, (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); /* init_timer(&bp->tx_timeout); */ /* bp->timeout_active = 0; */ ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev); if (ret) { printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq); goto err_out_iounmap_rx; } ret = request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", dev); if (ret) { printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line); goto err_out_irq0; } ret = request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", dev); if (ret) { printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line); goto err_out_irq1; } bp->next_bmac = bmac_devs; bmac_devs = dev; return;err_out_irq1: free_irq(bmac->intrs[1].line, dev);err_out_irq0: free_irq(dev->irq, dev);err_out_iounmap_rx: iounmap((void *)bp->rx_dma);err_out_iounmap_tx: iounmap((void *)bp->tx_dma);err_out_iounmap: iounmap((void *)dev->base_addr);err_out: unregister_netdev(dev); kfree(dev);}static int bmac_open(struct net_device *dev){ /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ if (!bmac_reset_and_enable(dev, 1)) return -ENOMEM; dev->flags |= IFF_RUNNING; return 0;}static int bmac_close(struct net_device *dev){ struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; unsigned short config; int i; dev->flags &= ~(IFF_UP | IFF_RUNNING); /* disable rx and tx */ config = bmread(dev, RXCFG); bmwrite(dev, RXCFG, (config & ~RxMACEnable)); config = bmread(dev, TXCFG); bmwrite(dev, TXCFG, (config & ~TxMACEnable)); bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */ /* disable rx and tx dma */ st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ /* free some skb's */ XXDEBUG(("bmac: free rx bufs\n")); for (i=0; i<N_RX_RING; i++) { if (bp->rx_bufs[i] != NULL) { dev_kfree_skb(bp->rx_bufs[i]); bp->rx_bufs[i] = NULL; } } bp->rx_allocated = 0; XXDEBUG(("bmac: free tx bufs\n")); for (i = 0; i<N_TX_RING; i++) { if (bp->tx_bufs[i] != NULL) { dev_kfree_skb(bp->tx_bufs[i]); bp->tx_bufs[i] = NULL; } } bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); return 0;}static voidbmac_start(struct net_device *dev){ struct bmac_data *bp = dev->priv; int i; struct sk_buff *skb; unsigned long flags; save_flags(flags); cli(); while (1) { i = bp->tx_fill + 1; if (i >= N_TX_RING) i = 0; if (i == bp->tx_empty) break; skb = skb_dequeue(bp->queue); if (skb == NULL) break; bmac_transmit_packet(skb, dev); } restore_flags(flags);}static intbmac_output(struct sk_buff *skb, struct net_device *dev){ struct bmac_data *bp = dev->priv; skb_queue_tail(bp->queue, skb); bmac_start(dev); return 0;}static void bmac_tx_timeout(unsigned long data){ struct net_device *dev = (struct net_device *) data; struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *td = bp->tx_dma; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_cmd *cp; unsigned long flags; unsigned short config, oldConfig; int i; XXDEBUG(("bmac: tx_timeout called\n")); save_flags(flags); cli(); bp->timeout_active = 0; /* update various counters *//* bmac_handle_misc_intrs(bp, 0); */ cp = &bp->tx_cmds[bp->tx_empty];/* XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", *//* ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, *//* mb->pr, mb->xmtfs, mb->fifofc)); */ /* turn off both tx and rx and reset the chip */ config = bmread(dev, RXCFG); bmwrite(dev, RXCFG, (config & ~RxMACEnable)); config = bmread(dev, TXCFG); bmwrite(dev, TXCFG, (config & ~TxMACEnable)); out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); printk(KERN_ERR "bmac: transmit timeout - resetting\n"); bmac_reset_chip(dev); /* restart rx dma */ cp = bus_to_virt(ld_le32(&rd->cmdptr)); out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); out_le16(&cp->xfer_status, 0); out_le32(&rd->cmdptr, virt_to_bus(cp)); out_le32(&rd->control, DBDMA_SET(RUN|WAKE)); /* fix up the transmit side */ XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n", bp->tx_empty, bp->tx_fill, bp->tx_fullup)); i = bp->tx_empty; ++bp->stats.tx_errors; if (i != bp->tx_fill) { dev_kfree_skb(bp->tx_bufs[i]); bp->tx_bufs[i] = NULL; if (++i >= N_TX_RING) i = 0; bp->tx_empty = i; } bp->tx_fullup = 0; netif_wake_queue(dev); if (i != bp->tx_fill) { cp = &bp->tx_cmds[i]; out_le16(&cp->xfer_status, 0); out_le16(&cp->command, OUTPUT_LAST); out_le32(&td->cmdptr, virt_to_bus(cp)); out_le32(&td->control, DBDMA_SET(RUN)); /* bmac_set_timeout(dev); */ XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i)); } /* turn it back on */ oldConfig = bmread(dev, RXCFG); bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); oldConfig = bmread(dev, TXCFG); bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); restore_flags(flags);}#if 0static void dump_dbdma(volatile struct dbdma_cmd *cp,int count){ int i,*ip; for (i=0;i< count;i++) { ip = (int*)(cp+i); printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n", ld_le32(ip+0), ld_le32(ip+1), ld_le32(ip+2), ld_le32(ip+3)); }}#endifstatic intbmac_proc_info(char *buffer, char **start, off_t offset, int length){ int len = 0; off_t pos = 0; off_t begin = 0; int i; if (bmac_devs == NULL) return (-ENOSYS); len += sprintf(buffer, "BMAC counters & registers\n"); for (i = 0; i<N_REG_ENTRIES; i++) { len += sprintf(buffer + len, "%s: %#08x\n", reg_entries[i].name, bmread(bmac_devs, reg_entries[i].reg_offset)); pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset+length) break; } *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return len;}MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");static void __exit bmac_cleanup (void){ struct bmac_data *bp; struct net_device *dev; if (bmac_devs == 0) return;#ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&bmac_sleep_notifier);#endif proc_net_remove("bmac"); do { dev = bmac_devs; bp = (struct bmac_data *) dev->priv; bmac_devs = bp->next_bmac; free_irq(dev->irq, dev); free_irq(bp->tx_dma_intr, dev); free_irq(bp->rx_dma_intr, dev); unregister_netdev(dev); kfree(dev); } while (bmac_devs != NULL);}module_init(bmac_probe);module_exit(bmac_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -