patch-2.2.11 linux/drivers/net/cosa.c
Next file: linux/drivers/net/cs89x0.c
Previous file: linux/drivers/net/com90xx.c
Back to the patch index
Back to the overall index
- Lines: 127
- Date:
Mon Aug 9 12:04:57 1999
- Orig file:
v2.2.10/linux/drivers/net/cosa.c
- Orig date:
Mon Jun 7 16:19:58 1999
diff -u --recursive --new-file v2.2.10/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
@@ -1,10 +1,7 @@
-/* $Id: cosa.c,v 1.24 1999/05/28 17:28:34 kas Exp $ */
+/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */
/*
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
- *
- * 5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
- * fixed a deadlock in cosa_sppp_open
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -105,6 +102,13 @@
#include "syncppp.h"
#include "cosa.h"
+/* Linux version stuff */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(wait, current) \
+ struct wait_queue wait = { current, NULL }
+#endif
+
/* Maximum length of the identification string. */
#define COSA_MAX_ID_STRING 128
@@ -133,7 +137,7 @@
struct semaphore rsem, wsem;
char *rxdata;
int rxsize;
- struct wait_queue *txwaitq, *rxwaitq;
+ wait_queue_head_t txwaitq, rxwaitq;
int tx_status, rx_status;
/* SPPP/HDLC device parts */
@@ -365,7 +369,7 @@
#endif
{
int i;
- printk(KERN_INFO "cosa v1.04 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
+ printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef __SMP__
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif
@@ -1273,10 +1277,8 @@
debug_status_out(cosa, 0);
#endif
}
- cosa_putdata8(cosa, 0);
cosa_putdata8(cosa, status);
#ifdef DEBUG_IO
- debug_data_cmd(cosa, 0);
debug_data_cmd(cosa, status);
#endif
}
@@ -1651,6 +1653,14 @@
* use the round-robin approach. The newer COSA firmwares have a simple
* flow-control - in the status word has bits 2 and 3 set to 1 means that the
* channel 0 or 1 doesn't want to receive data.
+ *
+ * It seems there is a bug in COSA firmware (need to trace it further):
+ * When the driver status says that the kernel has no more data for transmit
+ * (e.g. at the end of TX DMA) and then the kernel changes its mind
+ * (e.g. new packet is queued to hard_start_xmit()), the card issues
+ * the TX interrupt but does not mark the channel as ready-to-transmit.
+ * The fix seems to be to push the packet to COSA despite its request.
+ * We first try to obey the card's opinion, and then fall back to forced TX.
*/
static inline void tx_interrupt(struct cosa_data *cosa, int status)
{
@@ -1662,23 +1672,35 @@
spin_lock_irqsave(&cosa->lock, flags);
set_bit(TXBIT, &cosa->rxtx);
if (!test_bit(IRQBIT, &cosa->rxtx)) {
- /* flow control */
+ /* flow control, see the comment above */
int i=0;
- do {
- if (i++ > cosa->nchannels) {
- printk(KERN_WARNING
- "%s: No channel wants data in TX IRQ\n",
- cosa->name);
- put_driver_status_nolock(cosa);
- clear_bit(TXBIT, &cosa->rxtx);
- spin_unlock_irqrestore(&cosa->lock, flags);
- return;
- }
+ if (!cosa->txbitmap) {
+ printk(KERN_WARNING "%s: No channel wants data "
+ "in TX IRQ. Expect DMA timeout.",
+ cosa->name);
+ put_driver_status_nolock(cosa);
+ clear_bit(TXBIT, &cosa->rxtx);
+ spin_unlock_irqrestore(&cosa->lock, flags);
+ return;
+ }
+ while(1) {
cosa->txchan++;
+ i++;
if (cosa->txchan >= cosa->nchannels)
cosa->txchan = 0;
- } while ((!(cosa->txbitmap & (1<<cosa->txchan)))
- || status & (1<<(cosa->txchan+DRIVER_TXMAP_SHIFT)));
+ if (!(cosa->txbitmap & (1<<cosa->txchan)))
+ continue;
+ if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT)))
+ break;
+ /* in second pass, accept first ready-to-TX channel */
+ if (i > cosa->nchannels) {
+ /* Can be safely ignored */
+ printk(KERN_DEBUG "%s: Forcing TX "
+ "to not-ready channel %d\n",
+ cosa->name, cosa->txchan);
+ break;
+ }
+ }
cosa->txsize = cosa->chan[cosa->txchan].txsize;
if (cosa_dma_able(cosa->chan+cosa->txchan,
@@ -1788,6 +1810,7 @@
if (is_8bit(cosa)) {
if (!test_bit(IRQBIT, &cosa->rxtx)) {
set_bit(IRQBIT, &cosa->rxtx);
+ put_driver_status_nolock(cosa);
cosa->rxsize = cosa_getdata8(cosa) <<8;
#ifdef DEBUG_IO
debug_data_in(cosa, cosa->rxsize >> 8);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)