lkml.org 
[lkml]   [2000]   [Jul]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
SubjectPROBLEM: <AT1700/FMV-18x hangs up>
From
Date
I'm a writer of "drivers/net/fmv18x.c" and and find FMV-181 hangs up
with glibc-2.1. Thus I made a patch both for kernel 2.2.16 and
2.4.0-test1. Please include my patches into the next kernel releases.

[1.] AT1700/FMV-18x hangs up
[2.] The Allied Telesys LAN card AT1700 and Fujitsu LAN card
FMV-181/182/183/184 hang up on a system with glibc-2.1
installed (RedHat 6.2, Debian 2.2, Vine-2.0, etc).
[3.] networking, Ethernet, at1700 fmv18x
[4.] Kernel 2.2.16, 2.4.0-test1
[5.] eth0: transmit timed out with status XXXX, network cable problem?
[X.] I made a patch for "at1700.c" not for "fmv18x.c", because
fmv18x.c is a code duplication of at1700.c, and at1700.c supports
FMV-18x LAN cards. Thus I want to obsolete fmv18x.c and want be a
maintainer of at1700.c.

Sincerely,
--------
Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)
FUJITSU LABS LTD.
Phone: +81-44-754-2663, Fax: +81-44-754-2664

diff -cr ../linux-2.2.16.orig/drivers/net/at1700.c ./drivers/net/at1700.c
*** ../linux-2.2.16.orig/drivers/net/at1700.c Wed Jul 26 00:48:42 2000
--- ./drivers/net/at1700.c Thu Jul 20 23:07:33 2000
***************
*** 35,41 ****
*/

static const char *version =
! "at1700.c:v1.15 4/7/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";

#include <linux/config.h>
#include <linux/module.h>
--- 35,42 ----
*/

static const char *version =
! "at1700.c:v2.2.16 Jul/20/00 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"
! " Yutaka Tamiya (tamy@flab.fujitsu.co.jp)\n";

#include <linux/config.h>
#include <linux/module.h>
***************
*** 111,120 ****
/* Information that need to be kept for each board. */
struct net_local {
struct enet_statistics stats;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
! uint tx_started:1; /* Packets are on the Tx queue. */
! uint tx_queue_ready:1; /* Tx queue is ready to be sent. */
uint rx_started:1; /* Packets are Rxing. */
uint invalid_irq:1;
uchar tx_queue; /* Number of packet on the Tx queue. */
--- 112,122 ----
/* Information that need to be kept for each board. */
struct net_local {
struct enet_statistics stats;
+ spinlock_t lock;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
! uint tx_started:1; /* Transmitting packets to network. */
! uint tx_full:1; /* Set iff the Tx queue is full. */
uint rx_started:1; /* Packets are Rxing. */
uint invalid_irq:1;
uchar tx_queue; /* Number of packet on the Tx queue. */
***************
*** 433,438 ****
--- 435,441 ----

{
struct net_local *lp = (struct net_local *)dev->priv;
+ lp->lock = SPIN_LOCK_UNLOCKED;
lp->jumpered = is_fmv18x;
lp->mca_slot = slot;
/* Snarf the interrupt vector now. */
***************
*** 511,517 ****
outb(0xe8, ioaddr + CONFIG_1);

lp->tx_started = 0;
! lp->tx_queue_ready = 1;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
--- 514,520 ----
outb(0xe8, ioaddr + CONFIG_1);

lp->tx_started = 0;
! lp->tx_full = 0;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
***************
*** 539,562 ****
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;

! if (dev->tbusy) {
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10)
return 1;
printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
! inw(ioaddr + STATUS), inb(ioaddr + TX_STATUS) & 0x80
? "IRQ conflict" : "network cable problem");
printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
! dev->name, inw(ioaddr + 0), inw(ioaddr + 2), inw(ioaddr + 4),
inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10),
inw(ioaddr + 12), inw(ioaddr + 14));
lp->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
outw(0xffff, ioaddr + 24);
! outw(0xffff, ioaddr + TX_STATUS);
outw(0xe85a, ioaddr + CONFIG_0);
outw(0x8182, ioaddr + TX_INTR);
outb(0x00, ioaddr + TX_START);
--- 542,575 ----
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
+ ushort status;
+ unsigned long flags;

! if (net_debug > 4)
! printk("%s: Tx, queue = %d, tx_full = %d, tbusy = %d, tx_started = %d.\n", dev->name, lp->tx_queue, lp->tx_full, (int) dev->tbusy, lp->tx_started);
!
! /* Block a timer-based transmit from overlapping. This could better be
! done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
! if (lp->tx_full
! || test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10)
return 1;
+ status = inw(ioaddr + STATUS); /* inw(ioaddr+8) will change STATUS */
printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
! status, status & 0x80
? "IRQ conflict" : "network cable problem");
printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
! dev->name, status, inw(ioaddr + 2), inw(ioaddr + 4),
inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10),
inw(ioaddr + 12), inw(ioaddr + 14));
+ spin_lock_irqsave(&lp->lock, flags);
lp->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
outw(0xffff, ioaddr + 24);
! outw(0xffff, ioaddr + STATUS);
outw(0xe85a, ioaddr + CONFIG_0);
outw(0x8182, ioaddr + TX_INTR);
outb(0x00, ioaddr + TX_START);
***************
*** 564,609 ****
dev->tbusy=0;
dev->trans_start = jiffies;
lp->tx_started = 0;
! lp->tx_queue_ready = 1;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
! }
!
! /* Block a timer-based transmit from overlapping. This could better be
! done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
! if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
! printk("%s: Transmitter access conflict.\n", dev->name);
! else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;

! /* We may not start transmitting unless we finish transferring
! a packet into the Tx queue. During executing the following
! codes we possibly catch a Tx interrupt. Thus we flag off
! tx_queue_ready, so that we prevent the interrupt routine
! (net_interrupt) to start transmitting. */
! lp->tx_queue_ready = 0;
! {
! outw(length, ioaddr + DATAPORT);
! outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
!
! lp->tx_queue++;
! lp->tx_queue_len += length + 2;
}
! lp->tx_queue_ready = 1;

if (lp->tx_started == 0) {
/* If the Tx is idle, always trigger a transmit. */
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
lp->tx_started = 1;
! dev->tbusy = 0;
! } else if (lp->tx_queue_len < 4096 - 1502)
! /* Yes, there is room for one more packet. */
! dev->tbusy = 0;
}
dev_kfree_skb (skb);

--- 577,628 ----
dev->tbusy=0;
dev->trans_start = jiffies;
lp->tx_started = 0;
! lp->tx_full = 0;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
! spin_unlock_irqrestore(&lp->lock, flags);
! return 1;
! } else {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;

! /* Somtimes Tx/Rx interrupts are lost. In order to prevent
! our driver from hung up, we call net_interrupt() directly.
! Since net_interupt() is reentrant, we can call it at any
! time. */
! status = inw(ioaddr + TX_STATUS);
! if (dev->interrupt == 0 && (status & 0x8082) != 0) {
! if (net_debug > 4)
! printk("%s: call net_interrupt in Tx, status = %04x.\n",
! dev->name, status);
! net_interrupt(dev->irq, dev, NULL);
}
!
! spin_lock_irqsave(&lp->lock, flags);
!
! outw(length, ioaddr + DATAPORT);
! outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
!
! lp->tx_queue++;
! lp->tx_queue_len += length + 2;
! lp->tx_full = 0;

if (lp->tx_started == 0) {
+ if (net_debug > 4)
+ printk("%s: Start Txing in send, queue = %d.\n", dev->name, lp->tx_queue);
/* If the Tx is idle, always trigger a transmit. */
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
lp->tx_started = 1;
! } else if (lp->tx_queue_len >= 4096 - 1502) {
! /* No, there is no room for any more packets. */
! lp->tx_full = 1;
! }
! clear_bit(0, (void*) &dev->tbusy);
! spin_unlock_irqrestore(&lp->lock, flags);
}
dev_kfree_skb (skb);

***************
*** 618,623 ****
--- 637,643 ----
struct device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;
+ unsigned long flags;

if (dev == NULL) {
printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
***************
*** 627,639 ****

ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
! status = inw(ioaddr + TX_STATUS);
! outw(status, ioaddr + TX_STATUS);

if (net_debug > 4)
printk("%s: Interrupt with status %04x.\n", dev->name, status);
if (lp->rx_started == 0 &&
! (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
/* Got a packet(s).
We cannot execute net_rx more than once at the same time for
the same device. During executing net_rx, we possibly catch a
--- 647,662 ----

ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
!
! spin_lock_irqsave(&lp->lock, flags);
!
! status = inw(ioaddr + STATUS);
! outw(status, ioaddr + STATUS);

if (net_debug > 4)
printk("%s: Interrupt with status %04x.\n", dev->name, status);
if (lp->rx_started == 0 &&
! ((status & 0xff00) != 0 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
/* Got a packet(s).
We cannot execute net_rx more than once at the same time for
the same device. During executing net_rx, we possibly catch a
***************
*** 647,653 ****
lp->rx_started = 0;
}
if (status & 0x00ff) {
! if (status & 0x02) {
/* More than 16 collisions occurred */
if (net_debug > 4)
printk("%s: 16 Collision occur during Txing.\n", dev->name);
--- 670,676 ----
lp->rx_started = 0;
}
if (status & 0x00ff) {
! if (status & 0x0002) {
/* More than 16 collisions occurred */
if (net_debug > 4)
printk("%s: 16 Collision occur during Txing.\n", dev->name);
***************
*** 655,681 ****
outb(0x03, ioaddr + COL16CNTL);
lp->stats.collisions++;
}
! if (status & 0x82) {
lp->stats.tx_packets++;
/* The Tx queue has any packets and is not being
transferred a packet from the host, start
transmitting. */
! if (lp->tx_queue && lp->tx_queue_ready) {
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
! dev->tbusy = 0;
mark_bh(NET_BH); /* Inform upper layers. */
} else {
lp->tx_started = 0;
! dev->tbusy = 0;
mark_bh(NET_BH); /* Inform upper layers. */
}
}
}

dev->interrupt = 0;
return;
}

--- 678,713 ----
outb(0x03, ioaddr + COL16CNTL);
lp->stats.collisions++;
}
! if (status & 0x0082) {
lp->stats.tx_packets++;
+ lp->tx_full = 0;
/* The Tx queue has any packets and is not being
transferred a packet from the host, start
transmitting. */
! if (lp->tx_queue
! && test_and_set_bit(0, (void*) &dev->tbusy) == 0) {
! if (net_debug > 4)
! printk("%s: Start Txing in intr, queue = %d.\n", dev->name, lp->tx_queue);
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
! clear_bit(0, (void*) &dev->tbusy);
mark_bh(NET_BH); /* Inform upper layers. */
} else {
lp->tx_started = 0;
! /*clear_bit(0, (void*) &dev->tbusy);*/
mark_bh(NET_BH); /* Inform upper layers. */
}
}
}

+ spin_unlock_irqrestore(&lp->lock, flags);
dev->interrupt = 0;
+
+ if (net_debug > 4)
+ printk("%s: End Interrupt with status %04x.\n", dev->name, status);
+
return;
}

diff -cr ../linux-2.4.0-test1.orig/Documentation/Configure.help ./Documentation/Configure.help
*** ../linux-2.4.0-test1.orig/Documentation/Configure.help Wed Jul 26 01:02:09 2000
--- ./Documentation/Configure.help Wed Jul 26 01:25:49 2000
***************
*** 8497,8529 ****
Documentation/networking/net-modules.txt. The module will be called
ewrk3.o.

! AT1700/1720 support
CONFIG_AT1700
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto .

This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
If you want to compile it as a module, say M here and read
Documentation/modules.txt as well as
Documentation/networking/net-modules.txt. The module will be called
at1700.o.
- FMV-181/182/183/184 support
- CONFIG_FMV18X
- If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card,
- say Y and read the Ethernet-HOWTO, available from
- http://www.linuxdoc.org/docs.html#howto .
-
- If you use an FMV-183 or FMV-184 and it is not working, you may need
- to disable Plug & Play mode of the card.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called fmv18x.o. If you want to compile it as a
- module, say M here and read Documentation/modules.txt as well as
- Documentation/networking/net-modules.txt.

EtherExpress PRO support
CONFIG_EEXPRESS_PRO
--- 8497,8518 ----
Documentation/networking/net-modules.txt. The module will be called
ewrk3.o.

! AT1700/1720, FMV-181/182/183/184 support
CONFIG_AT1700
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
http://www.linuxdoc.org/docs.html#howto .

+ If you use an FMV-183 or FMV-184 and it is not working, you may neeed
+ to use isapnptools, or disable Plug & Play mode of the card with its
+ DOS utility program.
+
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
If you want to compile it as a module, say M here and read
Documentation/modules.txt as well as
Documentation/networking/net-modules.txt. The module will be called
at1700.o.

EtherExpress PRO support
CONFIG_EEXPRESS_PRO
diff -cr ../linux-2.4.0-test1.orig/drivers/net/Config.in ./drivers/net/Config.in
*** ../linux-2.4.0-test1.orig/drivers/net/Config.in Wed Jul 26 01:00:47 2000
--- ./drivers/net/Config.in Wed Jul 26 01:06:24 2000
***************
*** 93,101 ****
tristate ' NI5210 support' CONFIG_NI52
tristate ' NI6510 support' CONFIG_NI65
fi
! if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
! tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
! fi
tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
bool ' Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
--- 93,99 ----
tristate ' NI5210 support' CONFIG_NI52
tristate ' NI6510 support' CONFIG_NI65
fi
! tristate ' AT1700/1720, FMV-181/182/183/184 support' CONFIG_AT1700
tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
bool ' Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
***************
*** 105,113 ****
fi
tristate ' EtherExpress 16 support' CONFIG_EEXPRESS
tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO
- if [ "$CONFIG_OBSOLETE" = "y" ]; then
- tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X
- fi
tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
--- 103,108 ----
diff -cr ../linux-2.4.0-test1.orig/drivers/net/Space.c ./drivers/net/Space.c
*** ../linux-2.4.0-test1.orig/drivers/net/Space.c Wed Jul 26 01:00:33 2000
--- ./drivers/net/Space.c Wed Jul 26 01:05:07 2000
***************
*** 257,265 ****
#ifdef CONFIG_AT1700
{at1700_probe, 0},
#endif
- #ifdef CONFIG_FMV18X /* Fujitsu FMV-181/182 */
- {fmv18x_probe, 0},
- #endif
#ifdef CONFIG_ETH16I
{eth16i_probe, 0}, /* ICL EtherTeam 16i/32 */
#endif
--- 257,262 ----
diff -cr ../linux-2.4.0-test1.orig/drivers/net/at1700.c ./drivers/net/at1700.c
*** ../linux-2.4.0-test1.orig/drivers/net/at1700.c Wed Jul 26 01:00:12 2000
--- ./drivers/net/at1700.c Thu Jul 20 23:48:34 2000
***************
*** 35,41 ****
*/

static const char *version =
! "at1700.c:v1.15 4/7/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";

#include <linux/config.h>
#include <linux/module.h>
--- 35,42 ----
*/

static const char *version =
! "at1700.c:v2.4.0 Jul/20/00 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"
! " Yutaka Tamiya (tamy@flab.fujitsu.co.jp)\n";

#include <linux/config.h>
#include <linux/module.h>
***************
*** 114,124 ****
spinlock_t lock;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
! uint tx_started:1; /* Packets are on the Tx queue. */
! uint tx_queue_ready:1; /* Tx queue is ready to be sent. */
uint rx_started:1; /* Packets are Rxing. */
uint invalid_irq:1;
! uchar tx_queue; /* Number of packet on the Tx queue. */
char mca_slot; /* -1 means ISA */
ushort tx_queue_len; /* Current length of the Tx queue. */
};
--- 115,127 ----
spinlock_t lock;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
! uint tx_started:1; /* Transmitting packets to network. */
! uint tx_full:1; /* Set iff the Tx queue is full. */
uint rx_started:1; /* Packets are Rxing. */
+ uint interrupt:1; /* net_interrupt() is executing. */
uint invalid_irq:1;
! uint tx_busy; /* Transferring packets to the Tx queue. */
! uchar tx_queue; /* Number of packets on the Tx queue. */
char mca_slot; /* -1 means ISA */
ushort tx_queue_len; /* Current length of the Tx queue. */
};
***************
*** 438,444 ****
dev->watchdog_timeo = TX_TIMEOUT;

lp = (struct net_local *)dev->priv;
! lp->lock = SPIN_LOCK_UNLOCKED;

/* Fill in the fields of 'dev' with ethernet-generic values. */
ether_setup(dev);
--- 441,447 ----
dev->watchdog_timeo = TX_TIMEOUT;

lp = (struct net_local *)dev->priv;
! spin_lock_init(&lp->lock);

/* Fill in the fields of 'dev' with ethernet-generic values. */
ether_setup(dev);
***************
*** 520,529 ****
outb(0xe8, ioaddr + CONFIG_1);

lp->tx_started = 0;
! lp->tx_queue_ready = 1;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;

/* Turn on hardware Tx and Rx interrupts. */
outb(0x82, ioaddr + TX_INTR);
--- 523,534 ----
outb(0xe8, ioaddr + CONFIG_1);

lp->tx_started = 0;
! lp->tx_full = 0;
lp->rx_started = 0;
+ lp->tx_busy = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
+ lp->interrupt = 0;

/* Turn on hardware Tx and Rx interrupts. */
outb(0x82, ioaddr + TX_INTR);
***************
*** 545,562 ****
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;

printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
! inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
? "IRQ conflict" : "network cable problem");
printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
! dev->name, inw (ioaddr + 0), inw (ioaddr + 2), inw (ioaddr + 4),
inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10),
inw (ioaddr + 12), inw (ioaddr + 14));
lp->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
outw (0xffff, ioaddr + 24);
! outw (0xffff, ioaddr + TX_STATUS);
outw (0xe85a, ioaddr + CONFIG_0);
outw (0x8182, ioaddr + TX_INTR);
outb (0x00, ioaddr + TX_START);
--- 550,568 ----
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
+ ushort status = inw(ioaddr + STATUS); /* inw(ioaddr+8) will change STATUS */

printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
! status, status & 0x80
? "IRQ conflict" : "network cable problem");
printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
! dev->name, status, inw (ioaddr + 2), inw (ioaddr + 4),
inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10),
inw (ioaddr + 12), inw (ioaddr + 14));
lp->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
outw (0xffff, ioaddr + 24);
! outw (0xffff, ioaddr + STATUS);
outw (0xe85a, ioaddr + CONFIG_0);
outw (0x8182, ioaddr + TX_INTR);
outb (0x00, ioaddr + TX_START);
***************
*** 565,571 ****
dev->trans_start = jiffies;

lp->tx_started = 0;
! lp->tx_queue_ready = 1;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
--- 571,578 ----
dev->trans_start = jiffies;

lp->tx_started = 0;
! lp->tx_full = 0;
! lp->tx_busy = 0;
lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
***************
*** 580,614 ****
int ioaddr = dev->base_addr;
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;

! netif_stop_queue (dev);

! /* We may not start transmitting unless we finish transferring
! a packet into the Tx queue. During executing the following
! codes we possibly catch a Tx interrupt. Thus we flag off
! tx_queue_ready, so that we prevent the interrupt routine
! (net_interrupt) to start transmitting. */
! lp->tx_queue_ready = 0;
! {
! outw (length, ioaddr + DATAPORT);
! outsw (ioaddr + DATAPORT, buf, (length + 1) >> 1);

! lp->tx_queue++;
! lp->tx_queue_len += length + 2;
}
! lp->tx_queue_ready = 1;

if (lp->tx_started == 0) {
/* If the Tx is idle, always trigger a transmit. */
outb (0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
lp->tx_started = 1;
netif_start_queue (dev);
! } else if (lp->tx_queue_len < 4096 - 1502)
/* Yes, there is room for one more packet. */
netif_start_queue (dev);
dev_kfree_skb (skb);

return 0;
--- 587,644 ----
int ioaddr = dev->base_addr;
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
+ ushort status;
+ unsigned long flags;

! if (net_debug > 4)
! printk("%s: Tx, queue = %d, tx_full = %d, tx_busy = %d, tx_started = %d.\n", dev->name, lp->tx_queue, lp->tx_full, lp->tx_busy, lp->tx_started);

! netif_stop_queue (dev);

! /* If Tx queue is full or we cannot get the lock, return imediately. */
! if (lp->tx_full
! || test_and_set_bit(0, (void*) &lp->tx_busy) !=0)
! return 1;
!
! /* Somtimes Tx/Rx interrupts are lost. In order to prevent our driver
! from hung up, we call net_interrupt() directly. Since net_interupt()
! is reentrant, we can call it at any time. */
! status = inw(ioaddr + TX_STATUS);
! if (lp->interrupt == 0 && (status & 0x8082) != 0) {
! if (net_debug > 4)
! printk("%s: call net_interrupt in Tx, status = %04x.\n", dev->name, status);
! net_interrupt(dev->irq, dev, NULL);
}
!
! spin_lock_irqsave(&lp->lock, flags);
!
! outw (length, ioaddr + DATAPORT);
! outsw (ioaddr + DATAPORT, buf, (length + 1) >> 1);
!
! lp->tx_queue++;
! lp->tx_queue_len += length + 2;

if (lp->tx_started == 0) {
+ if (net_debug > 4)
+ printk("%s: Start Txing in send, queue = %d.\n", dev->name, lp->tx_queue);
/* If the Tx is idle, always trigger a transmit. */
outb (0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
lp->tx_started = 1;
+ lp->tx_full = 0;
netif_start_queue (dev);
! } else if (lp->tx_queue_len < 4096 - 1502) {
/* Yes, there is room for one more packet. */
netif_start_queue (dev);
+ lp->tx_full = 0;
+ } else {
+ lp->tx_full = 1;
+ }
+
+ clear_bit(0, (void*) &lp->tx_busy);
+ spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb (skb);

return 0;
***************
*** 622,645 ****
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;

if (dev == NULL) {
printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
return;
}
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;

! spin_lock (&lp->lock);
!
! status = inw(ioaddr + TX_STATUS);
! outw(status, ioaddr + TX_STATUS);

if (net_debug > 4)
printk("%s: Interrupt with status %04x.\n", dev->name, status);
if (lp->rx_started == 0 &&
! (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
/* Got a packet(s).
We cannot execute net_rx more than once at the same time for
the same device. During executing net_rx, we possibly catch a
--- 652,676 ----
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;
+ unsigned long flags;

if (dev == NULL) {
printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
return;
}
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
+ lp->interrupt = 1;

! spin_lock_irqsave(&lp->lock, flags);
!
! status = inw(ioaddr + STATUS);
! outw(status, ioaddr + STATUS);

if (net_debug > 4)
printk("%s: Interrupt with status %04x.\n", dev->name, status);
if (lp->rx_started == 0 &&
! ((status & 0xff00) != 0 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
/* Got a packet(s).
We cannot execute net_rx more than once at the same time for
the same device. During executing net_rx, we possibly catch a
***************
*** 653,659 ****
lp->rx_started = 0;
}
if (status & 0x00ff) {
! if (status & 0x02) {
/* More than 16 collisions occurred */
if (net_debug > 4)
printk("%s: 16 Collision occur during Txing.\n", dev->name);
--- 684,690 ----
lp->rx_started = 0;
}
if (status & 0x00ff) {
! if (status & 0x0002) {
/* More than 16 collisions occurred */
if (net_debug > 4)
printk("%s: 16 Collision occur during Txing.\n", dev->name);
***************
*** 661,676 ****
outb(0x03, ioaddr + COL16CNTL);
lp->stats.collisions++;
}
! if (status & 0x82) {
lp->stats.tx_packets++;
/* The Tx queue has any packets and is not being
transferred a packet from the host, start
transmitting. */
! if (lp->tx_queue && lp->tx_queue_ready) {
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
netif_wake_queue (dev);
} else {
lp->tx_started = 0;
--- 692,712 ----
outb(0x03, ioaddr + COL16CNTL);
lp->stats.collisions++;
}
! if (status & 0x0082) {
lp->stats.tx_packets++;
+ lp->tx_full = 0;
/* The Tx queue has any packets and is not being
transferred a packet from the host, start
transmitting. */
! if (lp->tx_queue
! && test_and_set_bit(0, (void*) &lp->tx_busy) == 0) {
! if (net_debug > 4)
! printk("%s: Start Txing in intr, queue = %d.\n", dev->name, lp->tx_queue);
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
+ clear_bit(0, (void*) &lp->tx_busy);
netif_wake_queue (dev);
} else {
lp->tx_started = 0;
***************
*** 679,685 ****
}
}

! spin_unlock (&lp->lock);
return;
}

--- 715,725 ----
}
}

! spin_unlock_irqrestore(&lp->lock, flags);
! lp->interrupt = 0;
!
! if (net_debug > 4)
! printk("%s: End Interrupt with status %04x.\n", dev->name, status);
return;
}

***************
*** 781,789 ****
/* Disable the IRQ on boards of fmv18x where it is feasible. */
if (lp->jumpered) {
outb(0x00, ioaddr + IOCONFIG1);
- free_irq(dev->irq, dev);
}

/* Power-down the chip. Green, green, green! */
outb(0x00, ioaddr + CONFIG_1);

--- 821,830 ----
/* Disable the IRQ on boards of fmv18x where it is feasible. */
if (lp->jumpered) {
outb(0x00, ioaddr + IOCONFIG1);
}

+ free_irq(dev->irq, dev);
+
/* Power-down the chip. Green, green, green! */
outb(0x00, ioaddr + CONFIG_1);

***************
*** 918,924 ****
dev_at1700.priv = NULL;

/* If we don't do this, we can't re-insmod it later. */
! free_irq(dev_at1700.irq, NULL);
release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
}
#endif /* MODULE */
--- 959,965 ----
dev_at1700.priv = NULL;

/* If we don't do this, we can't re-insmod it later. */
! /*free_irq(dev_at1700.irq, NULL);*/
release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
}
#endif /* MODULE */
\
 
 \ /
  Last update: 2005-03-22 13:57    [W:0.059 / U:0.224 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site