Commit 8d139952 authored by Jeff Garzik's avatar Jeff Garzik

Merge http://suncobalt.bkbits.net/net-drivers-2.5

into mandrakesoft.com:/home/jgarzik/repo/net-drivers-2.5
parents 05fd0be9 91f6fbd1
...@@ -1226,17 +1226,6 @@ CONFIG_NATSEMI ...@@ -1226,17 +1226,6 @@ CONFIG_NATSEMI
More specific information and updates are available from More specific information and updates are available from
<http://www.scyld.com/network/natsemi.html>. <http://www.scyld.com/network/natsemi.html>.
CONFIG_NATSEMI_CABLE_MAGIC
Some systems see lots of errors with NatSemi ethernet controllers
on certain cables. If you are seeing lots of errors, try turning
this option on. Some boards have incorrect values for supporting
resistors that can cause this change to break. If you turn this
option on and your network suddenly stops working, turn this
option off.
Say N unless you are certain you need this option.
Vendors should not enable this option by default.
CONFIG_SK_G16 CONFIG_SK_G16
If you have a network (Ethernet) card of this type, say Y and read If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from the Ethernet-HOWTO, available from
......
...@@ -165,9 +165,6 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then ...@@ -165,9 +165,6 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
dep_tristate ' Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI dep_tristate ' Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
if [ "$CONFIG_NATSEMI" = "y" -o "$CONFIG_NATSEMI" = "m" ]; then
bool ' NatSemi workaround for high errors' CONFIG_NATSEMI_CABLE_MAGIC
fi
dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
......
...@@ -100,20 +100,65 @@ ...@@ -100,20 +100,65 @@
* ETHTOOL_* further support (Tim Hockin) * ETHTOOL_* further support (Tim Hockin)
version 1.0.13: version 1.0.13:
* ETHTOOL_[GS]EEPROM support (Tim Hockin) * ETHTOOL_[G]EEPROM support (Tim Hockin)
version 1.0.13: version 1.0.13:
* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>) * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
version 1.0.14:
* Cleanup some messages and autoneg in ethtool (Tim Hockin)
version 1.0.15:
* Get rid of cable_magic flag
* use new (National provided) solution for cable magic issue
version 1.0.16:
* call netdev_rx() for RxErrors (Manfred Spraul)
* formatting and cleanups
* change options and full_duplex arrays to be zero
initialized
* enable only the WoL and PHY interrupts in wol mode
TODO: TODO:
* big endian support with CFG:BEM instead of cpu_to_le32 * big endian support with CFG:BEM instead of cpu_to_le32
* support for an external PHY * support for an external PHY
* flow control * flow control
*/ */
#if !defined(__OPTIMIZE__)
#warning You must compile this file with the correct options!
#warning See the last lines of the source file.
#error You must compile this driver with "-O".
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include <linux/rtnetlink.h>
#include <linux/mii.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#define DRV_NAME "natsemi" #define DRV_NAME "natsemi"
#define DRV_VERSION "1.07+LK1.0.13" #define DRV_VERSION "1.07+LK1.0.16"
#define DRV_RELDATE "Nov 12, 2001" #define DRV_RELDATE "Aug 28, 2002"
/* Updated to recommendations in pci-skeleton v2.03. */ /* Updated to recommendations in pci-skeleton v2.03. */
...@@ -132,7 +177,12 @@ c-help: http://www.scyld.com/network/natsemi.html ...@@ -132,7 +177,12 @@ c-help: http://www.scyld.com/network/natsemi.html
/* The user-configurable values. /* The user-configurable values.
These may be modified when a driver module is loaded.*/ These may be modified when a driver module is loaded.*/
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ #define NATSEMI_DEF_MSG (NETIF_MSG_DRV | \
NETIF_MSG_LINK | \
NETIF_MSG_WOL | \
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
static int debug = NATSEMI_DEF_MSG;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20; static int max_interrupt_work = 20;
...@@ -152,8 +202,8 @@ static int rx_copybreak; ...@@ -152,8 +202,8 @@ static int rx_copybreak;
The media type is usually passed in 'options[]'. The media type is usually passed in 'options[]'.
*/ */
#define MAX_UNITS 8 /* More are supported, limit only on options */ #define MAX_UNITS 8 /* More are supported, limit only on options */
static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int options[MAX_UNITS];
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS];
/* Operational parameters that are set at compile time. */ /* Operational parameters that are set at compile time. */
...@@ -164,7 +214,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; ...@@ -164,7 +214,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
There are no ill effects from too-large receive rings. */ There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 16 #define TX_RING_SIZE 16
#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ #define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */
#define RX_RING_SIZE 64 #define RX_RING_SIZE 32
/* Operational parameters that usually are not changed. */ /* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */ /* Time in jiffies before concluding the transmitter is hung. */
...@@ -183,37 +233,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; ...@@ -183,37 +233,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
#if !defined(__OPTIMIZE__)
#warning You must compile this file with the correct options!
#warning See the last lines of the source file.
#error You must compile this driver with "-O".
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include <linux/rtnetlink.h>
#include <linux/mii.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/* These identify the driver base version and may not be removed. */ /* These identify the driver base version and may not be removed. */
static char version[] __devinitdata = static char version[] __devinitdata =
KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker <becker@scyld.com>\n" KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker <becker@scyld.com>\n"
...@@ -232,7 +251,7 @@ MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); ...@@ -232,7 +251,7 @@ MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt"); MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt");
MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)"); MODULE_PARM_DESC(debug, "DP8381x default debug bitmask");
MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
...@@ -394,14 +413,12 @@ enum register_offsets { ...@@ -394,14 +413,12 @@ enum register_offsets {
SDCFG = 0xF8 SDCFG = 0xF8
}; };
/* the values for the 'magic' registers above (PGSEL=1) */ /* the values for the 'magic' registers above (PGSEL=1) */
#ifdef CONFIG_NATSEMI_CABLE_MAGIC #define PMDCSR_VAL 0x189c /* enable preferred adaptation circuitry */
#define PMDCSR_VAL 0x1898
#else
#define PMDCSR_VAL 0x189C
#endif
#define TSTDAT_VAL 0x0 #define TSTDAT_VAL 0x0
#define DSPCFG_VAL 0x5040 #define DSPCFG_VAL 0x5040
#define SDCFG_VAL 0x008c #define SDCFG_VAL 0x008c /* set voltage thresholds for Signal Detect */
#define DSPCFG_LOCK 0x20 /* coefficient lock bit in DSPCFG */
#define TSTDAT_FIXED 0xe8 /* magic number for bad coefficients */
/* misc PCI space registers */ /* misc PCI space registers */
enum pci_register_offsets { enum pci_register_offsets {
...@@ -421,6 +438,7 @@ enum ChipCmd_bits { ...@@ -421,6 +438,7 @@ enum ChipCmd_bits {
enum ChipConfig_bits { enum ChipConfig_bits {
CfgPhyDis = 0x200, CfgPhyDis = 0x200,
CfgPhyRst = 0x400, CfgPhyRst = 0x400,
CfgExtPhy = 0x1000,
CfgAnegEnable = 0x2000, CfgAnegEnable = 0x2000,
CfgAneg100 = 0x4000, CfgAneg100 = 0x4000,
CfgAnegFull = 0x8000, CfgAnegFull = 0x8000,
...@@ -630,10 +648,13 @@ struct netdev_private { ...@@ -630,10 +648,13 @@ struct netdev_private {
u32 SavedClkRun; u32 SavedClkRun;
/* silicon revision */ /* silicon revision */
u32 srr; u32 srr;
/* expected DSPCFG value */
u16 dspcfg;
/* MII transceiver section. */ /* MII transceiver section. */
u16 advertising; /* NWay media advertisement */ u16 advertising; /* NWay media advertisement */
unsigned int iosize; unsigned int iosize;
spinlock_t lock; spinlock_t lock;
u32 msg_enable;
}; };
static int eeprom_read(long ioaddr, int location); static int eeprom_read(long ioaddr, int location);
...@@ -643,6 +664,8 @@ static void natsemi_reset(struct net_device *dev); ...@@ -643,6 +664,8 @@ static void natsemi_reset(struct net_device *dev);
static void natsemi_reload_eeprom(struct net_device *dev); static void natsemi_reload_eeprom(struct net_device *dev);
static void natsemi_stop_rxtx(struct net_device *dev); static void natsemi_stop_rxtx(struct net_device *dev);
static int netdev_open(struct net_device *dev); static int netdev_open(struct net_device *dev);
static void do_cable_magic(struct net_device *dev);
static void undo_cable_magic(struct net_device *dev);
static void check_link(struct net_device *dev); static void check_link(struct net_device *dev);
static void netdev_timer(unsigned long data); static void netdev_timer(unsigned long data);
static void tx_timeout(struct net_device *dev); static void tx_timeout(struct net_device *dev);
...@@ -753,6 +776,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -753,6 +776,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
np->iosize = iosize; np->iosize = iosize;
spin_lock_init(&np->lock); spin_lock_init(&np->lock);
np->msg_enable = debug;
/* Reset the chip to erase previous misconfiguration. */ /* Reset the chip to erase previous misconfiguration. */
natsemi_reload_eeprom(dev); natsemi_reload_eeprom(dev);
...@@ -763,14 +787,15 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -763,14 +787,15 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
option = dev->mem_start; option = dev->mem_start;
/* The lower four bits are the media type. */ /* The lower four bits are the media type. */
if (option > 0) { if (option) {
if (option & 0x200) if (option & 0x200)
np->full_duplex = 1; np->full_duplex = 1;
if (option & 15) if (option & 15)
printk(KERN_INFO "%s: ignoring user supplied media type %d", printk(KERN_INFO
"%s: ignoring user supplied media type %d",
dev->name, option & 15); dev->name, option & 15);
} }
if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) if (find_cnt < MAX_UNITS && full_duplex[find_cnt])
np->full_duplex = 1; np->full_duplex = 1;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
...@@ -796,14 +821,17 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -796,14 +821,17 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
} }
netif_carrier_off(dev); netif_carrier_off(dev);
printk(KERN_INFO "%s: %s at 0x%lx, ", if (netif_msg_drv(np)) {
printk(KERN_INFO "%s: %s at %#08lx, ",
dev->name, natsemi_pci_info[chip_idx].name, ioaddr); dev->name, natsemi_pci_info[chip_idx].name, ioaddr);
for (i = 0; i < ETH_ALEN-1; i++) for (i = 0; i < ETH_ALEN-1; i++)
printk("%2.2x:", dev->dev_addr[i]); printk("%02x:", dev->dev_addr[i]);
printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq);
}
np->advertising = mdio_read(dev, 1, MII_ADVERTISE); np->advertising = mdio_read(dev, 1, MII_ADVERTISE);
if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000
&& netif_msg_probe(np)) {
u32 chip_config = readl(ioaddr + ChipConfig); u32 chip_config = readl(ioaddr + ChipConfig);
printk(KERN_INFO "%s: Transceiver default autonegotiation %s " printk(KERN_INFO "%s: Transceiver default autonegotiation %s "
"10%s %s duplex.\n", "10%s %s duplex.\n",
...@@ -812,12 +840,18 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -812,12 +840,18 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
chip_config & CfgAneg100 ? "0" : "", chip_config & CfgAneg100 ? "0" : "",
chip_config & CfgAnegFull ? "full" : "half"); chip_config & CfgAnegFull ? "full" : "half");
} }
printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", if (netif_msg_probe(np))
printk(KERN_INFO
"%s: Transceiver status %#04x advertising %#04x.\n",
dev->name, mdio_read(dev, 1, MII_BMSR), dev->name, mdio_read(dev, 1, MII_BMSR),
np->advertising); np->advertising);
/* save the silicon revision for later querying */ /* save the silicon revision for later querying */
np->srr = readl(ioaddr + SiliconRev); np->srr = readl(ioaddr + SiliconRev);
if (netif_msg_hw(np))
printk(KERN_INFO "%s: silicon revision %#04x.\n",
dev->name, np->srr);
return 0; return 0;
} }
...@@ -914,6 +948,7 @@ static void natsemi_reset(struct net_device *dev) ...@@ -914,6 +948,7 @@ static void natsemi_reset(struct net_device *dev)
u32 rfcr; u32 rfcr;
u16 pmatch[3]; u16 pmatch[3];
u16 sopass[3]; u16 sopass[3];
struct netdev_private *np = dev->priv;
/* /*
* Resetting the chip causes some registers to be lost. * Resetting the chip causes some registers to be lost.
...@@ -947,10 +982,10 @@ static void natsemi_reset(struct net_device *dev) ...@@ -947,10 +982,10 @@ static void natsemi_reset(struct net_device *dev)
break; break;
udelay(5); udelay(5);
} }
if (i==NATSEMI_HW_TIMEOUT && debug) { if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
printk(KERN_INFO "%s: reset did not complete in %d usec.\n", printk(KERN_INFO "%s: reset did not complete in %d usec.\n",
dev->name, i*5); dev->name, i*5);
} else if (debug > 2) { } else if (netif_msg_hw(np)) {
printk(KERN_DEBUG "%s: reset completed in %d usec.\n", printk(KERN_DEBUG "%s: reset completed in %d usec.\n",
dev->name, i*5); dev->name, i*5);
} }
...@@ -979,6 +1014,7 @@ static void natsemi_reset(struct net_device *dev) ...@@ -979,6 +1014,7 @@ static void natsemi_reset(struct net_device *dev)
static void natsemi_reload_eeprom(struct net_device *dev) static void natsemi_reload_eeprom(struct net_device *dev)
{ {
struct netdev_private *np = dev->priv;
int i; int i;
writel(EepromReload, dev->base_addr + PCIBusCfg); writel(EepromReload, dev->base_addr + PCIBusCfg);
...@@ -987,10 +1023,10 @@ static void natsemi_reload_eeprom(struct net_device *dev) ...@@ -987,10 +1023,10 @@ static void natsemi_reload_eeprom(struct net_device *dev)
break; break;
udelay(5); udelay(5);
} }
if (i==NATSEMI_HW_TIMEOUT && debug) { if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n", printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n",
dev->name, i*5); dev->name, i*5);
} else if (debug > 2) { } else if (netif_msg_hw(np)) {
printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n",
dev->name, i*5); dev->name, i*5);
} }
...@@ -999,6 +1035,7 @@ static void natsemi_reload_eeprom(struct net_device *dev) ...@@ -999,6 +1035,7 @@ static void natsemi_reload_eeprom(struct net_device *dev)
static void natsemi_stop_rxtx(struct net_device *dev) static void natsemi_stop_rxtx(struct net_device *dev)
{ {
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv;
int i; int i;
writel(RxOff | TxOff, ioaddr + ChipCmd); writel(RxOff | TxOff, ioaddr + ChipCmd);
...@@ -1007,10 +1044,10 @@ static void natsemi_stop_rxtx(struct net_device *dev) ...@@ -1007,10 +1044,10 @@ static void natsemi_stop_rxtx(struct net_device *dev)
break; break;
udelay(5); udelay(5);
} }
if (i==NATSEMI_HW_TIMEOUT && debug) { if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n",
dev->name, i*5); dev->name, i*5);
} else if (debug > 2) { } else if (netif_msg_hw(np)) {
printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n",
dev->name, i*5); dev->name, i*5);
} }
...@@ -1028,7 +1065,7 @@ static int netdev_open(struct net_device *dev) ...@@ -1028,7 +1065,7 @@ static int netdev_open(struct net_device *dev)
i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
if (i) return i; if (i) return i;
if (debug > 1) if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
dev->name, dev->irq); dev->name, dev->irq);
i = alloc_ring(dev); i = alloc_ring(dev);
...@@ -1043,8 +1080,8 @@ static int netdev_open(struct net_device *dev) ...@@ -1043,8 +1080,8 @@ static int netdev_open(struct net_device *dev)
netif_start_queue(dev); netif_start_queue(dev);
if (debug > 2) if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n",
dev->name, (int)readl(ioaddr + ChipCmd)); dev->name, (int)readl(ioaddr + ChipCmd));
/* Set the timer to check for link beat. */ /* Set the timer to check for link beat. */
...@@ -1057,6 +1094,54 @@ static int netdev_open(struct net_device *dev) ...@@ -1057,6 +1094,54 @@ static int netdev_open(struct net_device *dev)
return 0; return 0;
} }
static void do_cable_magic(struct net_device *dev)
{
/*
* 100 MBit links with short cables can trip an issue with the chip.
* The problem manifests as lots of CRC errors and/or flickering
* activity LED while idle. This process is based on instructions
* from engineers at National.
*/
if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) {
u16 data;
writew(1, dev->base_addr + PGSEL);
/*
* coefficient visibility should already be enabled via
* DSPCFG | 0x1000
*/
data = readw(dev->base_addr + TSTDAT) & 0xff;
/*
* the value must be negative, and within certain values
* (these values all come from National)
*/
if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
struct netdev_private *np = dev->priv;
/* the bug has been triggered - fix the coefficient */
writew(TSTDAT_FIXED, dev->base_addr + TSTDAT);
/* lock the value */
data = readw(dev->base_addr + DSPCFG);
np->dspcfg = data | DSPCFG_LOCK;
writew(np->dspcfg, dev->base_addr + DSPCFG);
}
writew(0, dev->base_addr + PGSEL);
}
}
static void undo_cable_magic(struct net_device *dev)
{
u16 data;
struct netdev_private *np = dev->priv;
writew(1, dev->base_addr + PGSEL);
/* make sure the lock bit is clear */
data = readw(dev->base_addr + DSPCFG);
np->dspcfg = data & ~DSPCFG_LOCK;
writew(np->dspcfg, dev->base_addr + DSPCFG);
writew(0, dev->base_addr + PGSEL);
}
static void check_link(struct net_device *dev) static void check_link(struct net_device *dev)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
...@@ -1064,29 +1149,31 @@ static void check_link(struct net_device *dev) ...@@ -1064,29 +1149,31 @@ static void check_link(struct net_device *dev)
int duplex; int duplex;
int chipcfg = readl(ioaddr + ChipConfig); int chipcfg = readl(ioaddr + ChipConfig);
if(!(chipcfg & CfgLink)) { if (!(chipcfg & CfgLink)) {
if (netif_carrier_ok(dev)) { if (netif_carrier_ok(dev)) {
if (debug) if (netif_msg_link(np))
printk(KERN_INFO "%s: no link. Disabling watchdog.\n", printk(KERN_NOTICE "%s: link down.\n",
dev->name); dev->name);
netif_carrier_off(dev); netif_carrier_off(dev);
undo_cable_magic(dev);
} }
return; return;
} }
if (!netif_carrier_ok(dev)) { if (!netif_carrier_ok(dev)) {
if (debug) if (netif_msg_link(np))
printk(KERN_INFO "%s: link is back. Enabling watchdog.\n", printk(KERN_NOTICE "%s: link up.\n", dev->name);
dev->name);
netif_carrier_on(dev); netif_carrier_on(dev);
do_cable_magic(dev);
} }
duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0); duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0);
/* if duplex is set then bit 28 must be set, too */ /* if duplex is set then bit 28 must be set, too */
if (duplex ^ !!(np->rx_config & RxAcceptTx)) { if (duplex ^ !!(np->rx_config & RxAcceptTx)) {
if (debug) if (netif_msg_link(np))
printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" printk(KERN_INFO
" capability.\n", dev->name, "%s: Setting %s-duplex based on negotiated "
"link capability.\n", dev->name,
duplex ? "full" : "half"); duplex ? "full" : "half");
if (duplex) { if (duplex) {
np->rx_config |= RxAcceptTx; np->rx_config |= RxAcceptTx;
...@@ -1106,17 +1193,12 @@ static void init_registers(struct net_device *dev) ...@@ -1106,17 +1193,12 @@ static void init_registers(struct net_device *dev)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
int i; int i;
/* save the silicon revision for later */
if (debug > 4)
printk(KERN_DEBUG "%s: found silicon revision %xh.\n",
dev->name, np->srr);
for (i=0;i<NATSEMI_HW_TIMEOUT;i++) { for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
if (readl(dev->base_addr + ChipConfig) & CfgAnegDone) if (readl(dev->base_addr + ChipConfig) & CfgAnegDone)
break; break;
udelay(10); udelay(10);
} }
if (i==NATSEMI_HW_TIMEOUT && debug) { if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) {
printk(KERN_INFO printk(KERN_INFO
"%s: autonegotiation did not complete in %d usec.\n", "%s: autonegotiation did not complete in %d usec.\n",
dev->name, i*10); dev->name, i*10);
...@@ -1135,6 +1217,7 @@ static void init_registers(struct net_device *dev) ...@@ -1135,6 +1217,7 @@ static void init_registers(struct net_device *dev)
writew(DSPCFG_VAL, ioaddr + DSPCFG); writew(DSPCFG_VAL, ioaddr + DSPCFG);
writew(SDCFG_VAL, ioaddr + SDCFG); writew(SDCFG_VAL, ioaddr + SDCFG);
writew(0, ioaddr + PGSEL); writew(0, ioaddr + PGSEL);
np->dspcfg = DSPCFG_VAL;
/* Enable PHY Specific event based interrupts. Link state change /* Enable PHY Specific event based interrupts. Link state change
and Auto-Negotiation Completion are among the affected. and Auto-Negotiation Completion are among the affected.
...@@ -1181,8 +1264,8 @@ static void init_registers(struct net_device *dev) ...@@ -1181,8 +1264,8 @@ static void init_registers(struct net_device *dev)
* nothing will be written to memory. */ * nothing will be written to memory. */
np->SavedClkRun = readl(ioaddr + ClkRun); np->SavedClkRun = readl(ioaddr + ClkRun);
writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun); writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun);
if (np->SavedClkRun & PMEStatus) { if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) {
printk(KERN_NOTICE "%s: Wake-up event %8.8x\n", printk(KERN_NOTICE "%s: Wake-up event %#08x\n",
dev->name, readl(ioaddr + WOLCmd)); dev->name, readl(ioaddr + WOLCmd));
} }
...@@ -1198,7 +1281,9 @@ static void init_registers(struct net_device *dev) ...@@ -1198,7 +1281,9 @@ static void init_registers(struct net_device *dev)
} }
/* /*
* The frequency on this has been increased because of a nasty little problem. * Purpose:
* check for sudden death of the NIC:
*
* It seems that a reference set for this chip went out with incorrect info, * It seems that a reference set for this chip went out with incorrect info,
* and there exist boards that aren't quite right. An unexpected voltage drop * and there exist boards that aren't quite right. An unexpected voltage drop
* can cause the PHY to get itself in a weird state (basically reset..). * can cause the PHY to get itself in a weird state (basically reset..).
...@@ -1212,7 +1297,7 @@ static void netdev_timer(unsigned long data) ...@@ -1212,7 +1297,7 @@ static void netdev_timer(unsigned long data)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
u16 dspcfg; u16 dspcfg;
if (debug > 3) { if (netif_msg_timer(np)) {
/* DO NOT read the IntrStatus register, /* DO NOT read the IntrStatus register,
* a read clears any pending interrupts. * a read clears any pending interrupts.
*/ */
...@@ -1220,15 +1305,18 @@ static void netdev_timer(unsigned long data) ...@@ -1220,15 +1305,18 @@ static void netdev_timer(unsigned long data)
dev->name); dev->name);
} }
spin_lock_irq(&np->lock);
/* check for a nasty random phy-reset - use dspcfg as a flag */ /* check for a nasty random phy-reset - use dspcfg as a flag */
writew(1, ioaddr+PGSEL); writew(1, ioaddr+PGSEL);
dspcfg = readw(ioaddr+DSPCFG); dspcfg = readw(ioaddr+DSPCFG);
writew(0, ioaddr+PGSEL); writew(0, ioaddr+PGSEL);
if (dspcfg != DSPCFG_VAL) { if (dspcfg != np->dspcfg) {
if (!netif_queue_stopped(dev)) { if (!netif_queue_stopped(dev)) {
printk(KERN_INFO spin_unlock_irq(&np->lock);
"%s: possible phy reset: re-initializing\n", if (netif_msg_hw(np))
dev->name); printk(KERN_NOTICE "%s: possible phy reset: "
"re-initializing\n", dev->name);
disable_irq(dev->irq); disable_irq(dev->irq);
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
init_registers(dev); init_registers(dev);
...@@ -1237,10 +1325,10 @@ static void netdev_timer(unsigned long data) ...@@ -1237,10 +1325,10 @@ static void netdev_timer(unsigned long data)
} else { } else {
/* hurry back */ /* hurry back */
next_tick = HZ; next_tick = HZ;
spin_unlock_irq(&np->lock);
} }
} else { } else {
/* init_registers() calls check_link() for the above case */ /* init_registers() calls check_link() for the above case */
spin_lock_irq(&np->lock);
check_link(dev); check_link(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
} }
...@@ -1251,18 +1339,18 @@ static void dump_ring(struct net_device *dev) ...@@ -1251,18 +1339,18 @@ static void dump_ring(struct net_device *dev)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
if (debug > 2) { if (netif_msg_pktdata(np)) {
int i; int i;
printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring); printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++) { for (i = 0; i < TX_RING_SIZE; i++) {
printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n",
i, np->tx_ring[i].next_desc, i, np->tx_ring[i].next_desc,
np->tx_ring[i].cmd_status, np->tx_ring[i].cmd_status,
np->tx_ring[i].addr); np->tx_ring[i].addr);
} }
printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++) { for (i = 0; i < RX_RING_SIZE; i++) {
printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n",
i, np->rx_ring[i].next_desc, i, np->rx_ring[i].next_desc,
np->rx_ring[i].cmd_status, np->rx_ring[i].cmd_status,
np->rx_ring[i].addr); np->rx_ring[i].addr);
...@@ -1278,7 +1366,9 @@ static void tx_timeout(struct net_device *dev) ...@@ -1278,7 +1366,9 @@ static void tx_timeout(struct net_device *dev)
disable_irq(dev->irq); disable_irq(dev->irq);
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
if (netif_device_present(dev)) { if (netif_device_present(dev)) {
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," if (netif_msg_tx_err(np))
printk(KERN_WARNING
"%s: Transmit timed out, status %#08x,"
" resetting...\n", " resetting...\n",
dev->name, readl(ioaddr + IntrStatus)); dev->name, readl(ioaddr + IntrStatus));
dump_ring(dev); dump_ring(dev);
...@@ -1438,7 +1528,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -1438,7 +1528,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies; dev->trans_start = jiffies;
if (debug > 4) { if (netif_msg_tx_queued(np)) {
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry); dev->name, np->cur_tx, entry);
} }
...@@ -1451,14 +1541,11 @@ static void netdev_tx_done(struct net_device *dev) ...@@ -1451,14 +1541,11 @@ static void netdev_tx_done(struct net_device *dev)
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE; int entry = np->dirty_tx % TX_RING_SIZE;
if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) { if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn))
if (debug > 4)
printk(KERN_DEBUG "%s: tx frame #%d is busy.\n",
dev->name, np->dirty_tx);
break; break;
} if (netif_msg_tx_done(np))
if (debug > 4) printk(KERN_DEBUG
printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n", "%s: tx frame #%d finished, status %#08x.\n",
dev->name, np->dirty_tx, dev->name, np->dirty_tx,
le32_to_cpu(np->tx_ring[entry].cmd_status)); le32_to_cpu(np->tx_ring[entry].cmd_status));
if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) { if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) {
...@@ -1495,30 +1582,31 @@ static void netdev_tx_done(struct net_device *dev) ...@@ -1495,30 +1582,31 @@ static void netdev_tx_done(struct net_device *dev)
static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
{ {
struct net_device *dev = dev_instance; struct net_device *dev = dev_instance;
struct netdev_private *np; struct netdev_private *np = dev->priv;
long ioaddr; long ioaddr = dev->base_addr;
int boguscnt = max_interrupt_work; int boguscnt = max_interrupt_work;
ioaddr = dev->base_addr;
np = dev->priv;
if (!netif_device_present(dev)) if (!netif_device_present(dev))
return; return;
do { do {
/* Reading automatically acknowledges all int sources. */ /* Reading automatically acknowledges all int sources. */
u32 intr_status = readl(ioaddr + IntrStatus); u32 intr_status = readl(ioaddr + IntrStatus);
if (debug > 4) if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n",
dev->name, intr_status); dev->name, intr_status);
if (intr_status == 0) if (intr_status == 0)
break; break;
if (intr_status & (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | IntrRxErr | IntrRxOverrun )) if (intr_status &
(IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
IntrRxErr | IntrRxOverrun)) {
netdev_rx(dev); netdev_rx(dev);
}
if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) { if (intr_status &
(IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
spin_lock(&np->lock); spin_lock(&np->lock);
netdev_tx_done(dev); netdev_tx_done(dev);
spin_unlock(&np->lock); spin_unlock(&np->lock);
...@@ -1529,16 +1617,16 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1529,16 +1617,16 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
netdev_error(dev, intr_status); netdev_error(dev, intr_status);
if (--boguscnt < 0) { if (--boguscnt < 0) {
printk(KERN_WARNING "%s: Too much work at interrupt, " if (netif_msg_intr(np))
"status=0x%4.4x.\n", printk(KERN_WARNING
dev->name, intr_status); "%s: Too much work at interrupt, "
"status=%#08x.\n", dev->name, intr_status);
break; break;
} }
} while (1); } while (1);
if (debug > 4) if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: exiting interrupt.\n", printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name);
dev->name);
} }
/* This routine is logically part of the interrupt handler, but separated /* This routine is logically part of the interrupt handler, but separated
...@@ -1552,22 +1640,24 @@ static void netdev_rx(struct net_device *dev) ...@@ -1552,22 +1640,24 @@ static void netdev_rx(struct net_device *dev)
/* If the driver owns the next entry it's a new packet. Send it up. */ /* If the driver owns the next entry it's a new packet. Send it up. */
while (desc_status < 0) { /* e.g. & DescOwn */ while (desc_status < 0) { /* e.g. & DescOwn */
if (debug > 4) if (netif_msg_rx_status(np))
printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", printk(KERN_DEBUG
" netdev_rx() entry %d status was %#08x.\n",
entry, desc_status); entry, desc_status);
if (--boguscnt < 0) if (--boguscnt < 0)
break; break;
if ((desc_status & (DescMore|DescPktOK|DescRxLong)) != DescPktOK) { if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
if (desc_status & DescMore) { if (desc_status & DescMore) {
printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " if (netif_msg_rx_err(np))
"multiple buffers, entry %#x status %x.\n", printk(KERN_WARNING
dev->name, np->cur_rx, desc_status); "%s: Oversized(?) Ethernet "
"frame spanned multiple "
"buffers, entry %#08x "
"status %#08x.\n", dev->name,
np->cur_rx, desc_status);
np->stats.rx_length_errors++; np->stats.rx_length_errors++;
} else { } else {
/* There was a error. */ /* There was an error. */
if (debug > 2)
printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
desc_status);
np->stats.rx_errors++; np->stats.rx_errors++;
if (desc_status & (DescRxAbort|DescRxOver)) if (desc_status & (DescRxAbort|DescRxOver))
np->stats.rx_over_errors++; np->stats.rx_over_errors++;
...@@ -1582,8 +1672,8 @@ static void netdev_rx(struct net_device *dev) ...@@ -1582,8 +1672,8 @@ static void netdev_rx(struct net_device *dev)
struct sk_buff *skb; struct sk_buff *skb;
/* Omit CRC size. */ /* Omit CRC size. */
int pkt_len = (desc_status & DescSizeMask) - 4; int pkt_len = (desc_status & DescSizeMask) - 4;
/* Check if the packet is long enough to accept without copying /* Check if the packet is long enough to accept
to a minimally-sized skbuff. */ * without copying to a minimally-sized skbuff. */
if (pkt_len < rx_copybreak if (pkt_len < rx_copybreak
&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb->dev = dev; skb->dev = dev;
...@@ -1646,11 +1736,16 @@ static void netdev_error(struct net_device *dev, int intr_status) ...@@ -1646,11 +1736,16 @@ static void netdev_error(struct net_device *dev, int intr_status)
spin_lock(&np->lock); spin_lock(&np->lock);
if (intr_status & LinkChange) { if (intr_status & LinkChange) {
printk(KERN_NOTICE u16 adv = mdio_read(dev, 1, MII_ADVERTISE);
"%s: Link changed: Autonegotiation advertising" u16 lpa = mdio_read(dev, 1, MII_LPA);
" %4.4x partner %4.4x.\n", dev->name, if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE
(int)mdio_read(dev, 1, MII_ADVERTISE), && netif_msg_link(np)) {
(int)mdio_read(dev, 1, MII_LPA)); printk(KERN_INFO
"%s: Autonegotiation advertising"
" %#04x partner %#04x.\n", dev->name,
adv, lpa);
}
/* read MII int status to clear the flag */ /* read MII int status to clear the flag */
readw(ioaddr + MIntrStatus); readw(ioaddr + MIntrStatus);
check_link(dev); check_link(dev);
...@@ -1661,18 +1756,19 @@ static void netdev_error(struct net_device *dev, int intr_status) ...@@ -1661,18 +1756,19 @@ static void netdev_error(struct net_device *dev, int intr_status)
if (intr_status & IntrTxUnderrun) { if (intr_status & IntrTxUnderrun) {
if ((np->tx_config & TxDrthMask) < 62) if ((np->tx_config & TxDrthMask) < 62)
np->tx_config += 2; np->tx_config += 2;
if (debug > 2) if (netif_msg_tx_err(np))
printk(KERN_NOTICE "%s: increasing Tx threshold, new tx cfg %8.8xh.\n", printk(KERN_NOTICE
"%s: increased Tx threshold, txcfg %#08x.\n",
dev->name, np->tx_config); dev->name, np->tx_config);
writel(np->tx_config, ioaddr + TxConfig); writel(np->tx_config, ioaddr + TxConfig);
} }
if (intr_status & WOLPkt) { if (intr_status & WOLPkt && netif_msg_wol(np)) {
int wol_status = readl(ioaddr + WOLCmd); int wol_status = readl(ioaddr + WOLCmd);
printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", printk(KERN_NOTICE "%s: Link wake-up event %#08x\n",
dev->name, wol_status); dev->name, wol_status);
} }
if (intr_status & RxStatusFIFOOver) { if (intr_status & RxStatusFIFOOver) {
if (debug >= 2) { if (netif_msg_rx_err(np) && netif_msg_intr(np)) {
printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", printk(KERN_NOTICE "%s: Rx status FIFO overrun\n",
dev->name); dev->name);
} }
...@@ -1680,10 +1776,8 @@ static void netdev_error(struct net_device *dev, int intr_status) ...@@ -1680,10 +1776,8 @@ static void netdev_error(struct net_device *dev, int intr_status)
} }
/* Hmmmmm, it's not clear how to recover from PCI faults. */ /* Hmmmmm, it's not clear how to recover from PCI faults. */
if (intr_status & IntrPCIErr) { if (intr_status & IntrPCIErr) {
if (debug) { printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
printk(KERN_NOTICE "%s: PCI error %08x\n", dev->name,
intr_status & IntrPCIErr); intr_status & IntrPCIErr);
}
np->stats.tx_fifo_errors++; np->stats.tx_fifo_errors++;
np->stats.rx_fifo_errors++; np->stats.rx_fifo_errors++;
} }
...@@ -1761,7 +1855,8 @@ static void __set_rx_mode(struct net_device *dev) ...@@ -1761,7 +1855,8 @@ static void __set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
/* Unconditionally log net taps. */ /* Unconditionally log net taps. */
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
dev->name);
rx_mode = RxFilterEnable | AcceptBroadcast rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
} else if ((dev->mc_count > multicast_filter_limit) } else if ((dev->mc_count > multicast_filter_limit)
...@@ -1896,7 +1991,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1896,7 +1991,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
/* get message-level */ /* get message-level */
case ETHTOOL_GMSGLVL: { case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = {ETHTOOL_GMSGLVL}; struct ethtool_value edata = {ETHTOOL_GMSGLVL};
edata.data = debug; edata.data = np->msg_enable;
if (copy_to_user(useraddr, &edata, sizeof(edata))) if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1906,7 +2001,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1906,7 +2001,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
struct ethtool_value edata; struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata))) if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT; return -EFAULT;
debug = edata.data; np->msg_enable = edata.data;
return 0; return 0;
} }
/* restart autonegotiation */ /* restart autonegotiation */
...@@ -1941,6 +2036,9 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1941,6 +2036,9 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
return -EFAULT; return -EFAULT;
if (eeprom.offset > eeprom.offset+eeprom.len)
return -EINVAL;
if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) { if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) {
eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset; eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset;
} }
...@@ -2096,18 +2194,22 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -2096,18 +2194,22 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->supported = ecmd->supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_TP); SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
/* only supports twisted-pair */ /* only supports twisted-pair or MII */
tmp = readl(dev->base_addr + ChipConfig);
if (tmp & CfgExtPhy)
ecmd->port = PORT_MII;
else
ecmd->port = PORT_TP; ecmd->port = PORT_TP;
/* only supports internal transceiver */ /* only supports internal transceiver */
ecmd->transceiver = XCVR_INTERNAL; ecmd->transceiver = XCVR_INTERNAL;
/* this isn't fully supported at higher layers */ /* not sure what this is for */
ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask;
ecmd->advertising = ADVERTISED_TP; ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
tmp = mdio_read(dev, 1, MII_ADVERTISE); tmp = mdio_read(dev, 1, MII_ADVERTISE);
if (tmp & ADVERTISE_10HALF) if (tmp & ADVERTISE_10HALF)
ecmd->advertising |= ADVERTISED_10baseT_Half; ecmd->advertising |= ADVERTISED_10baseT_Half;
...@@ -2118,14 +2220,15 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -2118,14 +2220,15 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
if (tmp & ADVERTISE_100FULL) if (tmp & ADVERTISE_100FULL)
ecmd->advertising |= ADVERTISED_100baseT_Full; ecmd->advertising |= ADVERTISED_100baseT_Full;
tmp = readl(dev->base_addr + ChipConfig); tmp = mdio_read(dev, 1, MII_BMCR);
if (tmp & CfgAnegEnable) { if (tmp & BMCR_ANENABLE) {
ecmd->advertising |= ADVERTISED_Autoneg; ecmd->advertising |= ADVERTISED_Autoneg;
ecmd->autoneg = AUTONEG_ENABLE; ecmd->autoneg = AUTONEG_ENABLE;
} else { } else {
ecmd->autoneg = AUTONEG_DISABLE; ecmd->autoneg = AUTONEG_DISABLE;
} }
tmp = readl(dev->base_addr + ChipConfig);
if (tmp & CfgSpeed100) { if (tmp & CfgSpeed100) {
ecmd->speed = SPEED_100; ecmd->speed = SPEED_100;
} else { } else {
...@@ -2152,7 +2255,7 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -2152,7 +2255,7 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
return -EINVAL; return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL; return -EINVAL;
if (ecmd->port != PORT_TP) if (ecmd->port != PORT_TP && ecmd->port != PORT_MII)
return -EINVAL; return -EINVAL;
if (ecmd->transceiver != XCVR_INTERNAL) if (ecmd->transceiver != XCVR_INTERNAL)
return -EINVAL; return -EINVAL;
...@@ -2162,39 +2265,22 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ...@@ -2162,39 +2265,22 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
/* WHEW! now lets bang some bits */ /* WHEW! now lets bang some bits */
if (ecmd->autoneg == AUTONEG_ENABLE) {
/* advertise only what has been requested */
tmp = readl(dev->base_addr + ChipConfig);
tmp &= ~(CfgAneg100 | CfgAnegFull);
tmp |= CfgAnegEnable;
if (ecmd->advertising & ADVERTISED_100baseT_Half
|| ecmd->advertising & ADVERTISED_100baseT_Full) {
tmp |= CfgAneg100;
}
if (ecmd->advertising & ADVERTISED_10baseT_Full
|| ecmd->advertising & ADVERTISED_100baseT_Full) {
tmp |= CfgAnegFull;
}
writel(tmp, dev->base_addr + ChipConfig);
/* turn on autonegotiation, and force a renegotiate */
tmp = mdio_read(dev, 1, MII_BMCR); tmp = mdio_read(dev, 1, MII_BMCR);
tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); if (ecmd->autoneg == AUTONEG_ENABLE) {
mdio_write(dev, 1, MII_BMCR, tmp); /* turn on autonegotiation */
tmp |= BMCR_ANENABLE;
np->advertising = mdio_read(dev, 1, MII_ADVERTISE); np->advertising = mdio_read(dev, 1, MII_ADVERTISE);
} else { } else {
/* turn off auto negotiation, set speed and duplexity */ /* turn off auto negotiation, set speed and duplexity */
tmp = mdio_read(dev, 1, MII_BMCR);
tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
if (ecmd->speed == SPEED_100) { if (ecmd->speed == SPEED_100)
tmp |= BMCR_SPEED100; tmp |= BMCR_SPEED100;
} if (ecmd->duplex == DUPLEX_FULL)
if (ecmd->duplex == DUPLEX_FULL) {
tmp |= BMCR_FULLDPLX; tmp |= BMCR_FULLDPLX;
} else { else
np->full_duplex = 0; np->full_duplex = 0;
} }
mdio_write(dev, 1, MII_BMCR, tmp); mdio_write(dev, 1, MII_BMCR, tmp);
}
return 0; return 0;
} }
...@@ -2229,7 +2315,7 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf) ...@@ -2229,7 +2315,7 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf)
/* the interrupt status is clear-on-read - see if we missed any */ /* the interrupt status is clear-on-read - see if we missed any */
if (rbuf[4] & rbuf[5]) { if (rbuf[4] & rbuf[5]) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: shoot, we dropped an interrupt (0x%x)\n", "%s: shoot, we dropped an interrupt (%#08x)\n",
dev->name, rbuf[4] & rbuf[5]); dev->name, rbuf[4] & rbuf[5]);
} }
...@@ -2296,7 +2382,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr) ...@@ -2296,7 +2382,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
if (debug > 1) if (netif_msg_wol(np))
printk(KERN_INFO "%s: remaining active for wake-on-lan\n", printk(KERN_INFO "%s: remaining active for wake-on-lan\n",
dev->name); dev->name);
...@@ -2319,7 +2405,8 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr) ...@@ -2319,7 +2405,8 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr)
/* enable the WOL interrupt. /* enable the WOL interrupt.
* Could be used to send a netlink message. * Could be used to send a netlink message.
*/ */
writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); writel(WOLPkt | LinkChange, ioaddr + IntrMask);
writel(1, ioaddr + IntrEnable);
} }
} }
...@@ -2331,12 +2418,15 @@ static int netdev_close(struct net_device *dev) ...@@ -2331,12 +2418,15 @@ static int netdev_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
netif_carrier_off(dev); netif_carrier_off(dev);
if (debug > 1) { if (netif_msg_ifdown(np))
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", printk(KERN_DEBUG
"%s: Shutting down ethercard, status was %#04x.\n",
dev->name, (int)readl(ioaddr + ChipCmd)); dev->name, (int)readl(ioaddr + ChipCmd));
printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", if (netif_msg_pktdata(np))
dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); printk(KERN_DEBUG
} "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
dev->name, np->cur_tx, np->dirty_tx,
np->cur_rx, np->dirty_rx);
del_timer_sync(&np->timer); del_timer_sync(&np->timer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment