au1000_eth.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,407 行 · 第 1/3 页
C
1,407 行
mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL); if (mii_phy) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; mii_phy->next = aup->mii; aup->phy_ops = mii_chip_table[i].phy_ops; aup->mii = mii_phy; aup->phy_ops->phy_init(dev,phy_addr); } else { printk(KERN_ERR "%s: out of memory\n", dev->name); return -1; } /* the current mii is on our mii_info_table, try next address */ break; } } } if (aup->mii == NULL) { printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name); return -1; } /* use last PHY */ aup->phy_addr = aup->mii->phy_addr; printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name); return 0;}/* * Buffer allocation/deallocation routines. The buffer descriptor returned * has the virtual and dma address of a buffer suitable for * both, receive and transmit operations. */static db_dest_t *GetFreeDB(struct au1000_private *aup){ db_dest_t *pDB; pDB = aup->pDBfree; if (pDB) { aup->pDBfree = pDB->pnext; } //printk("GetFreeDB: %x\n", pDB); return pDB;}void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB){ db_dest_t *pDBfree = aup->pDBfree; if (pDBfree) pDBfree->pnext = pDB; aup->pDBfree = pDB;}/* 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 = (void *)KSEG0ADDR(ret); } return ret;}static void dma_free(void *vaddr, size_t size){ vaddr = (void *)KSEG0ADDR(vaddr); free_pages((unsigned long) vaddr, get_order(size));}static void enable_rx_tx(struct net_device *dev){ struct au1000_private *aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk(KERN_INFO "%s: enable_rx_tx\n", dev->name); aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE); au_sync_delay(10);}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); au_sync_delay(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_EN_CLOCK_ENABLE; au_sync_delay(2); *aup->enable = 0; au_sync_delay(2); aup->tx_full = 0; spin_unlock_irqrestore(&aup->lock, flags);}/* * 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 *) (rx_base + sizeof(rx_dma_t)*i); } for (i=0; i<NUM_TX_DMA; i++) { aup->tx_dma_ring[i] = (volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i); }}static int __init au1000_init_module(void){ int i; int prid; int base_addr, irq; prid = read_c0_prid(); for (i=0; i<NUM_INTERFACES; i++) { if ( (prid & 0xffff0000) == 0x00030000 ) { base_addr = au1000_iflist[i].port; irq = au1000_iflist[i].irq; } else if ( (prid & 0xffff0000) == 0x01030000 ) { base_addr = au1500_iflist[i].port; irq = au1500_iflist[i].irq; } else if ( (prid & 0xffff0000) == 0x02030000 ) { base_addr = au1100_iflist[i].port; irq = au1100_iflist[i].irq; } else { printk(KERN_ERR "au1000 eth: unknown Processor ID\n"); return -ENODEV; } // check for valid entries, au1100 only has one entry if (base_addr && irq) { if (au1000_probe1(base_addr, irq, i) != 0) return -ENODEV; } } return 0;}static int __initau1000_probe1(long ioaddr, int irq, int port_num){ struct net_device *dev; static unsigned version_printed = 0; struct au1000_private *aup = NULL; int i, retval = 0; db_dest_t *pDB, *pDBfree; char *pmac, *argptr; char ethaddr[6]; if (!request_region(PHYSADDR(ioaddr), MAC_IOSIZE, "Au1000 ENET")) return -ENODEV; if (version_printed++ == 0) printk(version); retval = -ENOMEM; dev = alloc_etherdev(sizeof(struct au1000_private)); if (!dev) { printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n"); goto out; } SET_MODULE_OWNER(dev); printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", dev->name, ioaddr, irq); aup = dev->priv; /* Allocate the data buffers */ aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); if (!aup->vaddr) goto out1; /* aup->mac is the base address of the MAC's registers */ aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr); /* Setup some variables for quick register address access */ switch (ioaddr) { case AU1000_ETH0_BASE: case AU1500_ETH0_BASE: /* check env variables first */ if (!get_ethernet_addr(ethaddr)) { memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr)); } else { /* Check command line */ argptr = prom_getcmdline(); if ((pmac = strstr(argptr, "ethaddr=")) == NULL) { printk(KERN_INFO "%s: No mac address found\n", dev->name); /* use the hard coded mac addresses */ } else { str2eaddr(ethaddr, pmac + strlen("ethaddr=")); memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr)); } } if (ioaddr == AU1000_ETH0_BASE) aup->enable = (volatile u32 *) ((unsigned long)AU1000_MAC0_ENABLE); else aup->enable = (volatile u32 *) ((unsigned long)AU1500_MAC0_ENABLE); memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr)); setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); break; case AU1000_ETH1_BASE: case AU1500_ETH1_BASE: if (ioaddr == AU1000_ETH1_BASE) aup->enable = (volatile u32 *) ((unsigned long)AU1000_MAC1_ENABLE); else aup->enable = (volatile u32 *) ((unsigned long)AU1500_MAC1_ENABLE); memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr)); dev->dev_addr[4] += 0x10; setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); break; default: printk(KERN_ERR "%s: bad ioaddr\n", dev->name); break; } aup->phy_addr = PHY_ADDRESS; /* bring the device out of reset, otherwise probing the mii * will hang */ *aup->enable = MAC_EN_CLOCK_ENABLE; au_sync_delay(2); *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; au_sync_delay(2); retval = mii_probe(dev); if (retval) goto out2; retval = -EINVAL; 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 out2; 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 out2; 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; /* * 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); retval = register_netdev(dev); if (retval) goto out2; return 0;out2: dma_free(aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS));out1: free_netdev(dev);out: release_region(PHYSADDR(ioaddr), MAC_IOSIZE); 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 control; u16 link, speed; if (au1000_debug > 4) printk("%s: au1000_init\n", dev->name); spin_lock_irqsave(&aup->lock, flags); /* bring the device out of reset */ *aup->enable = MAC_EN_CLOCK_ENABLE; au_sync_delay(2); *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; au_sync_delay(20); 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; } au_sync(); aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;#ifndef CONFIG_CPU_LITTLE_ENDIAN control |= MAC_BIG_ENDIAN;#endif if (link && (dev->if_port == IF_PORT_100BASEFX)) { control |= MAC_FULL_DUPLEX; } aup->mac->control = control; au_sync(); 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; unsigned char if_port; u16 link, speed; if (!dev) { /* fatal error, don't restart the timer */ printk(KERN_ERR "au1000_timer error: NULL dev\n"); return; } if_port = dev->if_port; 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_INFO "%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_INFO "%s: link down\n", dev->name); } } } if (link && (dev->if_port != if_port) && (dev->if_port != IF_PORT_UNKNOWN)) { hard_stop(dev); if (dev->if_port == IF_PORT_100BASEFX) { printk(KERN_INFO "%s: going to full duplex\n", dev->name); aup->mac->control |= MAC_FULL_DUPLEX; au_sync_delay(1); } else { aup->mac->control &= ~MAC_FULL_DUPLEX; au_sync_delay(1); } enable_rx_tx(dev); } 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; if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); if ((retval = au1000_init(dev))) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?