From: Don Fry <brazilnut@us.ibm.com>
To: tsbogend@alpha.franken.de, jgarzik@pobox.com, netdev@oss.sgi.com
Subject: [PATCH 2.6.5] pcnet32 fix hang/crash with loopback test
Date: Wed, 7 Apr 2004 15:50:25 -0700 (PDT) [thread overview]
Message-ID: <200404072250.i37MoPC19556@DYN318364BLD.beaverton.ibm.com> (raw)
If the pcnet32 interface is not up, running the loopback test may hang or
crash the system. This patch provided by Jim Lewis fixes that problem.
Tested on ia32 and ppc systems.
--- linux-2.6.5/drivers/net/led.pcnet32.c Tue Apr 6 14:52:41 2004
+++ linux-2.6.5/drivers/net/pcnet32.c Wed Apr 7 14:45:15 2004
@@ -360,6 +360,7 @@
static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
static int pcnet32_close(struct net_device *);
static struct net_device_stats *pcnet32_get_stats(struct net_device *);
+static void pcnet32_load_multicast(struct net_device *dev);
static void pcnet32_set_multicast_list(struct net_device *);
static int pcnet32_ioctl(struct net_device *, struct ifreq *, int);
static void pcnet32_watchdog(struct net_device *);
@@ -627,34 +628,40 @@
struct pcnet32_access *a = &lp->a; /* access to registers */
ulong ioaddr = dev->base_addr; /* card base I/O address */
struct sk_buff *skb; /* sk buff */
- int x, y, i; /* counters */
+ int x, i; /* counters */
int numbuffs = 4; /* number of TX/RX buffers and descs */
u16 status = 0x8300; /* TX ring status */
+ u16 teststatus; /* test of ring status */
int rc; /* return code */
int size; /* size of packets */
unsigned char *packet; /* source packet data */
static int data_len = 60; /* length of source packets */
unsigned long flags;
+ unsigned long ticks;
*data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
+ if (netif_running(dev))
+ pcnet32_close(dev);
+
spin_lock_irqsave(&lp->lock, flags);
- lp->a.write_csr(ioaddr, 0, 0x7904);
- del_timer_sync(&lp->watchdog_timer);
+ /* Reset the PCNET32 */
+ lp->a.reset (ioaddr);
- netif_stop_queue(dev);
+ /* switch pcnet32 to 32bit mode */
+ lp->a.write_bcr (ioaddr, 20, 2);
+
+ lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ lp->init_block.filter[0] = 0;
+ lp->init_block.filter[1] = 0;
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
- x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
- x = x | 0x00000002;
- a->write_bcr(ioaddr, 32, x);
-
/* Initialize Transmit buffers. */
size = data_len + 15;
for (x=0; x<numbuffs; x++) {
@@ -668,19 +675,21 @@
skb_put(skb, size); /* create space for data */
lp->tx_skbuff[x] = skb;
lp->tx_ring[x].length = le16_to_cpu(-skb->len);
- lp->tx_ring[x].misc = 0x00000000;
+ lp->tx_ring[x].misc = 0;
- /* put DA and SA into the skb */
- for (i=0; i<12; i++)
- *packet++ = 0xff;
+ /* put DA and SA into the skb */
+ for (i=0; i<6; i++)
+ *packet++ = dev->dev_addr[i];
+ for (i=0; i<6; i++)
+ *packet++ = dev->dev_addr[i];
/* type */
*packet++ = 0x08;
*packet++ = 0x06;
/* packet number */
*packet++ = x;
/* fill packet with data */
- for (y=0; y<data_len; y++)
- *packet++ = y;
+ for (i=0; i<data_len; i++)
+ *packet++ = i;
lp->tx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data,
skb->len, PCI_DMA_TODEVICE);
@@ -690,20 +699,41 @@
}
}
- lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
- spin_unlock_irqrestore(&lp->lock, flags);
+ x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
+ x = x | 0x0002;
+ a->write_bcr(ioaddr, 32, x);
- mdelay(50); /* wait a bit */
+ lp->a.write_csr (ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
- spin_lock_irqsave(&lp->lock, flags);
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ teststatus = le16_to_cpu(0x8000);
+ lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
+ /* Check status of descriptors */
+ for (x=0; x<numbuffs; x++) {
+ ticks = 0;
+ rmb();
+ while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
+ mdelay(1);
+ spin_lock_irqsave(&lp->lock, flags);
+ rmb();
+ ticks++;
+ }
+ if (ticks == 200) {
+ if (netif_msg_hw(lp))
+ printk("%s: Desc %d failed to reset!\n",dev->name,x);
+ break;
+ }
+ }
+
+ lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
for (x=0; x<numbuffs; x++) {
printk(KERN_DEBUG "%s: Packet %d:\n", dev->name, x);
- skb=lp->rx_skbuff[x];
+ skb = lp->rx_skbuff[x];
for (i=0; i<size; i++) {
printk("%02x ", *(skb->data+i));
}
@@ -736,19 +766,17 @@
a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
- x = x & ~0x00000002;
+ x = x & ~0x0002;
a->write_bcr(ioaddr, 32, x);
- pcnet32_restart(dev, 0x0042); /* resume normal operation */
-
- netif_wake_queue(dev);
-
- mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
-
- /* Clear interrupts, and set interrupt enable. */
- lp->a.write_csr(ioaddr, 0, 0x7940);
spin_unlock_irqrestore(&lp->lock, flags);
+ if (netif_running(dev)) {
+ pcnet32_open(dev);
+ } else {
+ lp->a.write_bcr (ioaddr, 20, 4); /* return to 16bit mode */
+ }
+
return(rc);
} /* end pcnet32_loopback_test */
@@ -1056,7 +1084,7 @@
if (pcnet32_debug & NETIF_MSG_PROBE) {
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] );
+ printk(" %2.2x", dev->dev_addr[i]);
/* Version 0x2623 and 0x2624 */
if (((chip_version + 1) & 0xfffe) == 0x2624) {
@@ -1244,6 +1272,7 @@
u16 val;
int i;
int rc;
+ unsigned long flags;
if (dev->irq == 0 ||
request_irq(dev->irq, &pcnet32_interrupt,
@@ -1251,6 +1280,7 @@
return -EAGAIN;
}
+ spin_lock_irqsave(&lp->lock, flags);
/* Check for a valid station address */
if (!is_valid_ether_addr(dev->dev_addr)) {
rc = -EINVAL;
@@ -1331,8 +1361,8 @@
}
lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->init_block.filter[0] = 0x00000000;
- lp->init_block.filter[1] = 0x00000000;
+ pcnet32_load_multicast(dev);
+
if (pcnet32_init_ring(dev)) {
rc = -ENOMEM;
goto err_free_ring;
@@ -1371,6 +1401,7 @@
offsetof(struct pcnet32_private, init_block)),
lp->a.read_csr(ioaddr, 0));
+ spin_unlock_irqrestore(&lp->lock, flags);
return 0; /* Always succeed */
@@ -1393,6 +1424,7 @@
lp->a.write_bcr (ioaddr, 20, 4);
err_free_irq:
+ spin_unlock_irqrestore(&lp->lock, flags);
free_irq(dev->irq, dev);
return rc;
}
@@ -1885,11 +1917,14 @@
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
int i;
+ unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
netif_stop_queue(dev);
+ spin_lock_irqsave(&lp->lock, flags);
+
lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
if (netif_msg_ifdown(lp))
@@ -1905,6 +1940,8 @@
*/
lp->a.write_bcr (ioaddr, 20, 4);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
free_irq(dev->irq, dev);
/* free all allocated skbuffs */
--
Don Fry
brazilnut@us.ibm.com
next reply other threads:[~2004-04-07 22:50 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-04-07 22:50 Don Fry [this message]
2004-04-13 18:06 ` [PATCH 2.6.5] pcnet32 fix hang/crash with loopback test Jeff Garzik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200404072250.i37MoPC19556@DYN318364BLD.beaverton.ibm.com \
--to=brazilnut@us.ibm.com \
--cc=jgarzik@pobox.com \
--cc=netdev@oss.sgi.com \
--cc=tsbogend@alpha.franken.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).