--- driver.c.orig 2004-05-14 02:00:00.000000000 +0200 +++ driver.c 2005-01-21 15:40:33.000000000 +0100 @@ -18,6 +18,10 @@ * 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 + * Fixed for rev 0.4.1 by Stefan Schweizer */ #include @@ -57,6 +61,8 @@ #include "dbgif.h" #endif +#undef SINGLE_LOCK + #define KILOBYTE 1024 #define MEGABYTE (1024*KILOBYTE) #define DMA_BUFFER_SIZE (9*KILOBYTE) @@ -101,7 +107,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); @@ -1142,7 +1152,7 @@ } /* remove_ctrl */ /*---------------------------------------------------------------------------*\ -\*-C-------------------------------------------------------------------------*/ +\*---------------------------------------------------------------------------*/ static inline int in_critical (void) { return (0 < atomic_read (&crit_count)); @@ -1301,7 +1311,7 @@ capi_ctr_handle_message (ctrl, appl, skb); } /* msg2capi */ -/*-S-------------------------------------------------------------------------*\ +/*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static __attr void __stack scheduler_control (unsigned ena) { int enabled = (int) ena; @@ -1323,6 +1333,7 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static int sched_thread (void * arg) { + unsigned long flags; UNUSED_ARG (arg); daemonize (TARGET); @@ -1356,6 +1367,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 +1376,7 @@ } spin_unlock (&stack_lock); } + local_irq_restore(flags); } LOG("Scheduler thread stopped.\n"); up (&hotplug); @@ -1470,17 +1483,22 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ 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 { - 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 +1551,22 @@ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ 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 { - 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 */ @@ -1562,6 +1585,7 @@ return IRQ_NONE; } cp = (card_p) args; + spin_lock (&stack_lock); while (0 != ((flags = PEEK (cp->io_base + INT_CTL)) & CARD_PCI_INT_ASSERT)) { ++count; assert (count < 3); @@ -1572,6 +1596,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 +1611,7 @@ } } info (0 == (PEEK (cp->io_base + INT_CTL) & CARD_PCI_INT_ASSERT)); + spin_unlock (&stack_lock); return IRQ_RETVAL(count > 0); } /* irq_handler */