Well I'm having problems with the fritz-card dsl since linux 2.4 on my via epia (ITX form factor) router .
As far as i know, the fcdsl uses bus-master mode which causes system hangs sometimes. This patch should solve it.
It's based on the old driver patch from Christian Heckhoff.
Some more informations: http://freiburg.linux.de/~zeisberg/howtos/fritzcarddsl.html
The patchfile: fcdsl-suse9.1-3.11-02-locking.patch
--- driver.c 2005-03-28 09:53:06.000000000 +0200 +++ driver.c 2005-03-28 10:06:52.000000000 +0200 @@ -18,7 +18,11 @@ * http://www.opensource.org/licenses/lgpl-license.html * * Contact: AVM GmbH, Alt-Moabit 95, 10559 Berlin, Germany, email: info@avm.de - */ + * + * Mon Oct 20 22:43:31 2003 + * Modified by Joerg Lehrke to improve locking + * +*/ #include <asm/io.h> #include <asm/irq.h> @@ -57,6 +61,9 @@ #include "dbgif.h" #endif +#undef SINGLE_LOCK + + #define KILOBYTE 1024 #define MEGABYTE (1024*KILOBYTE) #define DMA_BUFFER_SIZE (9*KILOBYTE) @@ -101,7 +108,11 @@ static struct capi_ctr capi_ctrl[2]; static int capi_ctrl_ix = 0; static per_ctrl_t ctrl_params[2]; +#if defined (SINGLE_LOCK) +# define stack_lock qt_lock +#else static spinlock_t stack_lock = SPIN_LOCK_UNLOCKED; +#endif static atomic_t rx_flag = ATOMIC_INIT (0); static atomic_t tx_flag = ATOMIC_INIT (0); static atomic_t thread_flag = ATOMIC_INIT (0); @@ -1151,12 +1162,16 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static inline void check (void) { - + unsigned long flags; if (atomic_xchg (&rx_flag, 0)) { + spin_lock_irqsave (&stack_lock, flags); rx_handler (capi_card); + spin_unlock_irqrestore (&stack_lock, flags); } if (atomic_xchg (&tx_flag, 0)) { + spin_lock_irqsave (&stack_lock, flags); tx_handler (capi_card); + spin_unlock_irqrestore (&stack_lock, flags); } } /* check */ @@ -1323,7 +1338,7 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static int sched_thread (void * arg) { - + unsigned long flags; UNUSED_ARG (arg); daemonize (TARGET); snprintf (current->comm, 16, "%s_s", TARGET); @@ -1356,6 +1371,7 @@ } /* Body of thread, invoke scheduler */ + local_irq_save(flags); if (spin_trylock (&stack_lock)) { os_timer_poll (); assert (capi_lib->cm_schedule); @@ -1364,6 +1380,7 @@ } spin_unlock (&stack_lock); } + local_irq_restore(flags); } LOG("Scheduler thread stopped.\n"); up (&hotplug); @@ -1470,17 +1487,27 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static void tx_task (unsigned long data) { - + unsigned long flags; UNUSED_ARG (data); if (in_critical ()) { atomic_set (&tx_flag, 1); kick_scheduler (); - } else if (spin_trylock (&stack_lock)) { - tx_handler (capi_card); - spin_unlock (&stack_lock); +// } else if (spin_trylock (&stack_lock)) { +// tx_handler (capi_card); +// spin_unlock (&stack_lock); } else { - atomic_set (&tx_flag, 1); - kick_scheduler (); +// atomic_set (&tx_flag, 1); +// kick_scheduler (); + local_irq_save(flags); + if (spin_trylock (&stack_lock)) { + tx_handler (capi_card); + spin_unlock (&stack_lock); + } else { + atomic_set (&tx_flag, 1); + kick_scheduler (); + } + local_irq_restore(flags); + } } /* tx_task */ @@ -1533,17 +1560,27 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static void rx_task (unsigned long data) { - + unsigned long flags; UNUSED_ARG (data); if (in_critical ()) { atomic_set (&rx_flag, 1); kick_scheduler (); - } else if (spin_trylock (&stack_lock)) { - rx_handler (capi_card); - spin_unlock (&stack_lock); +// } else if (spin_trylock (&stack_lock)) { +// rx_handler (capi_card); +// spin_unlock (&stack_lock); } else { - atomic_set (&rx_flag, 1); - kick_scheduler (); +// atomic_set (&rx_flag, 1); +// kick_scheduler (); + local_irq_save(flags); + if (spin_trylock (&stack_lock)) { + rx_handler (capi_card); + spin_unlock (&stack_lock); + } else { + atomic_set (&rx_flag, 1); + kick_scheduler (); + } + local_irq_restore(flags); + } } /* rx_task */ @@ -1561,6 +1598,7 @@ if (capi_card != (card_p) args) { return IRQ_NONE; } + spin_lock (&stack_lock); cp = (card_p) args; while (0 != ((flags = PEEK (cp->io_base + INT_CTL)) & CARD_PCI_INT_ASSERT)) { ++count; @@ -1572,6 +1610,7 @@ assert ((PEEK (cp->io_base + INT_CTL) & ~(CARD_PCI_INT_ASSERT | CARD_PCI_INT_ISASSERTED)) != 0); if (!atomic_read (&link_open)) { + spin_unlock (&stack_lock); return IRQ_HANDLED; } tx_flag = PEEK (cp->io_base + XFER_TOTM_STATUS) == TM_READY; @@ -1586,6 +1625,7 @@ } } info (0 == (PEEK (cp->io_base + INT_CTL) & CARD_PCI_INT_ASSERT)); + spin_unlock (&stack_lock); return IRQ_RETVAL(count > 0); } /* irq_handler */