au1000_eth.c
来自「linux 内核源代码」· C语言 代码 · 共 1,315 行 · 第 1/3 页
C
1,315 行
struct au1000_private *aup = (struct au1000_private *) dev->priv; spin_lock_irqsave(&aup->lock, flags); if(force_reset || (!aup->mac_enabled)) { *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); aup->mac_enabled = 1; } spin_unlock_irqrestore(&aup->lock, flags);}static void reset_mac_unlocked(struct net_device *dev){ struct au1000_private *const aup = (struct au1000_private *) dev->priv; int i; hard_stop(dev); *aup->enable = MAC_EN_CLOCK_ENABLE; au_sync_delay(2); *aup->enable = 0; au_sync_delay(2); aup->tx_full = 0; for (i = 0; i < NUM_RX_DMA; i++) { /* reset control bits */ aup->rx_dma_ring[i]->buff_stat &= ~0xf; } for (i = 0; i < NUM_TX_DMA; i++) { /* reset control bits */ aup->tx_dma_ring[i]->buff_stat &= ~0xf; } aup->mac_enabled = 0;}static void reset_mac(struct net_device *dev){ struct au1000_private *const aup = (struct au1000_private *) dev->priv; unsigned long flags; if (au1000_debug > 4) printk(KERN_INFO "%s: reset mac, aup %x\n", dev->name, (unsigned)aup); spin_lock_irqsave(&aup->lock, flags); reset_mac_unlocked (dev); 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 voidsetup_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 struct { u32 base_addr; u32 macen_addr; int irq; struct net_device *dev;} iflist[2] = {#ifdef CONFIG_SOC_AU1000 {AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT}, {AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT}#endif#ifdef CONFIG_SOC_AU1100 {AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT}#endif#ifdef CONFIG_SOC_AU1500 {AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT}, {AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT}#endif#ifdef CONFIG_SOC_AU1550 {AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT}, {AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT}#endif};static int num_ifs;/* * Setup the base address and interrupt of the Au1xxx ethernet macs * based on cpu type and whether the interface is enabled in sys_pinfunc * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0. */static int __init au1000_init_module(void){ int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4); struct net_device *dev; int i, found_one = 0; num_ifs = NUM_ETH_INTERFACES - ni; for(i = 0; i < num_ifs; i++) { dev = au1000_probe(i); iflist[i].dev = dev; if (dev) found_one++; } if (!found_one) return -ENODEV; return 0;}/* * ethtool operations */static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct au1000_private *aup = (struct au1000_private *)dev->priv; if (aup->phy_dev) return phy_ethtool_gset(aup->phy_dev, cmd); return -EINVAL;}static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct au1000_private *aup = (struct au1000_private *)dev->priv; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (aup->phy_dev) return phy_ethtool_sset(aup->phy_dev, cmd); return -EINVAL;}static voidau1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct au1000_private *aup = (struct au1000_private *)dev->priv; strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); info->fw_version[0] = '\0'; sprintf(info->bus_info, "%s %d", DRV_NAME, aup->mac_id); info->regdump_len = 0;}static const struct ethtool_ops au1000_ethtool_ops = { .get_settings = au1000_get_settings, .set_settings = au1000_set_settings, .get_drvinfo = au1000_get_drvinfo, .get_link = ethtool_op_get_link,};static struct net_device * au1000_probe(int port_num){ static unsigned version_printed = 0; struct au1000_private *aup = NULL; struct net_device *dev = NULL; db_dest_t *pDB, *pDBfree; char ethaddr[6]; int irq, i, err; u32 base, macen; if (port_num >= NUM_ETH_INTERFACES) return NULL; base = CPHYSADDR(iflist[port_num].base_addr ); macen = CPHYSADDR(iflist[port_num].macen_addr); irq = iflist[port_num].irq; if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") || !request_mem_region(macen, 4, "Au1x00 ENET")) return NULL; if (version_printed++ == 0) printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR); dev = alloc_etherdev(sizeof(struct au1000_private)); if (!dev) { printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME); return NULL; } if ((err = register_netdev(dev)) != 0) { printk(KERN_ERR "%s: Cannot register net device, error %d\n", DRV_NAME, err); free_netdev(dev); return NULL; } printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n", dev->name, base, irq); aup = dev->priv; /* Allocate the data buffers */ /* Snooping works fine with eth on all au1xxx */ aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS), &aup->dma_addr, 0); if (!aup->vaddr) { free_netdev(dev); release_mem_region( base, MAC_IOSIZE); release_mem_region(macen, 4); return NULL; } /* aup->mac is the base address of the MAC's registers */ aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr; /* Setup some variables for quick register address access */ aup->enable = (volatile u32 *)iflist[port_num].macen_addr; aup->mac_id = port_num; au_macs[port_num] = aup; if (port_num == 0) { if (prom_get_ethernet_addr(ethaddr) == 0) memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr)); else { printk(KERN_INFO "%s: No MAC address found\n", dev->name); /* Use the hard coded MAC addresses */ } setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); } else if (port_num == 1) setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); /* * Assign to the Ethernet ports two consecutive MAC addresses * to match those that are printed on their stickers */ memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr)); dev->dev_addr[5] += port_num; *aup->enable = 0; aup->mac_enabled = 0; aup->mii_bus.priv = dev; aup->mii_bus.read = mdiobus_read; aup->mii_bus.write = mdiobus_write; aup->mii_bus.reset = mdiobus_reset; aup->mii_bus.name = "au1000_eth_mii"; aup->mii_bus.id = aup->mac_id; aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for(i = 0; i < PHY_MAX_ADDR; ++i) aup->mii_bus.irq[i] = PHY_POLL; /* if known, set corresponding PHY IRQs */#if defined(AU1XXX_PHY_STATIC_CONFIG)# if defined(AU1XXX_PHY0_IRQ) if (AU1XXX_PHY0_BUSID == aup->mii_bus.id) aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;# endif# if defined(AU1XXX_PHY1_IRQ) if (AU1XXX_PHY1_BUSID == aup->mii_bus.id) aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;# endif#endif mdiobus_register(&aup->mii_bus); if (mii_probe(dev) != 0) { goto err_out; } 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 err_out; } 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 err_out; } 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 = base; dev->irq = irq; dev->open = au1000_open; dev->hard_start_xmit = au1000_tx; dev->stop = au1000_close; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &au1000_ioctl; SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops); 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); return dev;err_out: /* here we should have a valid dev plus aup-> register addresses * so we can reset the mac properly.*/ reset_mac(dev); for (i = 0; i < NUM_RX_DMA; i++) { if (aup->rx_db_inuse[i]) ReleaseDB(aup, aup->rx_db_inuse[i]); } for (i = 0; i < NUM_TX_DMA; i++) { if (aup->tx_db_inuse[i]) ReleaseDB(aup, aup->tx_db_inuse[i]); } dma_free_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS), (void *)aup->vaddr, aup->dma_addr); unregister_netdev(dev); free_netdev(dev); release_mem_region( base, MAC_IOSIZE); release_mem_region(macen, 4); return NULL;}/* * 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; if (au1000_debug > 4) printk("%s: au1000_init\n", dev->name); /* bring the device out of reset */ enable_mac(dev, 1); spin_lock_irqsave(&aup->lock, flags); 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(); control = MAC_RX_ENABLE | MAC_TX_ENABLE;#ifndef CONFIG_CPU_LITTLE_ENDIAN control |= MAC_BIG_ENDIAN;#endif if (aup->phy_dev) { if (aup->phy_dev->link && (DUPLEX_FULL == aup->phy_dev->duplex)) control |= MAC_FULL_DUPLEX; else control |= MAC_DISABLE_RX_OWN; } else { /* PHY-less op, assume full-duplex */ control |= MAC_FULL_DUPLEX; } aup->mac->control = control; aup->mac->vlan1_tag = 0x8100; /* activate vlan support */ au_sync(); spin_unlock_irqrestore(&aup->lock, flags); return 0;}static voidau1000_adjust_link(struct net_device *dev){ struct au1000_private *aup = (struct au1000_private *) dev->priv; struct phy_device *phydev = aup->phy_dev; unsigned long flags; int status_change = 0; BUG_ON(!aup->phy_dev); spin_lock_irqsave(&aup->lock, flags); if (phydev->link && (aup->old_speed != phydev->speed)) { // speed changed switch(phydev->speed) { case SPEED_10: case SPEED_100: break; default: printk(KERN_WARNING
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?