au1000_eth.c
来自「linux 内核源代码」· C语言 代码 · 共 1,315 行 · 第 1/3 页
C
1,315 行
/* * * Alchemy Au1x00 ethernet driver * * Copyright 2001-2003, 2006 MontaVista Software Inc. * Copyright 2002 TimeSys Corp. * Added ethtool/mii-tool support, * Copyright 2004 Matt Porter <mporter@kernel.crashing.org> * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de * or riemer@riemer-nt.de: fixed the link beat detection with * ioctls (SIOCGMIIPHY) * Copyright 2006 Herbert Valerio Riedel <hvr@gnu.org> * converted to use linux-2.6.x's PHY framework * * Author: MontaVista Software, Inc. * ppopov@mvista.com or source@mvista.com * * ######################################################################## * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * ######################################################################## * * */#include <linux/dma-mapping.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/in.h>#include <linux/ioport.h>#include <linux/bitops.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/crc32.h>#include <linux/phy.h>#include <asm/cpu.h>#include <asm/mipsregs.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/processor.h>#include <au1000.h>#include <prom.h>#include "au1000_eth.h"#ifdef AU1000_ETH_DEBUGstatic int au1000_debug = 5;#elsestatic int au1000_debug = 3;#endif#define DRV_NAME "au1000_eth"#define DRV_VERSION "1.6"#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"#define DRV_DESC "Au1xxx on-chip Ethernet driver"MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPTION(DRV_DESC);MODULE_LICENSE("GPL");// prototypesstatic void hard_stop(struct net_device *);static void enable_rx_tx(struct net_device *dev);static struct net_device * au1000_probe(int port_num);static int au1000_init(struct net_device *);static int au1000_open(struct net_device *);static int au1000_close(struct net_device *);static int au1000_tx(struct sk_buff *, struct net_device *);static int au1000_rx(struct net_device *);static irqreturn_t au1000_interrupt(int, void *);static void au1000_tx_timeout(struct net_device *);static void set_rx_mode(struct net_device *);static int au1000_ioctl(struct net_device *, struct ifreq *, int);static int mdio_read(struct net_device *, int, int);static void mdio_write(struct net_device *, int, int, u16);static void au1000_adjust_link(struct net_device *);static void enable_mac(struct net_device *, int);/* * Theory of operation * * The Au1000 MACs use a simple rx and tx descriptor ring scheme. * There are four receive and four transmit descriptors. These * descriptors are not in memory; rather, they are just a set of * hardware registers. * * Since the Au1000 has a coherent data cache, the receive and * transmit buffers are allocated from the KSEG0 segment. The * hardware registers, however, are still mapped at KSEG1 to * make sure there's no out-of-order writes, and that all writes * complete immediately. *//* These addresses are only used if yamon doesn't tell us what * the mac address is, and the mac address is not passed on the * command line. */static unsigned char au1000_mac_addr[6] __devinitdata = { 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00};struct au1000_private *au_macs[NUM_ETH_INTERFACES];/* * board-specific configurations * * PHY detection algorithm * * If AU1XXX_PHY_STATIC_CONFIG is undefined, the PHY setup is * autodetected: * * mii_probe() first searches the current MAC's MII bus for a PHY, * selecting the first (or last, if AU1XXX_PHY_SEARCH_HIGHEST_ADDR is * defined) PHY address not already claimed by another netdev. * * If nothing was found that way when searching for the 2nd ethernet * controller's PHY and AU1XXX_PHY1_SEARCH_ON_MAC0 is defined, then * the first MII bus is searched as well for an unclaimed PHY; this is * needed in case of a dual-PHY accessible only through the MAC0's MII * bus. * * Finally, if no PHY is found, then the corresponding ethernet * controller is not registered to the network subsystem. *//* autodetection defaults */#undef AU1XXX_PHY_SEARCH_HIGHEST_ADDR#define AU1XXX_PHY1_SEARCH_ON_MAC0/* static PHY setup * * most boards PHY setup should be detectable properly with the * autodetection algorithm in mii_probe(), but in some cases (e.g. if * you have a switch attached, or want to use the PHY's interrupt * notification capabilities) you can provide a static PHY * configuration here * * IRQs may only be set, if a PHY address was configured * If a PHY address is given, also a bus id is required to be set * * ps: make sure the used irqs are configured properly in the board * specific irq-map */#if defined(CONFIG_MIPS_BOSPORUS)/* * Micrel/Kendin 5 port switch attached to MAC0, * MAC0 is associated with PHY address 5 (== WAN port) * MAC1 is not associated with any PHY, since it's connected directly * to the switch. * no interrupts are used */# define AU1XXX_PHY_STATIC_CONFIG# define AU1XXX_PHY0_ADDR 5# define AU1XXX_PHY0_BUSID 0# undef AU1XXX_PHY0_IRQ# undef AU1XXX_PHY1_ADDR# undef AU1XXX_PHY1_BUSID# undef AU1XXX_PHY1_IRQ#endif#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0)# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet#endif/* * MII operations */static int mdio_read(struct net_device *dev, int phy_addr, int reg){ struct au1000_private *aup = (struct au1000_private *) dev->priv; volatile u32 *const mii_control_reg = &aup->mac->mii_control; volatile u32 *const mii_data_reg = &aup->mac->mii_data; u32 timedout = 20; u32 mii_control; while (*mii_control_reg & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { printk(KERN_ERR "%s: read_MII busy timeout!!\n", dev->name); return -1; } } mii_control = MAC_SET_MII_SELECT_REG(reg) | MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ; *mii_control_reg = mii_control; timedout = 20; while (*mii_control_reg & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { printk(KERN_ERR "%s: mdio_read busy timeout!!\n", dev->name); return -1; } } return (int)*mii_data_reg;}static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value){ struct au1000_private *aup = (struct au1000_private *) dev->priv; volatile u32 *const mii_control_reg = &aup->mac->mii_control; volatile u32 *const mii_data_reg = &aup->mac->mii_data; u32 timedout = 20; u32 mii_control; while (*mii_control_reg & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { printk(KERN_ERR "%s: mdio_write busy timeout!!\n", dev->name); return; } } mii_control = MAC_SET_MII_SELECT_REG(reg) | MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE; *mii_data_reg = value; *mii_control_reg = mii_control;}static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum){ /* WARNING: bus->phy_map[phy_addr].attached_dev == dev does * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */ struct net_device *const dev = bus->priv; enable_mac(dev, 0); /* make sure the MAC associated with this * mii_bus is enabled */ return mdio_read(dev, phy_addr, regnum);}static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value){ struct net_device *const dev = bus->priv; enable_mac(dev, 0); /* make sure the MAC associated with this * mii_bus is enabled */ mdio_write(dev, phy_addr, regnum, value); return 0;}static int mdiobus_reset(struct mii_bus *bus){ struct net_device *const dev = bus->priv; enable_mac(dev, 0); /* make sure the MAC associated with this * mii_bus is enabled */ return 0;}static int mii_probe (struct net_device *dev){ struct au1000_private *const aup = (struct au1000_private *) dev->priv; struct phy_device *phydev = NULL;#if defined(AU1XXX_PHY_STATIC_CONFIG) BUG_ON(aup->mac_id < 0 || aup->mac_id > 1); if(aup->mac_id == 0) { /* get PHY0 */# if defined(AU1XXX_PHY0_ADDR) phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus.phy_map[AU1XXX_PHY0_ADDR];# else printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n", dev->name); return 0;# endif /* defined(AU1XXX_PHY0_ADDR) */ } else if (aup->mac_id == 1) { /* get PHY1 */# if defined(AU1XXX_PHY1_ADDR) phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus.phy_map[AU1XXX_PHY1_ADDR];# else printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n", dev->name); return 0;# endif /* defined(AU1XXX_PHY1_ADDR) */ }#else /* defined(AU1XXX_PHY_STATIC_CONFIG) */ int phy_addr; /* find the first (lowest address) PHY on the current MAC's MII bus */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) if (aup->mii_bus.phy_map[phy_addr]) { phydev = aup->mii_bus.phy_map[phy_addr];# if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR) break; /* break out with first one found */# endif }# if defined(AU1XXX_PHY1_SEARCH_ON_MAC0) /* try harder to find a PHY */ if (!phydev && (aup->mac_id == 1)) { /* no PHY found, maybe we have a dual PHY? */ printk (KERN_INFO DRV_NAME ": no PHY found on MAC1, " "let's see if it's attached to MAC0...\n"); BUG_ON(!au_macs[0]); /* find the first (lowest address) non-attached PHY on * the MAC0 MII bus */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { struct phy_device *const tmp_phydev = au_macs[0]->mii_bus.phy_map[phy_addr]; if (!tmp_phydev) continue; /* no PHY here... */ if (tmp_phydev->attached_dev) continue; /* already claimed by MAC0 */ phydev = tmp_phydev; break; /* found it */ } }# endif /* defined(AU1XXX_PHY1_SEARCH_OTHER_BUS) */#endif /* defined(AU1XXX_PHY_STATIC_CONFIG) */ if (!phydev) { printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name); return -1; } /* now we are supposed to have a proper phydev, to attach to... */ BUG_ON(!phydev); BUG_ON(phydev->attached_dev); phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0, PHY_INTERFACE_MODE_MII); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); return PTR_ERR(phydev); } /* mask with MAC supported features */ phydev->supported &= (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */ | SUPPORTED_MII | SUPPORTED_TP); phydev->advertising = phydev->supported; aup->old_link = 0; aup->old_speed = 0; aup->old_duplex = -1; aup->phy_dev = phydev; printk(KERN_INFO "%s: attached PHY driver [%s] " "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); 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; } 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;}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 enable_mac(struct net_device *dev, int force_reset){ unsigned long flags;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?