Driver works for a while, and then hangs silently (possible fix?)

MIchael MacDonald <[email protected]> Wed, 26 Mar 2003 17:53:12 -0500
Newsgroups gmane.linux.drivers.realtek.devel
Message-ID <[email protected]>
I have a D-Link DFE690-TXD Cardbus card based on the 8139 running as the 
second ethernet adapter in a Toshiba Satellite 1415-S105 laptop with 
Slackware 8.1 (kernel version 2.4.18).  I built and installed the 
rtl8139.c adapter and it seemed to work fine for a day or so, but then 
the card stopped responding--the computer could do no input or output 
over that interface.  Rebooting the laptop cleared the problem.

This happened several times (the laptop was plugged in the whole time 
and no power management features were turned on).  The problem seemed to 
be load dependent.  I was able to find a load (the GNOME galaxy screen 
saver directed to a remote X display) that would consistently hang the 
card after a few minutes.

I set the debug=8 module option.  I now got "Media selection tick" 
messages from the module every minute, both before and after it hanged, 
but no other message.  Looking at the interface with ifconfig, it would 
show no packet errors either before or after it stopped working. 
However, I noticed that after the interface stopped working, the packet 
receive count would continue to go up (presumably as it received packets 
from other machines on that network), but the packet sent count would 
stay constant.

I tried the rtl8139-diag program.  I noticed that when the card was 
"hung", it continued to cycle through its receive buffer address space, 
but that its send buffer registers stayed constant.

At this point I tried poking around in the rtl8139.c source code.  It 
seemed as though that it should be invariant that if 
netif_queue_paused(dev)  was true, the send queue should be full.  So I 
put the following test in the rtl8139_timer function:

	if (netif_queue_paused(dev) && np->cur_tx - (volatile unsigned 
int)np->dirty_tx < NUM_TX_DESC) {
		if ( netif_queue_paused(dev))
			rtl8129_tx_timeout(dev);
	}

(where I test netif_queue_paused twice to avoid a race condition)

When I tried this version of the driver, sure enough after the card 
hanged, at the next "Media selection tick" interval, the module reported 
a transmit time out and reset the transmit queue.  However, this did not 
unhang the card!  It would report the transmit time out again every 
timer interval, and seem to reset the chip, but the interface remained 
hanged.

After further poking around in the driver source, I guessed that it 
might be a good idea to call netif_resume_tx_queue instead of 
netif_unpause_tx_queue (which is a NOOP on 2.4+ kernels) at the end of 
the rtl8129_tx_timeout function.  I made this change.  Now, when the 
card becomes hanged, at the next timer interval, the test I inserted 
detects the condition and the rtl8129_tx_timeout function successfully 
gets the card going again.

OK, this makes the card usable again, since I can put up with the 
very-occasional x-second delay before the card resets.  However, perhaps 
there is a better way to keep the problem I am detecting from arising in 
the first place?