[svn-commits] sruffell: linux/trunk r8431 - in /linux/trunk/drivers/dahdi: voicebus/ wctdm2...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Mar 25 11:23:57 CDT 2010


Author: sruffell
Date: Thu Mar 25 11:23:53 2010
New Revision: 8431

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8431
Log:
wctdm24xxp: Add an 'hx8' mode for buffer processing.

The Hx8 series cards do not need any idle buffers and idle_buffers complicate
processing when using the timing_cable.  This change adds another mode of
operation for the voicebus layer for the Hx8 cards that operates without the
idle buffers.

Modified:
    linux/trunk/drivers/dahdi/voicebus/voicebus.c
    linux/trunk/drivers/dahdi/voicebus/voicebus.h
    linux/trunk/drivers/dahdi/wctdm24xxp/base.c

Modified: linux/trunk/drivers/dahdi/voicebus/voicebus.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/voicebus.c?view=diff&rev=8431&r1=8430&r2=8431
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.c Thu Mar 25 11:23:53 2010
@@ -352,15 +352,15 @@
 					 VOICEBUS_SFRAME_SIZE, DMA_TO_DEVICE);
 			kmem_cache_free(voicebus_vbb_cache, dl->pending[i]);
 		}
-		if (!test_bit(VOICEBUS_NORMAL_MODE, &vb->flags)) {
-			d->buffer1 = 0;
-			dl->pending[i] = NULL;
-			d->des0 &= ~OWN_BIT;
-		} else {
+		if (NORMAL == vb->mode) {
 			d->des1 |= 0x80000000;
 			d->buffer1 = vb->idle_vbb_dma_addr;
 			dl->pending[i] = vb->idle_vbb;
 			SET_OWNED(d);
+		} else {
+			d->buffer1 = 0;
+			dl->pending[i] = NULL;
+			d->des0 &= ~OWN_BIT;
 		}
 	}
 
@@ -667,7 +667,7 @@
 	}
 	tasklet_enable(&vb->tasklet);
 
-	if (test_bit(VOICEBUS_NORMAL_MODE, &vb->flags)) {
+	if (BOOT != vb->mode) {
 		for (i = 0; i < vb->min_tx_buffer_count; ++i) {
 			vbb = kmem_cache_alloc(voicebus_vbb_cache, GFP_KERNEL);
 			if (unlikely(NULL == vbb))
@@ -679,8 +679,11 @@
 		handle_transmit(vb, &buffers);
 
 		tasklet_disable(&vb->tasklet);
-		list_for_each_entry(vbb, &buffers, entry)
+		while (!list_empty(&buffers)) {
+			vbb = list_entry(buffers.next, struct vbb, entry);
+			list_del_init(&vbb->entry);
 			voicebus_transmit(vb, vbb);
+		}
 		tasklet_enable(&vb->tasklet);
 	}
 
@@ -791,7 +794,7 @@
 			 sizeof(vbb->data), DMA_TO_DEVICE);
 
 	vbb = dl->pending[head];
-	if (test_bit(VOICEBUS_NORMAL_MODE, &vb->flags)) {
+	if (NORMAL == vb->mode) {
 		d->buffer1 = vb->idle_vbb_dma_addr;
 		dl->pending[head] = vb->idle_vbb;
 		SET_OWNED(d);
@@ -845,10 +848,10 @@
 static void
 __vb_enable_interrupts(struct voicebus *vb)
 {
-	if (test_bit(VOICEBUS_NORMAL_MODE, &vb->flags))
+	if (BOOT == vb->mode)
+		__vb_setctl(vb, IER_CSR7, DEFAULT_NO_IDLE_INTERRUPTS);
+	else
 		__vb_setctl(vb, IER_CSR7, DEFAULT_NORMAL_INTERRUPTS);
-	else
-		__vb_setctl(vb, IER_CSR7, DEFAULT_NO_IDLE_INTERRUPTS);
 }
 
 static void
@@ -890,8 +893,9 @@
 	spin_unlock_bh(&vb->lock);
 }
 
-static void vb_tasklet_relaxed(unsigned long data);
-static void vb_tasklet(unsigned long data);
+static void vb_tasklet_boot(unsigned long data);
+static void vb_tasklet_hx8(unsigned long data);
+static void vb_tasklet_normal(unsigned long data);
 
 /*!
  * \brief Starts the VoiceBus interface.
@@ -913,10 +917,18 @@
 	if (!vb_is_stopped(vb))
 		return -EBUSY;
 
-	if (test_bit(VOICEBUS_NORMAL_MODE, &vb->flags))
-		tasklet_init(&vb->tasklet, vb_tasklet, (unsigned long)vb);
-	else
-		tasklet_init(&vb->tasklet, vb_tasklet_relaxed, (unsigned long)vb);
+	if (NORMAL == vb->mode) {
+		tasklet_init(&vb->tasklet, vb_tasklet_normal,
+			     (unsigned long)vb);
+	} else if (BOOT == vb->mode) {
+		tasklet_init(&vb->tasklet, vb_tasklet_boot,
+			     (unsigned long)vb);
+	} else if (HX8 == vb->mode) {
+		tasklet_init(&vb->tasklet, vb_tasklet_hx8,
+			     (unsigned long)vb);
+	} else {
+		return -EINVAL;
+	}
 
 	ret = vb_reset_interface(vb);
 	if (ret)
@@ -1091,10 +1103,13 @@
 }
 
 /**
- * vb_tasklet_relaxed() - Service the rings without strict timing requierments.
- *
- */
-static void vb_tasklet_relaxed(unsigned long data)
+ * vb_tasklet_boot() - When vb->mode == BOOT
+ *
+ * This deferred processing routine is for hx8 boards during initialization.  It
+ * simply services any completed tx / rx packets without any concerns about what
+ * the current latency is.
+ */
+static void vb_tasklet_boot(unsigned long data)
 {
 	struct voicebus *vb = (struct voicebus *)data;
 	LIST_HEAD(buffers);
@@ -1153,19 +1168,25 @@
 	return;
 }
 
-static void vb_tasklet(unsigned long data)
+/**
+ * vb_tasklet_hx8() - When vb->mode == HX8
+ *
+ * The normal deferred processing routine for the Hx8 boards.  This deferred
+ * processing routine doesn't configure any idle buffers and increases the
+ * latency when there is a hard underrun.  There are not any softunderruns here,
+ * unlike in vb_tasklet_normal.
+ */
+static void vb_tasklet_hx8(unsigned long data)
 {
 	struct voicebus *vb = (struct voicebus *)data;
-	int softunderrun;
+	int hardunderrun;
 	LIST_HEAD(buffers);
 	struct vbb *vbb;
-	struct voicebus_descriptor_list *const dl = &vb->txd;
-	struct voicebus_descriptor *d;
-	int behind = 0;
 	const int DEFAULT_COUNT = 5;
 	int count = DEFAULT_COUNT;
 	u32 des0 = 0;
 
+	hardunderrun = test_and_clear_bit(VOICEBUS_HARD_UNDERRUN, &vb->flags);
 	/* First, temporarily store any non-idle buffers that the hardware has
 	 * indicated it's finished transmitting.  Non idle buffers are those
 	 * buffers that contain actual data and was filled out by the client
@@ -1178,6 +1199,104 @@
 	while ((vbb = vb_get_completed_txb(vb)))
 		list_add_tail(&vbb->entry, &vb->tx_complete);
 
+	while (--count && !list_empty(&vb->tx_complete))
+		list_move_tail(vb->tx_complete.next, &buffers);
+
+	/* Prep all the new buffers for transmit before actually sending any
+	 * of them. */
+	handle_transmit(vb, &buffers);
+
+	if (unlikely(hardunderrun))
+		vb_increase_latency(vb, 1, &buffers);
+
+	/* Now we can send all our buffers together in a group. */
+	while (!list_empty(&buffers)) {
+		vbb = list_entry(buffers.next, struct vbb, entry);
+		list_del(&vbb->entry);
+		voicebus_transmit(vb, vbb);
+	}
+
+	/* Print any messages about soft latency bumps after we fix the transmit
+	 * descriptor ring. Otherwise it's possible to take so much time
+	 * printing the dmesg output that we lose the lead that we got on the
+	 * hardware, resulting in a hard underrun condition. */
+	if (unlikely(hardunderrun)) {
+#if !defined(CONFIG_VOICEBUS_SYSFS)
+		if (!test_bit(VOICEBUS_LATENCY_LOCKED, &vb->flags) &&
+		    printk_ratelimit()) {
+			if (vb->max_latency != vb->min_tx_buffer_count) {
+				dev_info(&vb->pdev->dev, "Missed interrupt. "
+					 "Increasing latency to %d ms in "
+					 "order to compensate.\n",
+					 vb->min_tx_buffer_count);
+			} else {
+				dev_info(&vb->pdev->dev, "ERROR: Unable to "
+					 "service card within %d ms and "
+					 "unable to further increase "
+					 "latency.\n", vb->max_latency);
+			}
+		}
+#endif
+	}
+
+	/* If there may still be buffers in the descriptor rings, reschedule
+	 * ourself to run again.  We essentially yield here to allow any other
+	 * cards a chance to run. */
+	if (unlikely(!count && !test_bit(VOICEBUS_STOP, &vb->flags)))
+		tasklet_hi_schedule(&vb->tasklet);
+
+	/* And finally, pass up any receive buffers. */
+	count = DEFAULT_COUNT;
+	while (--count && (vbb = vb_get_completed_rxb(vb, &des0))) {
+		if (((des0 >> 16) & 0x7fff) == VOICEBUS_SFRAME_SIZE)
+			list_add_tail(&vbb->entry, &buffers);
+		else
+			vb_submit_rxb(vb, vbb);
+	}
+
+	handle_receive(vb, &buffers);
+
+	while (!list_empty(&buffers)) {
+		vbb = list_entry(buffers.next, struct vbb, entry);
+		list_del(&vbb->entry);
+		vb_submit_rxb(vb, vbb);
+	}
+
+	return;
+}
+
+/**
+ * vb_tasklet_relaxed() - When vb->mode == NORMAL
+ *
+ * This is the standard deferred processing routine for CPLD based cards
+ * (essentially the non-hx8 cards).
+ */
+static void vb_tasklet_normal(unsigned long data)
+{
+	struct voicebus *vb = (struct voicebus *)data;
+	int softunderrun;
+	LIST_HEAD(buffers);
+	struct vbb *vbb;
+	struct voicebus_descriptor_list *const dl = &vb->txd;
+	struct voicebus_descriptor *d;
+	int behind = 0;
+	const int DEFAULT_COUNT = 5;
+	int count = DEFAULT_COUNT;
+	u32 des0 = 0;
+
+	WARN_ON_ONCE(NORMAL != vb->mode);
+	/* First, temporarily store any non-idle buffers that the hardware has
+	 * indicated it's finished transmitting.  Non idle buffers are those
+	 * buffers that contain actual data and was filled out by the client
+	 * driver (as of this writing, the wcte12xp or wctdm24xxp drivers) when
+	 * passed up through the handle_transmit callback.
+	 *
+	 * On the other hand, idle buffers are "dummy" buffers that solely exist
+	 * to in order to prevent the transmit descriptor ring from ever
+	 * completely draining. */
+	while ((vbb = vb_get_completed_txb(vb)))
+		list_add_tail(&vbb->entry, &vb->tx_complete);
+
 	if (unlikely(atomic_read(&dl->count) < 2)) {
 		softunderrun = 1;
 		d = vb_descriptor(dl, dl->head);
@@ -1193,7 +1312,9 @@
 				goto tx_error_exit;
 
 			vbb = vb_get_completed_txb(vb);
-			list_add_tail(&vbb->entry, &vb->tx_complete);
+			WARN_ON(!vbb);
+			if (vbb)
+				list_add_tail(&vbb->entry, &vb->tx_complete);
 			behind = 1;
 		} else  {
 			behind = 2;
@@ -1380,10 +1501,16 @@
 	if (unlikely((int_status &
 	    (TX_UNAVAILABLE_INTERRUPT|RX_UNAVAILABLE_INTERRUPT)) &&
 	    !test_bit(VOICEBUS_STOP, &vb->flags) &&
-	    test_bit(VOICEBUS_NORMAL_MODE, &vb->flags))) {
-		__vb_disable_interrupts(vb);
-		__vb_setctl(vb, SR_CSR5, int_status);
-		schedule_work(&vb->underrun_work);
+	    (BOOT != vb->mode))) {
+		if (NORMAL == vb->mode) {
+			__vb_disable_interrupts(vb);
+			__vb_setctl(vb, SR_CSR5, int_status);
+			schedule_work(&vb->underrun_work);
+		} else if (HX8 == vb->mode) {
+			set_bit(VOICEBUS_HARD_UNDERRUN, &vb->flags);
+			tasklet_hi_schedule(&vb->tasklet);
+			__vb_setctl(vb, SR_CSR5, int_status);
+		}
 	} else if (likely(int_status &
 		   (TX_COMPLETE_INTERRUPT|RX_COMPLETE_INTERRUPT))) {
 		/* ******************************************************** */
@@ -1443,7 +1570,8 @@
  * \todo Complete this description.
  */
 int
-__voicebus_init(struct voicebus *vb, const char *board_name, int normal_mode)
+__voicebus_init(struct voicebus *vb, const char *board_name,
+		enum voicebus_mode mode)
 {
 	int retval = 0;
 
@@ -1461,10 +1589,10 @@
 	spin_lock_init(&vb->lock);
 	set_bit(VOICEBUS_STOP, &vb->flags);
 
-	if (normal_mode)
-		set_bit(VOICEBUS_NORMAL_MODE, &vb->flags);
-	else
-		clear_bit(VOICEBUS_NORMAL_MODE, &vb->flags);
+	if ((NORMAL != mode) && (BOOT != mode) && (HX8 != mode))
+		return -EINVAL;
+
+	vb->mode = mode;
 
 	vb->min_tx_buffer_count = VOICEBUS_DEFAULT_LATENCY;
 

Modified: linux/trunk/drivers/dahdi/voicebus/voicebus.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/voicebus.h?view=diff&rev=8431&r1=8430&r2=8431
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.h (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.h Thu Mar 25 11:23:53 2010
@@ -89,8 +89,21 @@
 #define VOICEBUS_STOP				1
 #define VOICEBUS_STOPPED			2
 #define VOICEBUS_LATENCY_LOCKED			3
-#define VOICEBUS_NORMAL_MODE			4
-#define VOICEBUS_USERMODE			5
+#define VOICEBUS_HARD_UNDERRUN			4
+
+/**
+ * voicebus_mode
+ *
+ * NORMAL:	For non-hx8 boards.  Uses idle_buffers.
+ * BOOT:	For hx8 boards.  For sending single packets at a time.
+ * RELAXED:	Normal operating mode for Hx8 Boards.  Does not use
+ *		idle_buffers.
+ */
+enum voicebus_mode {
+	NORMAL = 0,
+	BOOT = 1,
+	HX8 = 2,
+};
 
 /**
  * struct voicebus - Represents physical interface to voicebus card.
@@ -108,6 +121,7 @@
 	const int		*debug;
 	void __iomem 		*iobase;
 	struct tasklet_struct 	tasklet;
+	enum voicebus_mode	mode;
 
 #if defined(CONFIG_VOICEBUS_TIMER)
 	struct timer_list	timer;
@@ -140,7 +154,7 @@
 #endif
 
 int __voicebus_init(struct voicebus *vb, const char *board_name,
-		    int normal_mode);
+		    enum voicebus_mode mode);
 void voicebus_release(struct voicebus *vb);
 int voicebus_start(struct voicebus *vb);
 void voicebus_stop(struct voicebus *vb);
@@ -150,13 +164,13 @@
 
 static inline int voicebus_init(struct voicebus *vb, const char *board_name)
 {
-	return __voicebus_init(vb, board_name, 1);
+	return __voicebus_init(vb, board_name, NORMAL);
 }
 
 static inline int
-voicebus_no_idle_init(struct voicebus *vb, const char *board_name)
-{
-	return __voicebus_init(vb, board_name, 0);
+voicebus_boot_init(struct voicebus *vb, const char *board_name)
+{
+	return __voicebus_init(vb, board_name, BOOT);
 }
 
 /**
@@ -188,7 +202,12 @@
 
 static inline void voicebus_set_normal_mode(struct voicebus *vb)
 {
-	set_bit(VOICEBUS_NORMAL_MODE, &vb->flags);
+	vb->mode = NORMAL;
+}
+
+static inline void voicebus_set_hx8_mode(struct voicebus *vb)
+{
+	vb->mode = HX8;
 }
 
 /**

Modified: linux/trunk/drivers/dahdi/wctdm24xxp/base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/wctdm24xxp/base.c?view=diff&rev=8431&r1=8430&r2=8431
==============================================================================
--- linux/trunk/drivers/dahdi/wctdm24xxp/base.c (original)
+++ linux/trunk/drivers/dahdi/wctdm24xxp/base.c Thu Mar 25 11:23:53 2010
@@ -4668,7 +4668,7 @@
 
 	if (is_hx8(wc)) {
 		wc->vb.ops = &hx8_voicebus_operations;
-		ret = voicebus_no_idle_init(&wc->vb, wc->board_name);
+		ret = voicebus_boot_init(&wc->vb, wc->board_name);
 	} else {
 		wc->vb.ops = &voicebus_operations;
 		ret = voicebus_init(&wc->vb, wc->board_name);
@@ -4716,12 +4716,12 @@
 			return -EIO;
 		}
 
-		/* Switch back to the normal mode of operation */
+		/* Switch to the normal operating mode for this card. */
 		voicebus_stop(&wc->vb);
 		wc->vb.ops = &voicebus_operations;
 		voicebus_set_minlatency(&wc->vb, latency);
 		voicebus_set_maxlatency(&wc->vb, max_latency);
-		voicebus_set_normal_mode(&wc->vb);
+		voicebus_set_hx8_mode(&wc->vb);
 		if (voicebus_start(&wc->vb))
 			BUG_ON(1);
 	}




More information about the svn-commits mailing list