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 + -
显示快捷键?