📄 au1000_eth.c
字号:
DMA memory allocation, derived from pci_alloc_consistent. However, the Au1000 data cache is coherent (when programmed so), therefore we return KSEG0 address, not KSEG1.*/static void *dma_alloc(size_t size, dma_addr_t * dma_handle){ void *ret; int gfp = GFP_ATOMIC | GFP_DMA; ret = (void *) __get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); *dma_handle = virt_to_bus(ret); ret = KSEG0ADDR(ret); } return ret;}static void dma_free(void *vaddr, size_t size){ vaddr = KSEG0ADDR(vaddr); free_pages((unsigned long) vaddr, get_order(size));}static void hard_stop(struct net_device *dev){ struct au1000_private *aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk(KERN_INFO "%s: hard stop\n", dev->name); aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE); sync(); mdelay(10);}static void reset_mac(struct net_device *dev){ u32 flags; struct au1000_private *aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk(KERN_INFO "%s: reset mac, aup %x\n", dev->name, (unsigned)aup); spin_lock_irqsave(&aup->lock, flags); del_timer(&aup->timer); hard_stop(dev); *aup->enable |= MAC_DMA_RESET; sync(); mdelay(10); aup->tx_full = 0; spin_unlock_irqrestore(&aup->lock, flags);}static void cleanup_buffers(struct net_device *dev){ int i; struct au1000_private *aup = (struct au1000_private *) dev->priv; for (i=0; i<NUM_RX_DMA; i++) { if (aup->rx_db_inuse[i]) { ReleaseDB(aup, aup->rx_db_inuse[i]); aup->rx_db_inuse[i] = 0; } } for (i=0; i<NUM_TX_DMA; i++) { if (aup->tx_db_inuse[i]) { ReleaseDB(aup, aup->tx_db_inuse[i]); aup->tx_db_inuse[i] = 0; } }}/* * Setup the receive and transmit "rings". These pointers are the addresses * of the rx and tx MAC DMA registers so they are fixed by the hardware -- * these are not descriptors sitting in memory. */static void setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base){ int i; for (i=0; i<NUM_RX_DMA; i++) { aup->rx_dma_ring[i] = (volatile rx_dma_t *) ioremap_nocache((unsigned long) (rx_base + sizeof(rx_dma_t)*i), sizeof(rx_dma_t)); } for (i=0; i<NUM_TX_DMA; i++) { aup->tx_dma_ring[i] = (volatile tx_dma_t *)ioremap_nocache((unsigned long) (tx_base + sizeof(tx_dma_t)*i), sizeof(tx_dma_t)); }}/* * Probe for a AU1000 ethernet controller. */int __init au1000_probe(struct net_device *dev){ int base_addr = au1000_iflist[next_dev].port; int irq = au1000_iflist[next_dev].irq;#ifndef CONFIG_MIPS_AU1000_ENET return -ENODEV;#endif if (au1000_debug > 4) printk(KERN_INFO "%s: au1000_probe base_addr %x\n", dev->name, base_addr); if (next_dev >= NUM_INTERFACES) { return -ENODEV; } if (au1000_probe1(dev, base_addr, irq, next_dev) == 0) { next_dev++; return 0; } next_dev++; return -ENODEV;}static int __initau1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num){ static unsigned version_printed = 0; struct au1000_private *aup = NULL; int i, retval = 0; db_dest_t *pDB, *pDBfree; u16 link, speed; if ((ioaddr != AU1000_ETH0_BASE) && (ioaddr != AU1000_ETH1_BASE)) { return -ENODEV; } if (!request_region(ioaddr, MAC_IOSIZE, "Au1000 ENET")) { return -ENODEV; } if (version_printed++ == 0) printk(version); if (!dev) { dev = init_etherdev(0, sizeof(struct au1000_private)); } if (!dev) { printk (KERN_ERR "au1000 eth: init_etherdev failed\n"); return -ENODEV; } printk("%s: Au1000 ethernet found at 0x%lx, irq %d\n", dev->name, ioaddr, irq); /* Initialize our private structure */ if (dev->priv == NULL) { aup = (struct au1000_private *) kmalloc(sizeof(*aup), GFP_KERNEL); if (aup == NULL) { retval = -ENOMEM; goto free_region; } dev->priv = aup; } aup = dev->priv; memset(aup, 0, sizeof(*aup)); /* Allocate the data buffers */ aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); if (!aup->vaddr) { retval = -ENOMEM; goto free_region; } /* aup->mac is the base address of the MAC's registers */ aup->mac = (volatile mac_reg_t *)ioremap_nocache((unsigned long)ioaddr, sizeof(*aup->mac)); /* Setup some variables for quick register address access */ if (ioaddr == AU1000_ETH0_BASE) { aup->enable = (volatile u32 *) ioremap_nocache((unsigned long)MAC0_ENABLE, sizeof(*aup->enable)); memcpy(dev->dev_addr, au1000_mac_addr[0], sizeof(dev->dev_addr)); setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); } else if (ioaddr == AU1000_ETH1_BASE) { aup->enable = (volatile u32 *) ioremap_nocache((unsigned long)MAC1_ENABLE, sizeof(*aup->enable)); memcpy(dev->dev_addr, au1000_mac_addr[1], sizeof(dev->dev_addr)); setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); } else { /* should never happen */ printk (KERN_ERR "au1000 eth: bad ioaddr %x\n", (unsigned)ioaddr); retval = -ENODEV; goto free_region; } aup->phy_addr = PHY_ADDRESS; /* bring the device out of reset, otherwise probing the mii * will hang */ *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; sync(); mdelay(2); if (mii_probe(dev) != 0) { goto free_region; } aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); if (!link) { printk(KERN_INFO "%s: link down resetting...\n", dev->name); aup->phy_ops->phy_reset(dev, aup->phy_addr); aup->phy_ops->phy_init(dev, aup->phy_addr); } else { printk(KERN_INFO "%s: link up (%s)\n", dev->name, phy_link[speed]); } pDBfree = NULL; /* setup the data buffer descriptors and attach a buffer to each one */ pDB = aup->db; for (i=0; i<(NUM_TX_BUFFS+NUM_RX_BUFFS); i++) { pDB->pnext = pDBfree; pDBfree = pDB; pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i); pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); pDB++; } aup->pDBfree = pDBfree; for (i=0; i<NUM_RX_DMA; i++) { pDB = GetFreeDB(aup); if (!pDB) goto free_region; aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->rx_db_inuse[i] = pDB; } for (i=0; i<NUM_TX_DMA; i++) { pDB = GetFreeDB(aup); if (!pDB) goto free_region; aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->tx_dma_ring[i]->len = 0; aup->tx_db_inuse[i] = pDB; } spin_lock_init(&aup->lock); dev->base_addr = ioaddr; dev->irq = irq; dev->open = au1000_open; dev->hard_start_xmit = au1000_tx; dev->stop = au1000_close; dev->get_stats = au1000_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &au1000_ioctl; dev->set_config = &au1000_set_config; dev->tx_timeout = au1000_tx_timeout; dev->watchdog_timeo = ETH_TX_TIMEOUT; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* * The boot code uses the ethernet controller, so reset it to start fresh. * au1000_init() expects that the device is in reset state. */ reset_mac(dev); return 0;free_region: release_region(ioaddr, MAC_IOSIZE); unregister_netdev(dev); if (aup->vaddr) dma_free((void *)aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); if (dev->priv != NULL) kfree(dev->priv); kfree(dev); printk(KERN_ERR "%s: au1000_probe1 failed. Returns %d\n", dev->name, retval); return retval;}/* * Initialize the interface. * * When the device powers up, the clocks are disabled and the * mac is in reset state. When the interface is closed, we * do the same -- reset the device and disable the clocks to * conserve power. Thus, whenever au1000_init() is called, * the device should already be in reset state. */static int au1000_init(struct net_device *dev){ struct au1000_private *aup = (struct au1000_private *) dev->priv; u32 flags; int i; u32 value, control; if (au1000_debug > 4) printk("%s: au1000_init", dev->name); spin_lock_irqsave(&aup->lock, flags); /* bring the device out of reset */ value = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; *aup->enable = value; sync(); mdelay(200); aup->mac->control = 0; aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2; aup->tx_tail = aup->tx_head; aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2; aup->mac->mac_addr_high = dev->dev_addr[5]<<8 | dev->dev_addr[4]; aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 | dev->dev_addr[1]<<8 | dev->dev_addr[0]; for (i=0; i<NUM_RX_DMA; i++) { aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE; } sync(); control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;#ifndef CONFIG_CPU_LITTLE_ENDIAN control |= MAC_BIG_ENDIAN;#endif aup->mac->control = control; spin_unlock_irqrestore(&aup->lock, flags); return 0;}static void au1000_timer(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct au1000_private *aup = (struct au1000_private *) dev->priv; u16 mii_data, link, speed; if (!dev) { /* fatal error, don't restart the timer */ printk(KERN_ERR "au1000_timer error: NULL dev\n"); return; } if (!(dev->flags & IFF_UP)) { goto set_timer; } if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) { if (link) { if (!(dev->flags & IFF_RUNNING)) { netif_carrier_on(dev); dev->flags |= IFF_RUNNING; printk(KERN_DEBUG "%s: link up\n", dev->name); } } else { if (dev->flags & IFF_RUNNING) { netif_carrier_off(dev); dev->flags &= ~IFF_RUNNING; dev->if_port = 0; printk(KERN_DEBUG "%s: link down\n", dev->name); } } }set_timer: aup->timer.expires = RUN_AT((1*HZ)); aup->timer.data = (unsigned long)dev; aup->timer.function = &au1000_timer; /* timer handler */ add_timer(&aup->timer);}static int au1000_open(struct net_device *dev){ int retval; struct au1000_private *aup = (struct au1000_private *) dev->priv; MOD_INC_USE_COUNT; if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); if ((retval = au1000_init(dev))) { printk(KERN_ERR "%s: error in au1000_init\n", dev->name); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return retval; } netif_start_queue(dev); if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); MOD_DEC_USE_COUNT; return retval; } aup->timer.expires = RUN_AT((3*HZ)); aup->timer.data = (unsigned long)dev; aup->timer.function = &au1000_timer; /* timer handler */ add_timer(&aup->timer); if (au1000_debug > 4) printk("%s: open: Initialization done.\n", dev->name); return 0;}static int au1000_close(struct net_device *dev){ u32 flags; struct au1000_private *aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk("%s: close: dev=%p\n", dev->name, dev); spin_lock_irqsave(&aup->lock, flags); /* stop the device */ if (netif_device_present(dev)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -