fcdsl locking patch

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

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 */
 
wiki/projects/linux/fcdsl.txt · Last modified: 2005/03/28 12:19 by e-razor
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki