Commit a8807fa8 authored by Don Fry's avatar Don Fry Committed by Jeff Garzik

[PATCH] pcnet32: fix bogus carrier errors with 79c973

The 79C973 version of the pcnet32 chipset would report all transmit
operations as being sent with a carrier error.  The root cause was
writing reserved bits in bcr33.  It caused the 973 to report xmit
as errors, and caused 975 and 976 to hard hang when reading bcr34.

My thanks to Bruce Penrod for his help in finding the cause of this
bug.
parent 3385606e
......@@ -22,8 +22,8 @@
*************************************************************************/
#define DRV_NAME "pcnet32"
#define DRV_VERSION "1.30a"
#define DRV_RELDATE "05.22.2004"
#define DRV_VERSION "1.30b"
#define DRV_RELDATE "05.24.2004"
#define PFX DRV_NAME ": "
static const char *version =
......@@ -132,7 +132,7 @@ static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = {
};
#define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN)
#define PCNET32_NUM_REGS 146
#define PCNET32_NUM_REGS 168
#define MAX_UNITS 8 /* More are supported, limit only on options */
static int options[MAX_UNITS];
......@@ -242,6 +242,8 @@ static int full_duplex[MAX_UNITS];
* v1.30 18 May 2004 Don Fry removed timer and Last Transmit Interrupt
* (ltint) as they added complexity and didn't give good throughput.
* v1.30a 22 May 2004 Don Fry limit frames received during interrupt.
* v1.30b 24 May 2004 Don Fry fix bogus tx carrier errors with 79c973,
* assisted by Bruce Penrod <bmpenrod@endruntechnologies.com>.
*/
......@@ -889,15 +891,25 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
for (i=0; i<16; i += 2)
*buff++ = inw(ioaddr + i);
for (i = 0; i <= 89; i++) {
/* read control and status registers */
for (i=0; i<90; i++) {
*buff++ = a->read_csr(ioaddr, i);
}
*buff++ = a->read_csr(ioaddr, 112);
*buff++ = a->read_csr(ioaddr, 114);
for (i = 0; i <= 35; i++) {
*buff++ = (i == 34) ? 0xdead : a->read_bcr(ioaddr, i);
/* read bus configuration registers */
for (i=0; i<36; i++) {
*buff++ = a->read_bcr(ioaddr, i);
}
/* read mii phy registers */
if (lp->mii) {
for (i=0; i<32; i++) {
lp->a.write_bcr(ioaddr, 33, ((lp->mii_if.phy_id) << 5) | i);
*buff++ = lp->a.read_bcr(ioaddr, 34);
}
}
if (!(csr0 & 0x0004)) { /* If not stopped */
......@@ -1751,6 +1763,9 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* There was an major error, log it. */
int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
lp->stats.tx_errors++;
if (netif_msg_tx_err(lp))
printk(KERN_ERR "%s: Tx error status=%04x err_status=%08x\n",
dev->name, status, err_status);
if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
if (err_status & 0x10000000) lp->stats.tx_window_errors++;
......@@ -2116,39 +2131,33 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
}
/* This routine assumes that the lp->lock is held */
static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
{
struct pcnet32_private *lp = dev->priv;
unsigned long ioaddr = dev->base_addr;
u16 val_out;
int phyaddr;
if (!lp->mii)
return 0;
phyaddr = lp->a.read_bcr(ioaddr, 33);
lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
val_out = lp->a.read_bcr(ioaddr, 34);
lp->a.write_bcr(ioaddr, 33, phyaddr);
return val_out;
}
/* This routine assumes that the lp->lock is held */
static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
{
struct pcnet32_private *lp = dev->priv;
unsigned long ioaddr = dev->base_addr;
int phyaddr;
if (!lp->mii)
return;
phyaddr = lp->a.read_bcr(ioaddr, 33);
lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
lp->a.write_bcr(ioaddr, 34, val);
lp->a.write_bcr(ioaddr, 33, phyaddr);
}
static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
......
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