From: Dennis Bjorklund <db@zigo.dhs.org>
To: David Schmitt <david@heureka.co.at>
Cc: <linux-kernel@vger.kernel.org>
Subject: Re: ISSUE: DFE530-TX REV-A3-1 times out on transmit
Date: Tue, 28 Aug 2001 09:26:41 +0200 (CEST) [thread overview]
Message-ID: <Pine.LNX.4.33.0108280921160.12686-200000@cosmo.zigo.dhs.org> (raw)
In-Reply-To: <20010827102740.A9557@www.heureka.co.at>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 522 bytes --]
On Mon, 27 Aug 2001, David Schmitt wrote:
> As mentioned above, it seems like the 2.2.19 version does the Right
> Thing (but doesn't recover autmatically).
I backported the recover stuff from 2.4.x to 2.2.20-pre9 and it works nice
for me. I've been running it for a couple of weeks without problem and
where it before locked up it now resets (clear improvement for me).
I sent it to Alan in hope that it could make it to 2.2.20 but I got no
reply. I don't know if I should continue send it to him or what.
--
/Dennis
[-- Attachment #2: Type: TEXT/PLAIN, Size: 12736 bytes --]
--- linux/drivers/net/via-rhine.c Sat Aug 18 14:10:07 2001
+++ linux-2.2.19/drivers/net/via-rhine.c Sat Aug 18 14:23:38 2001
@@ -25,11 +25,15 @@
LK1.0.0:
- Urban Widmark: merges from Beckers 1.08b version and 2.4.0 (VT6102)
+
+ LK1.0.1
+ - Dennis Björklund: backport tx_timeout from 2.4.x to reset on timeout
+ instead of stop working...
*/
/* These identify the driver base version and may not be removed. */
static const char version1[] =
-"via-rhine.c:v1.08b-LK1.0.0 12/14/2000 Written by Donald Becker\n";
+"via-rhine.c:v1.08b-LK1.0.1 12/14/2000 Written by Donald Becker\n";
static const char version2[] =
" http://www.scyld.com/network/via-rhine.html\n";
@@ -95,9 +99,11 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
+#include <asm/irq.h>
/* Condensed bus+endian portability operations. */
#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
@@ -256,6 +262,13 @@
struct device *dev, long ioaddr, int irq,
int chp_idx, int fnd_cnt);
+enum via_rhine_chips {
+ VT86C100A = 0,
+ VT6102,
+ VT3043,
+};
+
+/* directly indexed by enum via_rhine_chips, above */
static struct pci_id_info pci_tbl[] __initdata = {
{ "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
RHINE_IOTYPE, 128, via_probe1},
@@ -379,7 +392,6 @@
static void check_duplex(struct device *dev);
static void netdev_timer(unsigned long data);
static void tx_timeout(struct device *dev);
-static void init_ring(struct device *dev);
static int start_tx(struct sk_buff *skb, struct device *dev);
static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_rx(struct device *dev);
@@ -395,6 +407,31 @@
/* A list of our installed devices, for removing the driver module. */
static struct device *root_net_dev = NULL;
+static void wait_for_reset(struct device *dev, char *name)
+{
+ struct netdev_private *np = dev->priv;
+ long ioaddr = dev->base_addr;
+ int chip_id = np->chip_id;
+ int i;
+
+ /* 3043 may need long delay after reset (dlink) */
+ if (chip_id == VT3043 || chip_id == VT86C100A)
+ udelay(100);
+
+ i = 0;
+ do {
+ udelay(5);
+ i++;
+ if(i > 2000) {
+ printk(KERN_ERR "%s: reset did not complete in 10 ms.\n", name);
+ break;
+ }
+ } while(readw(ioaddr + ChipCmd) & CmdReset);
+ if (debug > 1)
+ printk(KERN_INFO "%s: reset finished after %d microseconds.\n",
+ name, 5*i);
+}
+
/* Ideally we would detect all network cards in slot order. That would
be best done a central PCI probe dispatch, which wouldn't work
well when dynamically adding drivers. So instead we detect just the
@@ -594,6 +631,141 @@
return dev;
}
+static void alloc_rbufs(struct device *dev)
+{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
+ int i;
+
+ np->cur_rx = 0;
+ np->dirty_rx = 0;
+
+ np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+ np->rx_head_desc = &np->rx_ring[0];
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ np->rx_ring[i].rx_status = 0;
+ np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+ np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
+ np->rx_skbuff[i] = 0;
+ }
+ /* Mark the last entry as wrapping the ring. */
+ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
+
+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+ np->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
+ np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
+ }
+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+}
+
+static void free_rbufs(struct device* dev)
+{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
+ int i;
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ np->rx_ring[i].rx_status = 0;
+ np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+ if (np->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+ np->rx_skbuff[i]->free = 1;
+#endif
+ dev_kfree_skb(np->rx_skbuff[i]);
+ }
+ np->rx_skbuff[i] = 0;
+ }
+}
+
+static void alloc_tbufs(struct device* dev)
+{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
+ int i;
+
+ np->tx_full = 0;
+ np->cur_tx = 0;
+ np->dirty_tx = 0;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ np->tx_skbuff[i] = 0;
+ np->tx_ring[i].tx_status = 0;
+ np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+ np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
+ np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
+ }
+ np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
+}
+
+static void free_tbufs(struct device *dev)
+{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
+ int i;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (np->tx_skbuff[i])
+ dev_kfree_skb(np->tx_skbuff[i]);
+ np->tx_skbuff[i] = 0;
+ if (np->tx_buf[i]) {
+ kfree(np->tx_buf[i]);
+ np->tx_buf[i] = 0;
+ }
+ }
+}
+
+static void init_registers(struct device *dev)
+{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int i;
+
+ for (i = 0; i < 6; i++)
+ writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
+
+ /* Initialize other registers. */
+ writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
+ /* Configure the FIFO thresholds. */
+ writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */
+ np->tx_thresh = 0x20;
+ np->rx_thresh = 0x60; /* Written in set_rx_mode(). */
+
+ if (dev->if_port == 0)
+ dev->if_port = np->default_port;
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+
+ writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
+ writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
+
+ set_rx_mode(dev);
+
+ dev->start = 1;
+
+ /* Enable interrupts by setting the interrupt mask. */
+ writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
+ IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+ IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
+ ioaddr + IntrEnable);
+
+ np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
+ if (np->duplex_lock)
+ np->chip_cmd |= CmdFDuplex;
+ writew(np->chip_cmd, ioaddr + ChipCmd);
+
+ check_duplex(dev);
+ /* The LED outputs of various MII xcvrs should be configured. */
+ /* For NS or Mison phys, turn on bit 1 in register 0x17 */
+ /* For ESI phys, turn on bit 7 in register 0x17. */
+ mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
+ (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
+}
+
\f
/* Read and write over the MII Management Data I/O (MDIO) interface. */
@@ -650,7 +822,6 @@
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
long ioaddr = dev->base_addr;
- int i;
/* Reset the chip. */
writew(CmdReset, ioaddr + ChipCmd);
@@ -666,48 +837,10 @@
printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
dev->name, dev->irq);
- init_ring(dev);
-
- writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
- writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
-
- for (i = 0; i < 6; i++)
- writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-
- /* Initialize other registers. */
- writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
- /* Configure the FIFO thresholds. */
- writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */
- np->tx_thresh = 0x20;
- np->rx_thresh = 0x60; /* Written in set_rx_mode(). */
-
- if (dev->if_port == 0)
- dev->if_port = np->default_port;
-
- dev->tbusy = 0;
- dev->interrupt = 0;
-
- set_rx_mode(dev);
-
- dev->start = 1;
+ alloc_rbufs(dev);
+ alloc_tbufs(dev);
- /* Enable interrupts by setting the interrupt mask. */
- writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
- IntrTxDone | IntrTxAbort | IntrTxUnderrun |
- IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
- ioaddr + IntrEnable);
-
- np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
- if (np->duplex_lock)
- np->chip_cmd |= CmdFDuplex;
- writew(np->chip_cmd, ioaddr + ChipCmd);
-
- check_duplex(dev);
- /* The LED outputs of various MII xcvrs should be configured. */
- /* For NS or Mison phys, turn on bit 1 in register 0x17 */
- /* For ESI phys, turn on bit 7 in register 0x17. */
- mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
- (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
+ init_registers(dev);
if (debug > 2)
printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
@@ -775,6 +908,7 @@
static void tx_timeout(struct device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
+ struct pci_dev *pdev = pci_find_slot(np->pci_bus, np->pci_devfn);
long ioaddr = dev->base_addr;
printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
@@ -782,60 +916,32 @@
dev->name, readw(ioaddr + IntrStatus),
mdio_read(dev, np->phys[0], 1));
- /* Perhaps we should reinitialize the hardware here. */
dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
- /* Trigger an immediate transmit demand. */
-
- dev->trans_start = jiffies;
- np->stats.tx_errors++;
- return;
-}
+ /* protect against concurrent rx interrupts */
+ disable_irq(pdev->irq);
+ /* Reset the chip. */
+ writew(CmdReset, ioaddr + ChipCmd);
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void init_ring(struct device *dev)
-{
- struct netdev_private *np = (struct netdev_private *)dev->priv;
- int i;
-
- np->tx_full = 0;
- np->cur_rx = np->cur_tx = 0;
- np->dirty_rx = np->dirty_tx = 0;
+ /* clear all descriptors */
+ free_tbufs(dev);
+ free_rbufs(dev);
+ alloc_tbufs(dev);
+ alloc_rbufs(dev);
+
+ /* Reinitialize the hardware. */
+ wait_for_reset(dev, dev->name);
+ init_registers(dev);
- np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
- np->rx_head_desc = &np->rx_ring[0];
+ enable_irq(pdev->irq);
- for (i = 0; i < RX_RING_SIZE; i++) {
- np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
- np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
- np->rx_skbuff[i] = 0;
- }
- /* Mark the last entry as wrapping the ring. */
- np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
+ dev->trans_start = jiffies;
+ np->stats.tx_errors++;
- /* Fill in the Rx buffers. Handle allocation failure gracefully. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
- np->rx_skbuff[i] = skb;
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
- np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
- }
- np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- np->tx_skbuff[i] = 0;
- np->tx_ring[i].tx_status = 0;
- np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
- np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
- np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
- }
- np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
+ /* wake queue */
+ clear_bit(0, (void*)&dev->tbusy);
+ mark_bh(NET_BH);
return;
}
@@ -1233,7 +1339,6 @@
{
long ioaddr = dev->base_addr;
struct netdev_private *np = (struct netdev_private *)dev->priv;
- int i;
dev->start = 0;
dev->tbusy = 1;
@@ -1255,27 +1360,8 @@
free_irq(dev->irq, dev);
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
- if (np->rx_skbuff[i]) {
-#if LINUX_VERSION_CODE < 0x20100
- np->rx_skbuff[i]->free = 1;
-#endif
- dev_kfree_skb(np->rx_skbuff[i]);
- }
- np->rx_skbuff[i] = 0;
- }
- for (i = 0; i < TX_RING_SIZE; i++) {
- if (np->tx_skbuff[i])
- dev_kfree_skb(np->tx_skbuff[i]);
- np->tx_skbuff[i] = 0;
- if (np->tx_buf[i]) {
- kfree(np->tx_buf[i]);
- np->tx_buf[i] = 0;
- }
- }
+ free_rbufs(dev);
+ free_tbufs(dev);
MOD_DEC_USE_COUNT;
prev parent reply other threads:[~2001-08-28 7:27 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-08-24 14:24 ISSUE: DFE530-TX REV-A3-1 times out on transmit David Schmitt
2001-08-25 17:05 ` Urban Widmark
2001-08-27 8:27 ` David Schmitt
2001-08-27 9:13 ` David Schmitt
2001-08-27 19:02 ` Urban Widmark
2001-08-28 13:45 ` David Schmitt
2001-08-28 19:46 ` Urban Widmark
2001-08-29 6:42 ` Dennis Bjorklund
2001-08-29 12:48 ` David Schmitt
2001-08-29 18:45 ` Urban Widmark
2001-08-31 12:18 ` David Schmitt
2001-08-28 7:26 ` Dennis Bjorklund [this message]
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=Pine.LNX.4.33.0108280921160.12686-200000@cosmo.zigo.dhs.org \
--to=db@zigo.dhs.org \
--cc=david@heureka.co.at \
--cc=linux-kernel@vger.kernel.org \
/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).