X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fau1000_eth.c;h=f0b6879a1c7d31463ab03da8682f8e23b68366c8;hb=refs%2Fheads%2Fvserver;hp=2bd0ac9594e5f96d8fbecd981fefbaa56447d68b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 2bd0ac959..f0b6879a1 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1,10 +1,22 @@ /* - * Alchemy Semi Au1000 ethernet driver * - * Copyright 2001 MontaVista Software Inc. + * Alchemy Au1x00 ethernet driver + * + * Copyright 2001-2003, 2006 MontaVista Software Inc. + * Copyright 2002 TimeSys Corp. + * Added ethtool/mii-tool support, + * Copyright 2004 Matt Porter + * 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 + * 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. @@ -17,487 +29,365 @@ * 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 #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include - +#include #include #include -#include #include -#include +#include +#include +#include #include "au1000_eth.h" #ifdef AU1000_ETH_DEBUG -static int au1000_debug = 10; +static int au1000_debug = 5; #else static int au1000_debug = 3; #endif +#define DRV_NAME "au1000_eth" +#define DRV_VERSION "1.6" +#define DRV_AUTHOR "Pete Popov " +#define DRV_DESC "Au1xxx on-chip Ethernet driver" + +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); + // prototypes -static void *dma_alloc(size_t, dma_addr_t *); -static void dma_free(void *, size_t); static void hard_stop(struct net_device *); static void enable_rx_tx(struct net_device *dev); -static int __init au1000_probe1(long, int, int); +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 *, struct pt_regs *); +static irqreturn_t au1000_interrupt(int, void *); static void au1000_tx_timeout(struct net_device *); -static int au1000_set_config(struct net_device *dev, struct ifmap *map); static void set_rx_mode(struct net_device *); static struct net_device_stats *au1000_get_stats(struct net_device *); -static inline void update_tx_stats(struct net_device *, u32, u32); -static inline void update_rx_stats(struct net_device *, u32); -static void au1000_timer(unsigned long); 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 dump_mii(struct net_device *dev, int phy_id); +static void au1000_adjust_link(struct net_device *); +static void enable_mac(struct net_device *, int); // externs -extern void ack_rise_edge_irq(unsigned int); extern int get_ethernet_addr(char *ethernet_addr); -extern inline void str2eaddr(unsigned char *ea, unsigned char *str); -extern inline unsigned char str2hexnum(unsigned char c); -extern char * __init prom_getcmdline(void); +extern void str2eaddr(unsigned char *ea, unsigned char *str); +extern char * prom_getcmdline(void); /* * 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 + * 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 + * 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. */ - -/* - * Base address and interrupt of the Au1xxx ethernet macs - */ -static struct { - unsigned int port; - int irq; -} au1000_iflist[NUM_INTERFACES] = { - {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, - {AU1000_ETH1_BASE, AU1000_ETH1_IRQ} - }, - au1500_iflist[NUM_INTERFACES] = { - {AU1500_ETH0_BASE, AU1000_ETH0_IRQ}, - {AU1500_ETH1_BASE, AU1000_ETH1_IRQ} - }, - au1100_iflist[NUM_INTERFACES] = { - {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, - {0, 0} - }; - -static char version[] __devinitdata = - "au1000eth.c:1.0 ppopov@mvista.com\n"; - /* 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 = { +static unsigned char au1000_mac_addr[6] __devinitdata = { 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00 }; -#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) -#define RUN_AT(x) (jiffies + (x)) +struct au1000_private *au_macs[NUM_ETH_INTERFACES]; -// For reading/writing 32-bit words from/to DMA memory -#define cpu_to_dma32 cpu_to_be32 -#define dma32_to_cpu be32_to_cpu - - -/* FIXME - * All of the PHY code really should be detached from the MAC - * code. +/* + * 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. */ -int bcm_5201_init(struct net_device *dev, int phy_addr) -{ - s16 data; - - /* Stop auto-negotiation */ - //printk("bcm_5201_init\n"); - data = mdio_read(dev, phy_addr, MII_CONTROL); - mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO); - - /* Set advertisement to 10/100 and Half/Full duplex - * (full capabilities) */ - data = mdio_read(dev, phy_addr, MII_ANADV); - data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T; - mdio_write(dev, phy_addr, MII_ANADV, data); - - /* Restart auto-negotiation */ - data = mdio_read(dev, phy_addr, MII_CONTROL); - data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO; - mdio_write(dev, phy_addr, MII_CONTROL, data); - - /* Enable TX LED instead of FDX */ - data = mdio_read(dev, phy_addr, MII_INT); - data &= ~MII_FDX_LED; - mdio_write(dev, phy_addr, MII_INT, data); - - /* Enable TX LED instead of FDX */ - data = mdio_read(dev, phy_addr, MII_INT); - data &= ~MII_FDX_LED; - mdio_write(dev, phy_addr, MII_INT, data); - - if (au1000_debug > 4) dump_mii(dev, phy_addr); - return 0; -} - -int bcm_5201_reset(struct net_device *dev, int phy_addr) -{ - s16 mii_control, timeout; - - //printk("bcm_5201_reset\n"); - mii_control = mdio_read(dev, phy_addr, MII_CONTROL); - mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET); - mdelay(1); - for (timeout = 100; timeout > 0; --timeout) { - mii_control = mdio_read(dev, phy_addr, MII_CONTROL); - if ((mii_control & MII_CNTL_RESET) == 0) - break; - mdelay(1); - } - if (mii_control & MII_CNTL_RESET) { - printk(KERN_ERR "%s PHY reset timeout !\n", dev->name); - return -1; - } - return 0; -} - -int -bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) -{ - u16 mii_data; - struct au1000_private *aup; - - if (!dev) { - printk(KERN_ERR "bcm_5201_status error: NULL dev\n"); - return -1; - } - aup = (struct au1000_private *) dev->priv; - - mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS); - if (mii_data & MII_STAT_LINK) { - *link = 1; - mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL); - if (mii_data & MII_AUX_100) { - if (mii_data & MII_AUX_FDX) { - *speed = IF_PORT_100BASEFX; - dev->if_port = IF_PORT_100BASEFX; - } - else { - *speed = IF_PORT_100BASETX; - dev->if_port = IF_PORT_100BASETX; - } - } - else { - *speed = IF_PORT_10BASET; - dev->if_port = IF_PORT_10BASET; - } +/* autodetection defaults */ +#undef AU1XXX_PHY_SEARCH_HIGHEST_ADDR +#define AU1XXX_PHY1_SEARCH_ON_MAC0 - } - else { - *link = 0; - *speed = 0; - dev->if_port = IF_PORT_UNKNOWN; - } - return 0; -} - -int lsi_80227_init(struct net_device *dev, int phy_addr) -{ - if (au1000_debug > 4) - printk("lsi_80227_init\n"); - - /* restart auto-negotiation */ - mdio_write(dev, phy_addr, 0, 0x3200); - - mdelay(1); - - /* set up LEDs to correct display */ - mdio_write(dev, phy_addr, 17, 0xffc0); - - if (au1000_debug > 4) - dump_mii(dev, phy_addr); - return 0; -} - -int lsi_80227_reset(struct net_device *dev, int phy_addr) -{ - s16 mii_control, timeout; - - if (au1000_debug > 4) { - printk("lsi_80227_reset\n"); - dump_mii(dev, phy_addr); - } - - mii_control = mdio_read(dev, phy_addr, MII_CONTROL); - mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET); - mdelay(1); - for (timeout = 100; timeout > 0; --timeout) { - mii_control = mdio_read(dev, phy_addr, MII_CONTROL); - if ((mii_control & MII_CNTL_RESET) == 0) - break; - mdelay(1); - } - if (mii_control & MII_CNTL_RESET) { - printk(KERN_ERR "%s PHY reset timeout !\n", dev->name); - return -1; - } - return 0; -} - -int -lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) -{ - u16 mii_data; - struct au1000_private *aup; - - if (!dev) { - printk(KERN_ERR "lsi_80227_status error: NULL dev\n"); - return -1; - } - aup = (struct au1000_private *) dev->priv; - - mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS); - if (mii_data & MII_STAT_LINK) { - *link = 1; - mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_STAT); - if (mii_data & MII_LSI_STAT_SPD) { - if (mii_data & MII_LSI_STAT_FDX) { - *speed = IF_PORT_100BASEFX; - dev->if_port = IF_PORT_100BASEFX; - } - else { - *speed = IF_PORT_100BASETX; - dev->if_port = IF_PORT_100BASETX; - } - } - else { - *speed = IF_PORT_10BASET; - dev->if_port = IF_PORT_10BASET; - } - - } - else { - *link = 0; - *speed = 0; - dev->if_port = IF_PORT_UNKNOWN; - } - return 0; -} - -int am79c901_init(struct net_device *dev, int phy_addr) -{ - printk("am79c901_init\n"); - return 0; -} - -int am79c901_reset(struct net_device *dev, int phy_addr) -{ - printk("am79c901_reset\n"); - return 0; -} - -int -am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) -{ - return 0; -} +/* 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 + */ -struct phy_ops bcm_5201_ops = { - bcm_5201_init, - bcm_5201_reset, - bcm_5201_status, -}; +#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 -struct phy_ops am79c901_ops = { - am79c901_init, - am79c901_reset, - am79c901_status, -}; +# define AU1XXX_PHY0_ADDR 5 +# define AU1XXX_PHY0_BUSID 0 +# undef AU1XXX_PHY0_IRQ -struct phy_ops lsi_80227_ops = { - lsi_80227_init, - lsi_80227_reset, - lsi_80227_status, -}; +# undef AU1XXX_PHY1_ADDR +# undef AU1XXX_PHY1_BUSID +# undef AU1XXX_PHY1_IRQ +#endif -static struct mii_chip_info { - const char * name; - u16 phy_id0; - u16 phy_id1; - struct phy_ops *phy_ops; -} mii_chip_table[] = { - {"Broadcom BCM5201 10/100 BaseT PHY", 0x0040, 0x6212, &bcm_5201_ops }, - {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, &am79c901_ops }, - {"LSI 80227 10/100 BaseT PHY", 0x0016, 0xf840, &lsi_80227_ops }, - {"Broadcom BCM5221 10/100 BaseT PHY", 0x0040, 0x61e4, &bcm_5201_ops }, - {0,}, -}; +#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0) +# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet +#endif -static int mdio_read(struct net_device *dev, int phy_id, int reg) +/* + * 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 (aup->mac->mii_control & MAC_MII_BUSY) { + while (*mii_control_reg & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII busy timeout!!\n", + 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_id) | MAC_MII_READ; + mii_control = MAC_SET_MII_SELECT_REG(reg) | + MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ; - aup->mac->mii_control = mii_control; + *mii_control_reg = mii_control; timedout = 20; - while (aup->mac->mii_control & MAC_MII_BUSY) { + while (*mii_control_reg & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: mdio_read busy timeout!!\n", + printk(KERN_ERR "%s: mdio_read busy timeout!!\n", dev->name); return -1; } } - return (int)aup->mac->mii_data; + return (int)*mii_data_reg; } -static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value) +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 (aup->mac->mii_control & MAC_MII_BUSY) { + while (*mii_control_reg & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: mdio_write busy timeout!!\n", + 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_id) | MAC_MII_WRITE; + 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; - aup->mac->mii_data = value; - aup->mac->mii_control = mii_control; + 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 void dump_mii(struct net_device *dev, int phy_id) +static int mdiobus_reset(struct mii_bus *bus) { - int i, val; + struct net_device *const dev = bus->priv; - for (i = 0; i < 7; i++) { - if ((val = mdio_read(dev, phy_id, i)) >= 0) - printk("%s: MII Reg %d=%x\n", dev->name, i, val); - } - for (i = 16; i < 25; i++) { - if ((val = mdio_read(dev, phy_id, i)) >= 0) - printk("%s: MII Reg %d=%x\n", dev->name, i, val); - } + enable_mac(dev, 0); /* make sure the MAC associated with this + * mii_bus is enabled */ + return 0; } -static int __init mii_probe (struct net_device * dev) +static int mii_probe (struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + 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; - aup->mii = NULL; + /* 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 + } - /* search for total of 32 possible mii phy addresses */ - for (phy_addr = 0; phy_addr < 32; phy_addr++) { - u16 mii_status; - u16 phy_id0, phy_id1; - int i; +# 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"); - mii_status = mdio_read(dev, phy_addr, MII_STATUS); - if (mii_status == 0xffff || mii_status == 0x0000) - /* the mii is not accessible, try next one */ - continue; - - phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0); - phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1); - - /* search our mii table for the current mii */ - for (i = 0; mii_chip_table[i].phy_id1; i++) { - if (phy_id0 == mii_chip_table[i].phy_id0 && - phy_id1 == mii_chip_table[i].phy_id1) { - struct mii_phy * mii_phy; - - printk(KERN_INFO "%s: %s at phy address %d\n", - dev->name, mii_chip_table[i].name, - phy_addr); - 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; - } + 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) */ - if (aup->mii == NULL) { - printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name); +#endif /* defined(AU1XXX_PHY_STATIC_CONFIG) */ + if (!phydev) { + printk (KERN_ERR DRV_NAME ":%s: no PHY 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); + /* 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; } @@ -505,7 +395,7 @@ static int __init mii_probe (struct net_device * dev) /* * Buffer allocation/deallocation routines. The buffer descriptor returned - * has the virtual and dma address of a buffer suitable for + * 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) @@ -516,7 +406,6 @@ static db_dest_t *GetFreeDB(struct au1000_private *aup) if (pDB) { aup->pDBfree = pDB->pnext; } - //printk("GetFreeDB: %x\n", pDB); return pDB; } @@ -528,35 +417,6 @@ void ReleaseDB(struct au1000_private *aup, db_dest_t *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; @@ -579,184 +439,309 @@ static void hard_stop(struct net_device *dev) au_sync_delay(10); } - -static void reset_mac(struct net_device *dev) +static void enable_mac(struct net_device *dev, int force_reset) { - u32 flags; + unsigned long 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); + + 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; + *aup->enable = 0; au_sync_delay(2); + aup->tx_full = 0; - spin_unlock_irqrestore(&aup->lock, flags); + 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 void +static void setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base) { int i; - for (i=0; irx_dma_ring[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; itx_dma_ring[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 interupt 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 i; - int prid; - int base_addr, irq; - - prid = read_c0_prid(); - for (i=0; i> 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; } -static int __init -au1000_probe1(long ioaddr, int irq, int port_num) +/* + * 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 void +au1000_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) { - struct net_device *dev; static unsigned version_printed = 0; struct au1000_private *aup = NULL; - int i, retval = 0; + struct net_device *dev = NULL; db_dest_t *pDB, *pDBfree; char *pmac, *argptr; char ethaddr[6]; + int irq, i, err; + u32 base, macen; - if (!request_region(PHYSADDR(ioaddr), MAC_IOSIZE, "Au1000 ENET")) - return -ENODEV; + if (port_num >= NUM_ETH_INTERFACES) + return NULL; - if (version_printed++ == 0) - printk(version); + 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; - retval = -ENOMEM; + 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 "au1000 eth: alloc_etherdev failed\n"); - goto out; + printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME); + return NULL; } - SET_MODULE_OWNER(dev); + 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: Au1xxx ethernet found at 0x%lx, irq %d\n", - dev->name, ioaddr, irq); + printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n", + dev->name, base, 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; + /* 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 *)((unsigned long)ioaddr); + aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr; + /* 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 { + aup->enable = (volatile u32 *)iflist[port_num].macen_addr; + aup->mac_id = port_num; + au_macs[port_num] = aup; + + if (port_num == 0) { + /* Check the environment variables first */ + if (get_ethernet_addr(ethaddr) == 0) + memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_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 { + 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)); + memcpy(au1000_mac_addr, ethaddr, + sizeof(au1000_mac_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; + } else if (port_num == 1) 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); + /* + * 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); - retval = mii_probe(dev); - if (retval) - goto out2; + if (mii_probe(dev) != 0) { + goto err_out; + } - 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++) { + 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); @@ -765,22 +750,26 @@ au1000_probe1(long ioaddr, int irq, int port_num) } aup->pDBfree = pDBfree; - for (i=0; irx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; aup->rx_db_inuse[i] = pDB; } - for (i=0; itx_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->base_addr = base; dev->irq = irq; dev->open = au1000_open; dev->hard_start_xmit = au1000_tx; @@ -788,34 +777,41 @@ au1000_probe1(long ioaddr, int irq, int port_num) dev->get_stats = au1000_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &au1000_ioctl; - dev->set_config = &au1000_set_config; + 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 + /* + * 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; + return dev; -out2: - dma_free(aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); -out1: +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); -out: - release_region(PHYSADDR(ioaddr), MAC_IOSIZE); - printk(KERN_ERR "%s: au1000_probe1 failed. Returns %d\n", - dev->name, retval); - return retval; + 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 @@ -830,18 +826,14 @@ static int au1000_init(struct net_device *dev) 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); + if (au1000_debug > 4) + printk("%s: au1000_init\n", dev->name); /* 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); + 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; @@ -852,79 +844,110 @@ static int au1000_init(struct net_device *dev) 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; irx_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; + control = MAC_RX_ENABLE | MAC_TX_ENABLE; #ifndef CONFIG_CPU_LITTLE_ENDIAN control |= MAC_BIG_ENDIAN; #endif - if (link && (dev->if_port == IF_PORT_100BASEFX)) { + 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 void au1000_timer(unsigned long data) +static void +au1000_adjust_link(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; struct au1000_private *aup = (struct au1000_private *) dev->priv; - unsigned char if_port; - u16 link, speed; + struct phy_device *phydev = aup->phy_dev; + unsigned long flags; - if (!dev) { - /* fatal error, don't restart the timer */ - printk(KERN_ERR "au1000_timer error: NULL dev\n"); - return; - } + int status_change = 0; - 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); - } + 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 + "%s: Speed (%d) is not 10/100 ???\n", + dev->name, phydev->speed); + break; } + + aup->old_speed = phydev->speed; + + status_change = 1; } - if (link && (dev->if_port != if_port) && - (dev->if_port != IF_PORT_UNKNOWN)) { + if (phydev->link && (aup->old_duplex != phydev->duplex)) { + // duplex mode changed + + /* switching duplex mode requires to disable rx and tx! */ 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); - } + + if (DUPLEX_FULL == phydev->duplex) + aup->mac->control = ((aup->mac->control + | MAC_FULL_DUPLEX) + & ~MAC_DISABLE_RX_OWN); + else + aup->mac->control = ((aup->mac->control + & ~MAC_FULL_DUPLEX) + | MAC_DISABLE_RX_OWN); + au_sync_delay(1); + enable_rx_tx(dev); + aup->old_duplex = phydev->duplex; + + status_change = 1; } - aup->timer.expires = RUN_AT((1*HZ)); - aup->timer.data = (unsigned long)dev; - aup->timer.function = &au1000_timer; /* timer handler */ - add_timer(&aup->timer); + if(phydev->link != aup->old_link) { + // link state changed + if (phydev->link) // link went up + netif_schedule(dev); + else { // link went down + aup->old_speed = 0; + aup->old_duplex = -1; + } + + aup->old_link = phydev->link; + status_change = 1; + } + + spin_unlock_irqrestore(&aup->lock, flags); + + if (status_change) { + if (phydev->link) + printk(KERN_INFO "%s: link up (%d/%s)\n", + dev->name, phydev->speed, + DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); + else + printk(KERN_INFO "%s: link down\n", dev->name); + } } static int au1000_open(struct net_device *dev) @@ -935,24 +958,26 @@ static int au1000_open(struct net_device *dev) if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, 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); + return retval; + } + if ((retval = au1000_init(dev))) { printk(KERN_ERR "%s: error in au1000_init\n", dev->name); free_irq(dev->irq, dev); 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); - return retval; + if (aup->phy_dev) { + /* cause the PHY state machine to schedule a link state check */ + aup->phy_dev->state = PHY_CHANGELINK; + phy_start(aup->phy_dev); } - aup->timer.expires = RUN_AT((3*HZ)); - aup->timer.data = (unsigned long)dev; - aup->timer.function = &au1000_timer; /* timer handler */ - add_timer(&aup->timer); + netif_start_queue(dev); if (au1000_debug > 4) printk("%s: open: Initialization done.\n", dev->name); @@ -962,42 +987,63 @@ static int au1000_open(struct net_device *dev) static int au1000_close(struct net_device *dev) { - u32 flags; - struct au1000_private *aup = (struct au1000_private *) dev->priv; + unsigned long flags; + struct au1000_private *const aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk("%s: close: dev=%p\n", dev->name, dev); + if (aup->phy_dev) + phy_stop(aup->phy_dev); + spin_lock_irqsave(&aup->lock, flags); - + + reset_mac_unlocked (dev); + /* stop the device */ - if (netif_device_present(dev)) - netif_stop_queue(dev); + netif_stop_queue(dev); /* disable the interrupt */ free_irq(dev->irq, dev); spin_unlock_irqrestore(&aup->lock, flags); - reset_mac(dev); return 0; } static void __exit au1000_cleanup_module(void) { -} + int i, j; + struct net_device *dev; + struct au1000_private *aup; + for (i = 0; i < num_ifs; i++) { + dev = iflist[i].dev; + if (dev) { + aup = (struct au1000_private *) dev->priv; + unregister_netdev(dev); + for (j = 0; j < NUM_RX_DMA; j++) + if (aup->rx_db_inuse[j]) + ReleaseDB(aup, aup->rx_db_inuse[j]); + for (j = 0; j < NUM_TX_DMA; j++) + if (aup->tx_db_inuse[j]) + ReleaseDB(aup, aup->tx_db_inuse[j]); + dma_free_noncoherent(NULL, MAX_BUF_SIZE * + (NUM_TX_BUFFS + NUM_RX_BUFFS), + (void *)aup->vaddr, aup->dma_addr); + release_mem_region(dev->base_addr, MAC_IOSIZE); + release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4); + free_netdev(dev); + } + } +} -static inline void -update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +static void update_tx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; struct net_device_stats *ps = &aup->stats; - ps->tx_packets++; - ps->tx_bytes += pkt_len; - if (status & TX_FRAME_ABORTED) { - if (dev->if_port == IF_PORT_100BASEFX) { + if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) { if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) { /* any other tx errors are only valid * in half duplex mode */ @@ -1028,9 +1074,8 @@ static void au1000_tx_ack(struct net_device *dev) ptxd = aup->tx_dma_ring[aup->tx_tail]; while (ptxd->buff_stat & TX_T_DONE) { - update_tx_stats(dev, ptxd->status, aup->tx_len[aup->tx_tail] & 0x3ff); + update_tx_stats(dev, ptxd->status); ptxd->buff_stat &= ~TX_T_DONE; - aup->tx_len[aup->tx_tail] = 0; ptxd->len = 0; au_sync(); @@ -1051,14 +1096,15 @@ static void au1000_tx_ack(struct net_device *dev) static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; int i; - if (au1000_debug > 4) - printk("%s: tx: aup %x len=%d, data=%p, head %d\n", - dev->name, (unsigned)aup, skb->len, + if (au1000_debug > 5) + printk("%s: tx: aup %x len=%d, data=%p, head %d\n", + dev->name, (unsigned)aup, skb->len, skb->data, aup->tx_head); ptxd = aup->tx_dma_ring[aup->tx_head]; @@ -1070,8 +1116,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) return 1; } else if (buff_stat & TX_T_DONE) { - update_tx_stats(dev, ptxd->status, aup->tx_len[aup->tx_head] & 0x3ff); - aup->tx_len[aup->tx_head] = 0; + update_tx_stats(dev, ptxd->status); ptxd->len = 0; } @@ -1082,17 +1127,18 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) pDB = aup->tx_db_inuse[aup->tx_head]; memcpy((void *)pDB->vaddr, skb->data, skb->len); - if (skb->len < MAC_MIN_PKT_SIZE) { - for (i=skb->len; ilen < ETH_ZLEN) { + for (i=skb->len; ivaddr)[i] = 0; } - aup->tx_len[aup->tx_head] = MAC_MIN_PKT_SIZE; - ptxd->len = MAC_MIN_PKT_SIZE; + ptxd->len = ETH_ZLEN; } - else { - aup->tx_len[aup->tx_head] = skb->len; + else ptxd->len = skb->len; - } + + ps->tx_packets++; + ps->tx_bytes += ptxd->len; + ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; au_sync(); dev_kfree_skb(skb); @@ -1101,7 +1147,6 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) return 0; } - static inline void update_rx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; @@ -1122,7 +1167,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status) if (status & RX_COLL) ps->collisions++; } - else + else ps->rx_bytes += status & RX_FRAME_LEN_MASK; } @@ -1137,8 +1182,9 @@ static int au1000_rx(struct net_device *dev) volatile rx_dma_t *prxd; u32 buff_stat, status; db_dest_t *pDB; + u32 frmlen; - if (au1000_debug > 4) + if (au1000_debug > 5) printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head); prxd = aup->rx_dma_ring[aup->rx_head]; @@ -1150,7 +1196,9 @@ static int au1000_rx(struct net_device *dev) if (!(status & RX_ERROR)) { /* good frame */ - skb = dev_alloc_skb((status & RX_FRAME_LEN_MASK) + 2); + frmlen = (status & RX_FRAME_LEN_MASK); + frmlen -= 4; /* Remove FCS */ + skb = dev_alloc_skb(frmlen + 2); if (skb == NULL) { printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", @@ -1160,21 +1208,21 @@ static int au1000_rx(struct net_device *dev) } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte IP header align */ - eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, - status & RX_FRAME_LEN_MASK, 0); - skb_put(skb, status & RX_FRAME_LEN_MASK); + eth_copy_and_sum(skb, + (unsigned char *)pDB->vaddr, frmlen, 0); + skb_put(skb, frmlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* pass the packet to upper layers */ } else { if (au1000_debug > 4) { - if (status & RX_MISSED_FRAME) + if (status & RX_MISSED_FRAME) printk("rx miss\n"); - if (status & RX_WDOG_TIMER) + if (status & RX_WDOG_TIMER) printk("rx wdog\n"); - if (status & RX_RUNT) + if (status & RX_RUNT) printk("rx runt\n"); - if (status & RX_OVERLEN) + if (status & RX_OVERLEN) printk("rx overlen\n"); if (status & RX_COLL) printk("rx coll\n"); @@ -1206,17 +1254,20 @@ static int au1000_rx(struct net_device *dev) /* * Au1000 interrupt service routine. */ -irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t au1000_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; if (dev == NULL) { printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); - return IRQ_NONE; + return IRQ_RETVAL(1); } - au1000_tx_ack(dev); + + /* Handle RX interrupts first to minimize chance of overrun */ + au1000_rx(dev); - return IRQ_HANDLED; + au1000_tx_ack(dev); + return IRQ_RETVAL(1); } @@ -1237,12 +1288,11 @@ static void set_rx_mode(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - if (au1000_debug > 4) + if (au1000_debug > 4) printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ aup->mac->control |= MAC_PROMISCUOUS; - printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > MULTICAST_FILTER_LIMIT) { aup->mac->control |= MAC_PASS_ALL_MULTI; @@ -1256,8 +1306,8 @@ static void set_rx_mode(struct net_device *dev) mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr)>>26, - mc_filter); + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, + (long *)mc_filter); } aup->mac->multi_hash_high = mc_filter[1]; aup->mac->multi_hash_low = mc_filter[0]; @@ -1266,127 +1316,15 @@ static void set_rx_mode(struct net_device *dev) } } - static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - u16 *data = (u16 *)&rq->ifr_data; - - /* fixme */ - switch(cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - data[0] = PHY_ADDRESS; - return 0; - - case SIOCGMIIREG: /* Read the specified MII register. */ - //data[3] = mdio_read(ioaddr, data[0], data[1]); - return 0; - - case SIOCSMIIREG: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - //mdio_write(ioaddr, data[0], data[1], data[2]); - return 0; - - default: - return -EOPNOTSUPP; - } -} - - -static int au1000_set_config(struct net_device *dev, struct ifmap *map) -{ - struct au1000_private *aup = (struct au1000_private *) dev->priv; - u16 control; + struct au1000_private *aup = (struct au1000_private *)dev->priv; - if (au1000_debug > 4) { - printk("%s: set_config called: dev->if_port %d map->port %x\n", - dev->name, dev->if_port, map->port); - } + if (!netif_running(dev)) return -EINVAL; - switch(map->port){ - case IF_PORT_UNKNOWN: /* use auto here */ - printk(KERN_INFO "%s: config phy for aneg\n", - dev->name); - dev->if_port = map->port; - /* Link Down: the timer will bring it up */ - netif_carrier_off(dev); - - /* read current control */ - control = mdio_read(dev, aup->phy_addr, MII_CONTROL); - control &= ~(MII_CNTL_FDX | MII_CNTL_F100); - - /* enable auto negotiation and reset the negotiation */ - mdio_write(dev, aup->phy_addr, MII_CONTROL, - control | MII_CNTL_AUTO | - MII_CNTL_RST_AUTO); + if (!aup->phy_dev) return -EINVAL; // PHY not controllable - break; - - case IF_PORT_10BASET: /* 10BaseT */ - printk(KERN_INFO "%s: config phy for 10BaseT\n", - dev->name); - dev->if_port = map->port; - - /* Link Down: the timer will bring it up */ - netif_carrier_off(dev); - - /* set Speed to 10Mbps, Half Duplex */ - control = mdio_read(dev, aup->phy_addr, MII_CONTROL); - control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | - MII_CNTL_FDX); - - /* disable auto negotiation and force 10M/HD mode*/ - mdio_write(dev, aup->phy_addr, MII_CONTROL, control); - break; - - case IF_PORT_100BASET: /* 100BaseT */ - case IF_PORT_100BASETX: /* 100BaseTx */ - printk(KERN_INFO "%s: config phy for 100BaseTX\n", - dev->name); - dev->if_port = map->port; - - /* Link Down: the timer will bring it up */ - netif_carrier_off(dev); - - /* set Speed to 100Mbps, Half Duplex */ - /* disable auto negotiation and enable 100MBit Mode */ - control = mdio_read(dev, aup->phy_addr, MII_CONTROL); - printk("read control %x\n", control); - control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX); - control |= MII_CNTL_F100; - mdio_write(dev, aup->phy_addr, MII_CONTROL, control); - break; - - case IF_PORT_100BASEFX: /* 100BaseFx */ - printk(KERN_INFO "%s: config phy for 100BaseFX\n", - dev->name); - dev->if_port = map->port; - - /* Link Down: the timer will bring it up */ - netif_carrier_off(dev); - - /* set Speed to 100Mbps, Full Duplex */ - /* disable auto negotiation and enable 100MBit Mode */ - control = mdio_read(dev, aup->phy_addr, MII_CONTROL); - control &= ~MII_CNTL_AUTO; - control |= MII_CNTL_F100 | MII_CNTL_FDX; - mdio_write(dev, aup->phy_addr, MII_CONTROL, control); - break; - case IF_PORT_10BASE2: /* 10Base2 */ - case IF_PORT_AUI: /* AUI */ - /* These Modes are not supported (are they?)*/ - printk(KERN_ERR "%s: 10Base2/AUI not supported", - dev->name); - return -EOPNOTSUPP; - break; - - default: - printk(KERN_ERR "%s: Invalid media selected", - dev->name); - return -EINVAL; - } - return 0; + return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd); } static struct net_device_stats *au1000_get_stats(struct net_device *dev)