Newer
Older
* 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
* 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/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/mipsregs.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/processor.h>
#include "au1000_eth.h"
#ifdef AU1000_ETH_DEBUG
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 <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1xxx on-chip Ethernet driver"
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");
/*
* 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
#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0)
# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet
static void enable_mac(struct net_device *dev, int force_reset)
{
unsigned long flags;
struct au1000_private *aup = netdev_priv(dev);
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);
}
/*
* MII operations
*/
static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
struct au1000_private *aup = netdev_priv(dev);
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",
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 au1000_mdio_write(struct net_device *dev, int phy_addr,
int reg, u16 value)
struct au1000_private *aup = netdev_priv(dev);
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",
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 au1000_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 au1000_mdio_read(dev, phy_addr, regnum);
static int au1000_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 */
au1000_mdio_write(dev, phy_addr, regnum, value);
static int au1000_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;
}
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
static void hard_stop(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
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_rx_tx(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
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
au1000_adjust_link(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
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
"%s: Speed (%d) is not 10/100 ???\n",
dev->name, phydev->speed);
break;
}
aup->old_speed = phydev->speed;
status_change = 1;
}
if (phydev->link && (aup->old_duplex != phydev->duplex)) {
// duplex mode changed
/* switching duplex mode requires to disable rx and tx! */
hard_stop(dev);
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;
}
if(phydev->link != aup->old_link) {
// link state changed
if (!phydev->link) {
/* 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 mii_probe (struct net_device *dev)
{
struct au1000_private *const aup = netdev_priv(dev);
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);
/* now we are supposed to have a proper phydev, to attach to... */
BUG_ON(phydev->attached_dev);
phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
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 reset_mac_unlocked(struct net_device *dev)
{
struct au1000_private *const aup = netdev_priv(dev);
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 = netdev_priv(dev);
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.
*/
setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
{
int i;
for (i = 0; i < NUM_RX_DMA; i++) {
(volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
}
for (i = 0; i < NUM_TX_DMA; 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
};
/*
* ethtool operations
*/
static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
struct au1000_private *aup = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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,
/*
* 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 = netdev_priv(dev);
unsigned long 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);
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;
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 inline void update_rx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = netdev_priv(dev);
struct net_device_stats *ps = &dev->stats;
ps->rx_packets++;
if (status & RX_MCAST_FRAME)
ps->multicast++;
if (status & RX_ERROR) {
ps->rx_errors++;
if (status & RX_MISSED_FRAME)
ps->rx_missed_errors++;
if (status & (RX_OVERLEN | RX_OVERLEN | RX_LEN_ERROR))
ps->rx_length_errors++;
if (status & RX_CRC_ERROR)
ps->rx_crc_errors++;
if (status & RX_COLL)
ps->collisions++;
else
ps->rx_bytes += status & RX_FRAME_LEN_MASK;
static int au1000_rx(struct net_device *dev)
struct au1000_private *aup = netdev_priv(dev);
struct sk_buff *skb;
volatile rx_dma_t *prxd;
u32 buff_stat, status;
db_dest_t *pDB;
u32 frmlen;
if (au1000_debug > 5)
printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);
prxd = aup->rx_dma_ring[aup->rx_head];
buff_stat = prxd->buff_stat;
while (buff_stat & RX_T_DONE) {
status = prxd->status;
pDB = aup->rx_db_inuse[aup->rx_head];
update_rx_stats(dev, status);
if (!(status & RX_ERROR)) {
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
/* good frame */
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",
dev->name);
dev->stats.rx_dropped++;
continue;
}
skb_reserve(skb, 2); /* 16 byte IP header align */
skb_copy_to_linear_data(skb,
(unsigned char *)pDB->vaddr, frmlen);
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)
printk("rx miss\n");
if (status & RX_WDOG_TIMER)
printk("rx wdog\n");
if (status & RX_RUNT)
printk("rx runt\n");
if (status & RX_OVERLEN)
printk("rx overlen\n");
if (status & RX_COLL)
printk("rx coll\n");
if (status & RX_MII_ERROR)
printk("rx mii error\n");
if (status & RX_CRC_ERROR)
printk("rx crc error\n");
if (status & RX_LEN_ERROR)
printk("rx len error\n");
if (status & RX_U_CNTRL_FRAME)
printk("rx u control frame\n");
if (status & RX_MISSED_FRAME)
printk("rx miss\n");
}
}
prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1);
au_sync();
/* next descriptor */
prxd = aup->rx_dma_ring[aup->rx_head];
buff_stat = prxd->buff_stat;
static void update_tx_stats(struct net_device *dev, u32 status)
struct au1000_private *aup = netdev_priv(dev);
if (status & TX_FRAME_ABORTED) {
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 */
ps->tx_errors++;
ps->tx_aborted_errors++;
}
else {
ps->tx_errors++;
ps->tx_aborted_errors++;
if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER))
ps->tx_carrier_errors++;
}
}
}
/*
* Called from the interrupt service routine to acknowledge
* the TX DONE bits. This is a must if the irq is setup as
* edge triggered.
*/
static void au1000_tx_ack(struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
volatile tx_dma_t *ptxd;
while (ptxd->buff_stat & TX_T_DONE) {
update_tx_stats(dev, ptxd->status);
ptxd->buff_stat &= ~TX_T_DONE;
ptxd->len = 0;
au_sync();
aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);
ptxd = aup->tx_dma_ring[aup->tx_tail];
if (aup->tx_full) {
aup->tx_full = 0;
netif_wake_queue(dev);
}
/*
* Au1000 interrupt service routine.
*/
static irqreturn_t au1000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
/* Handle RX interrupts first to minimize chance of overrun */
au1000_rx(dev);
au1000_tx_ack(dev);
return IRQ_RETVAL(1);
}
static int au1000_open(struct net_device *dev)
{
int retval;
struct au1000_private *aup = netdev_priv(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;
}
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);
netif_start_queue(dev);
if (au1000_debug > 4)
printk("%s: open: Initialization done.\n", dev->name);
return 0;
}
static int au1000_close(struct net_device *dev)
{
unsigned long flags;
struct au1000_private *const aup = netdev_priv(dev);
if (au1000_debug > 4)
printk("%s: close: dev=%p\n", dev->name, dev);
if (aup->phy_dev)
phy_stop(aup->phy_dev);
reset_mac_unlocked (dev);
/* stop the device */
netif_stop_queue(dev);
/* disable the interrupt */
free_irq(dev->irq, dev);
spin_unlock_irqrestore(&aup->lock, flags);
return 0;
}
/*
* Au1000 transmit routine.
*/
static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
{
struct au1000_private *aup = netdev_priv(dev);
struct net_device_stats *ps = &dev->stats;
volatile tx_dma_t *ptxd;
u32 buff_stat;
db_dest_t *pDB;
int i;
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];
buff_stat = ptxd->buff_stat;
if (buff_stat & TX_DMA_ENABLE) {
/* We've wrapped around and the transmitter is still busy */
netif_stop_queue(dev);
aup->tx_full = 1;
return 1;
}
else if (buff_stat & TX_T_DONE) {
update_tx_stats(dev, ptxd->status);
ptxd->len = 0;
}
if (aup->tx_full) {
aup->tx_full = 0;
netif_wake_queue(dev);
}
pDB = aup->tx_db_inuse[aup->tx_head];
skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);
((char *)pDB->vaddr)[i] = 0;
}
ptxd->len = ETH_ZLEN;
}
else
ps->tx_packets++;
ps->tx_bytes += ptxd->len;
ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
au_sync();
dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
dev->trans_start = jiffies;
return 0;
}
/*
* The Tx ring has been full longer than the watchdog timeout
* value. The transmitter must be hung?
*/
static void au1000_tx_timeout(struct net_device *dev)
{
printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev);