[svn-commits] sruffell: branch linux/sruffell/dahdi-linux-chainedvb r7340 - /linux/team/sru...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Oct 5 16:55:08 CDT 2009


Author: sruffell
Date: Mon Oct  5 16:54:58 2009
New Revision: 7340

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=7340
Log:
wip: Printing messages in the middle of softunder recovery can cause lock.

If console printing is enabled, printing any messages during the softunderrun
recovery can cause the hardware to advance beyond the 'fixed' head and tail
pointers.  This means that eventually the hardware will wrap back around to the
idle buffer descriptor that it completed (which doesn't have the OWN bit set)
and lock up.

Modified:
    linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c

Modified: linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c
URL: http://svnview.digium.com/svn/dahdi/linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c?view=diff&rev=7340&r1=7339&r2=7340
==============================================================================
--- linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c Mon Oct  5 16:54:58 2009
@@ -28,7 +28,7 @@
  */
 
 #define DEBUG
-#define HERE() printk(KERN_DEBUG "HERE: %s:%d\n", __FILE__, __LINE__)
+#define HERE() do { printk(KERN_DEBUG "HERE: %s:%d\n", __FILE__, __LINE__); } while(0)
 
 static int debug;
 
@@ -53,7 +53,7 @@
 #define TIMER 2		/* Run in a system timer. */
 #define WORKQUEUE 3	/* Run in a workqueue. */
 #ifndef VOICEBUS_DEFERRED
-#define VOICEBUS_DEFERRED INTERRUPT
+#define VOICEBUS_DEFERRED TASKLET
 #endif
 #if VOICEBUS_DEFERRED == WORKQUEUE
 #define VOICEBUS_ALLOC_FLAGS GFP_KERNEL
@@ -117,6 +117,15 @@
 #define 	CSR9_MDI		0x00080000
 
 #define OWN_BIT (1 << 31)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+/* Also don't define this for later RHEL >= 5.2 . hex_asc is from the 
+ * same linux-2.6-net-infrastructure-updates-to-mac80211-iwl4965.patch
+ * as is the bool typedef. */
+#if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,18)  || !  defined(hex_asc)
+typedef int			bool;
+#endif
+#endif
 
 /* In memory structure shared by the host and the adapter. */
 struct voicebus_descriptor {
@@ -229,8 +238,6 @@
 	unsigned int 	min_tx_buffer_count;
 };
 
-DEFINE_RATELIMIT_STATE(voicebus_ratelimit_state, HZ, 100);
-
 /*
  * Use the following macros to lock the VoiceBus interface, and it won't
  * matter if the deferred processing is running inside the interrupt handler,
@@ -806,18 +813,6 @@
 		return -EFAULT;
 	}
 
-#if 0 /* !!!TODO!!! */
-	/* If we're on the idle buffer, but it isn't owned, we're in a
-	 * softunderrun condition that wasn't handled.
-	 */
-	if (unlikely(!OWNED(d->desc))) {
-		if (__ratelimit(&voicebus_ratelimit_state))
-			dev_err(&vb->pdev->dev, "tx descriptor overrun.\n");
-		voicebus_free(vb, vbb);
-		return -EFAULT;
-	}
-#endif
-
 	dl->tail = get_next_descriptor(dl, d);
 	d->pending = vbb;
 	d->desc->buffer2 = dl->tail->dma_addr;
@@ -1269,53 +1264,38 @@
 static void
 __vb_increase_latency(struct voicebus *vb, int increase)
 {
-	static int __warn_once = 1;
 	void *vbb;
 	int latency;
 
 	assert_in_vb_deferred(vb);
 
-	latency = vb->min_tx_buffer_count;
-	if (MAX_LATENCY == latency) {
-		if (__warn_once) {
-			/* We must subtract two from this number since there
-			 * are always two buffers in the TX FIFO.
-			 */
-			dev_err(&vb->pdev->dev,
-				"ERROR: Unable to service card within %d ms "\
-				"and unable to further increase latency.\n",
-				MAX_LATENCY-2);
-			__warn_once = 0;
-		}
-	} else {
-		latency = (latency + increase > MAX_LATENCY) ?
-				MAX_LATENCY : latency+increase;
-		/* Because there are 2 buffers in the transmit FIFO on the
-		 * hardware, setting 3 ms of latency means that the host needs
-		 * to be able to service the cards within 1ms.  This is because
-		 * the interface will load up 2 buffers into the TX FIFO then
-		 * attempt to read the 3rd descriptor.  If the OWN bit isn't
-		 * set, then the hardware will set the TX descriptor not
-		 * available interrupt.
-		 */
-		dev_info(&vb->pdev->dev, "Missed interrupt. " \
-			"Increasing latency to %d ms in order to compensate.\n",
-			latency);
-		/* Set the minimum latency in case we're restarted...we don't
-		 * want to wait for the buffer to grow to this depth again in
-		 * that case.
-		 */
-		increase = latency - vb->min_tx_buffer_count;
-		while (increase--) {
-			vbb = voicebus_alloc(vb);
-
-			if (unlikely(NULL == vbb))
-				BUG_ON(1);
-			else
-				vb->handle_transmit(vbb, vb->context);
-		}
-		voicebus_set_minlatency(vb, latency);
-	}
+	if (MAX_LATENCY == vb->min_tx_buffer_count)
+		return;
+
+	latency = (vb->min_tx_buffer_count + increase > MAX_LATENCY) ?
+			MAX_LATENCY : vb->min_tx_buffer_count + increase;
+	/* Because there are 2 buffers in the transmit FIFO on the
+	 * hardware, setting 3 ms of latency means that the host needs
+	 * to be able to service the cards within 1ms.  This is because
+	 * the interface will load up 2 buffers into the TX FIFO then
+	 * attempt to read the 3rd descriptor.  If the OWN bit isn't
+	 * set, then the hardware will set the TX descriptor not
+	 * available interrupt.
+	 */
+	/* Set the minimum latency in case we're restarted...we don't
+	 * want to wait for the buffer to grow to this depth again in
+	 * that case.
+	 */
+	increase = latency - vb->min_tx_buffer_count;
+	while (increase--) {
+		vbb = voicebus_alloc(vb);
+
+		if (unlikely(NULL == vbb))
+			BUG_ON(1);
+		else
+			vb->handle_transmit(vbb, vb->context);
+	}
+	voicebus_set_minlatency(vb, latency);
 }
 
 static void *vbb_stash[DLIST_SIZE];
@@ -1332,6 +1312,8 @@
 	void *vbb;
 	int buffer_count;
 	int i;
+	int idle_buffers = 0;
+	int softunderrun = 0;
 
 	int underrun = test_bit(TX_UNDERRUN, &vb->flags);
 
@@ -1344,8 +1326,17 @@
 		++buffer_count;
 	}
 
-	if (unlikely(vb_check_softunderrun(vb)))
-		__vb_increase_latency(vb, vb_recover_tx_descriptor_list(vb) + buffer_count);
+	/* NOTE: Do not print anything to the console from the time you've
+	 * detected a soft underrun until the transmit descriptors are fixed up
+	 * again. Otherwise the hardware could advance past where you set the
+	 * head and tail pointers and then eventually run into the desciptor
+	 * that it was currently working on when the softunderrun condition was
+	 * first hit. */
+	if (unlikely(vb_check_softunderrun(vb))) {
+		softunderrun = 1;
+		idle_buffers = vb_recover_tx_descriptor_list(vb);
+		__vb_increase_latency(vb, idle_buffers + buffer_count);
+	}
 
 	for (i = 0; i < buffer_count; ++i) {
 		/* After the upper layer is done with the completed buffer, it
@@ -1358,10 +1349,20 @@
 	 * drain the transmit descriptor ring which means that interrupts were
 	 * locked for DLIST_SIZE ms. */
 	if (unlikely(underrun)) {
-		HERE();
+		if (printk_ratelimit())
+			HERE();
 		vb_rx_demand_poll(vb);
 		vb_tx_demand_poll(vb);
 		clear_bit(TX_UNDERRUN, &vb->flags);
+	}
+
+	/* Print any messages about soft latency bumps after we restuff the
+	 * transmit buffer...otherwise it's possible to take so much time
+	 * printing the dmesg output that we lost the lead that we got on the
+	 * hardware, resulting in a hard underrun condition. */
+	if (unlikely(softunderrun)) {
+		dev_info(&vb->pdev->dev, "Sent %d idle buffers. Latency set to %d ms in order to compensate.\n",
+			idle_buffers, vb->min_tx_buffer_count);
 	}
 
 	while ((vbb = vb_get_completed_rxb(vb))) {




More information about the svn-commits mailing list