📄 bmac.c
字号:
#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 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 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 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 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 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 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 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;}intbmac_probe(struct device *dev){ int j, rev; struct bmac_data *bp; struct device_node *bmacs; unsigned char *addr; static struct device_node *all_bmacs = NULL, *next_bmac; if (all_bmacs == NULL) { all_bmacs = find_devices("bmac"); is_bmac_plus = 0; if (all_bmacs == NULL) { all_bmacs = find_compatible_devices("network", "bmac+"); if (all_bmacs) is_bmac_plus = 1; } next_bmac = all_bmacs; } bmacs = next_bmac; if (bmacs == NULL) return -ENODEV; next_bmac = bmacs->next; bmac_devs = dev; /* KLUDGE!! */ if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) { printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n", bmacs->full_name); return -EINVAL; } if (dev == NULL) { dev = init_etherdev(NULL, PRIV_BYTES); bmac_devs = dev; /*KLUDGE!!*/ } else { /* XXX this doesn't look right (but it's never used :-) */ dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL); if (dev->priv == 0) return -ENOMEM; }#ifdef MODULE bmac_devs = dev;#endif dev->base_addr = (unsigned long) ioremap(bmacs->addrs[0].address, bmacs->addrs[0].size); dev->irq = bmacs->intrs[0].line; bmwrite(dev, INTDISABLE, DisableAll); addr = get_property(bmacs, "mac-address", NULL); if (addr == NULL) { addr = get_property(bmacs, "local-mac-address", NULL); if (addr == NULL) { printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n", dev->base_addr); return -EAGAIN; } } 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) return -EINVAL; ether_setup(dev); bp = (struct bmac_data *) dev->priv; memset(bp, 0, sizeof(struct bmac_data)); bp->tx_dma = (volatile struct dbdma_regs *) ioremap(bmacs->addrs[1].address, bmacs->addrs[1].size); bp->tx_dma_intr = bmacs->intrs[1].line; bp->rx_dma = (volatile struct dbdma_regs *) ioremap(bmacs->addrs[2].address, bmacs->addrs[2].size); bp->rx_dma_intr = bmacs->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 = bmacs; memset(&bp->stats, 0, sizeof(bp->stats)); 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; */ if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) { printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq); return -EAGAIN; } if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", dev)) { printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line); return -EAGAIN; } if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", dev)) { printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line); return -EAGAIN; } if (!bmac_reset_and_enable(dev, 0)) return -ENOMEM; #ifdef CONFIG_PROC_FS proc_net_register(&(struct proc_dir_entry) { PROC_NET_BMAC, 4, "bmac", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, bmac_proc_info });#endif return 0;}static int bmac_open(struct device *dev){ /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ bmac_reset_and_enable(dev, 1); dev->flags |= IFF_UP | IFF_RUNNING; return 0;}static int bmac_close(struct 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 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 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 device *dev = (struct 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; dev->tbusy = 0; mark_bh(NET_BH); XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n")); 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 dummy){ 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;}#ifdef MODULEMODULE_AUTHOR("Randy Gobbel/Paul Mackerras");MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");int init_module(void){ int res; if(bmac_devs != NULL) return -EBUSY; res = bmac_probe(NULL); return res;}void cleanup_module(void){ struct bmac_data *bp = (struct bmac_data *) bmac_devs->priv; unregister_netdev(bmac_devs); free_irq(bmac_devs->irq, bmac_misc_intr); free_irq(bp->tx_dma_intr, bmac_txdma_intr); free_irq(bp->rx_dma_intr, bmac_rxdma_intr); kfree(bmac_devs); bmac_devs = NULL;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -