[svn-commits] sruffell: linux/trunk r8095 - in /linux/trunk/drivers/dahdi: voicebus/ vpmadt...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Feb 25 11:34:02 CST 2010


Author: sruffell
Date: Thu Feb 25 11:33:58 2010
New Revision: 8095

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8095
Log:
wctdm24xxp, wcte12xp: Buffer handling improvements.

This patch moves the majority of the buffer processing for the voicebus based
cards out of the interrupt handler and into a tasklet.  When multiple cards are
running on the same CPU, and there was a latency condition that would cause them
to get behind, this now allows the tasklet to limit how many buffers are
processed on each card before giving the other card a chance to start working on
it's backlog.

Additionally, when the card detects a hard under run, instead of trying to fix
it up in the handling routine, it will now reschedule a work item that will
completely reset the descriptor rings.

Modified:
    linux/trunk/drivers/dahdi/voicebus/GpakCust.c
    linux/trunk/drivers/dahdi/voicebus/voicebus.c
    linux/trunk/drivers/dahdi/voicebus/voicebus.h
    linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c
    linux/trunk/drivers/dahdi/wctdm24xxp/base.c
    linux/trunk/drivers/dahdi/wcte12xp/base.c

Modified: linux/trunk/drivers/dahdi/voicebus/GpakCust.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/voicebus/GpakCust.c?view=diff&rev=8095&r1=8094&r2=8095
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/GpakCust.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/GpakCust.c Thu Feb 25 11:33:58 2010
@@ -751,7 +751,8 @@
 
 	vpmadt032_io_wait(vpm);
 	if ( NumWords < VPM150M_MAX_COMMANDS ) {
-		struct vpmadt032_cmd *cmds[VPM150M_MAX_COMMANDS] = {NULL};
+		struct vpmadt032_cmd *cmds[VPM150M_MAX_COMMANDS];
+		memset(cmds, 0, sizeof(cmds));
 		vpmadt032_setpage(vpm, DspAddress >> 16);
 		DspAddress &= 0xffff;
 		for (i=0; i < NumWords; ++i) {

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=8095&r1=8094&r2=8095
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.c Thu Feb 25 11:33:58 2010
@@ -35,17 +35,12 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 
 #include <dahdi/kernel.h>
 #include "voicebus.h"
 #include "vpmadtreg.h"
 #include "GpakCust.h"
-
-#if VOICEBUS_DEFERRED == WORKQUEUE
-#define VOICEBUS_ALLOC_FLAGS GFP_KERNEL
-#else
-#define VOICEBUS_ALLOC_FLAGS GFP_ATOMIC
-#endif
 
 #if VOICEBUS_DEFERRED == TIMER
 #if HZ < 1000
@@ -109,9 +104,16 @@
 	volatile __le32 container; /* Unused */
 } __attribute__((packed));
 
-static inline void handle_transmit(struct voicebus *vb, void *vbb)
-{
-	vb->ops->handle_transmit(vb, vbb);
+static inline void
+handle_transmit(struct voicebus *vb, struct list_head *buffers)
+{
+	vb->ops->handle_transmit(vb, buffers);
+}
+
+static inline void
+handle_receive(struct voicebus *vb, struct list_head *buffers)
+{
+	vb->ops->handle_receive(vb, buffers);
 }
 
 /*
@@ -132,7 +134,7 @@
 #define VBLOCK_FROM_DEFERRED(_vb_) 	spin_lock(&((_vb_)->lock))
 #define VBUNLOCK_FROM_DEFERRED(_vb_)	spin_lock(&((_vb_)->lock))
 #else
-#define LOCKS_VOICEBUS			unsigned long _irqflags
+#define LOCKS_VOICEBUS			unsigned long _irqflags;
 #define LOCKS_FROM_DEFERRED
 #define VBLOCK(_vb_) 			spin_lock_irqsave(&((_vb_)->lock), _irqflags)
 #define VBUNLOCK(_vb_)			spin_unlock_irqrestore(&((_vb_)->lock), _irqflags)
@@ -145,35 +147,6 @@
 #define STOP				2
 #define STOPPED				3
 #define LATENCY_LOCKED			4
-
-#if VOICEBUS_DEFERRED == WORKQUEUE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-/*! \brief Make the current task real-time. */
-static void
-vb_setup_deferred(void *data)
-#else
-static void
-vb_setup_deferred(struct work_struct *work)
-#endif
-{
-	struct sched_param param = { .sched_priority = 99 };
-	sched_setscheduler(current, SCHED_FIFO, &param);
-}
-/*! \brief Schedule a work item to make the voicebus workqueue real-time. */
-static void
-vb_set_workqueue_priority(struct voicebus *vb)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-	DECLARE_WORK(deferred_setup, vb_setup_deferred, NULL);
-#else
-	DECLARE_WORK(deferred_setup, vb_setup_deferred);
-#endif
-	queue_work(vb->workqueue, &deferred_setup);
-	flush_workqueue(vb->workqueue);
-}
-#endif
-#endif
 
 static inline struct voicebus_descriptor *
 vb_descriptor(const struct voicebus_descriptor_list *dl,
@@ -297,7 +270,7 @@
 int
 voicebus_set_minlatency(struct voicebus *vb, unsigned int ms)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	/*
 	 * One millisecond of latency means that we have 3 buffers pending,
 	 * since two are always going to be waiting in the TX fifo on the
@@ -323,7 +296,7 @@
 int
 voicebus_current_latency(struct voicebus *vb)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	int latency;
 	VBLOCK(vb);
 	latency = vb->min_tx_buffer_count;
@@ -368,7 +341,10 @@
 static inline u32
 __vb_getctl(struct voicebus *vb, u32 addr)
 {
-	return le32_to_cpu(inl(vb->iobase + addr));
+	u32 ret;
+	ret = inl(vb->iobase + addr);
+	rmb();
+	return ret;
 }
 
 /*!
@@ -377,7 +353,7 @@
 static inline u32
 vb_getctl(struct voicebus *vb, u32 addr)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	u32 val;
 	VBLOCK(vb);
 	val = __vb_getctl(vb, addr);
@@ -385,6 +361,14 @@
 	return val;
 }
 
+static int
+__vb_is_stopped(struct voicebus *vb)
+{
+	u32 reg;
+	reg = __vb_getctl(vb, SR_CSR5);
+	reg = (reg >> 17) & 0x3f;
+	return (0 == reg) ? 1 : 0;
+}
 /*!
  * \brief Returns whether or not the interface is running.
  *
@@ -396,10 +380,12 @@
 static int
 vb_is_stopped(struct voicebus *vb)
 {
-	u32 reg;
-	reg = vb_getctl(vb, SR_CSR5);
-	reg = (reg >> 17) & 0x38;
-	return (0 == reg) ? 1 : 0;
+	LOCKS_VOICEBUS
+	int ret;
+	VBLOCK(vb);
+	ret = __vb_is_stopped(vb);
+	VBUNLOCK(vb);
+	return ret;
 }
 
 static void
@@ -408,9 +394,11 @@
 	unsigned int i;
 	struct voicebus_descriptor_list *dl = &vb->txd;
 	struct voicebus_descriptor *d;
-
-	BUG_ON(!vb_is_stopped(vb));
-
+	unsigned long flags;
+
+	WARN_ON(!vb_is_stopped(vb));
+
+	spin_lock_irqsave(&vb->lock, flags);
 	for (i = 0; i < DRING_SIZE; ++i) {
 		d = vb_descriptor(dl, i);
 		if (d->buffer1 && (d->buffer1 != vb->idle_vbb_dma_addr)) {
@@ -419,13 +407,16 @@
 					 VOICEBUS_SFRAME_SIZE, DMA_TO_DEVICE);
 			voicebus_free(vb, dl->pending[i]);
 		}
+		d->des1 |= 0x80000000;
 		d->buffer1 = vb->idle_vbb_dma_addr;
 		dl->pending[i] = vb->idle_vbb;
 		SET_OWNED(d);
 	}
+
 	/* Send out two idle buffers to start because sometimes the first buffer
 	 * doesn't make it back to us. */
 	dl->head = dl->tail = 2;
+	spin_unlock_irqrestore(&vb->lock, flags);
 	atomic_set(&dl->count, 0);
 }
 
@@ -435,9 +426,11 @@
 	unsigned int i;
 	struct voicebus_descriptor_list *dl = &vb->rxd;
 	struct voicebus_descriptor *d;
+	unsigned long flags;
 
 	BUG_ON(!vb_is_stopped(vb));
 
+	spin_lock_irqsave(&vb->lock, flags);
 	for (i = 0; i < DRING_SIZE; ++i) {
 		d = vb_descriptor(dl, i);
 		if (d->buffer1) {
@@ -445,7 +438,7 @@
 					 VOICEBUS_SFRAME_SIZE, DMA_FROM_DEVICE);
 			d->buffer1 = 0;
 			BUG_ON(!dl->pending[i]);
-			voicebus_free(vb, dl->pending[i]);
+			kmem_cache_free(buffer_cache, dl->pending[i]);
 			dl->pending[i] = NULL;
 		}
 		d->des0 &= ~OWN_BIT;
@@ -453,6 +446,7 @@
 	dl->head = 0;
 	dl->tail = 0;
 	atomic_set(&dl->count, 0);
+	spin_unlock_irqrestore(&vb->lock, flags);
 }
 
 static void vb_cleanup_descriptors(struct voicebus *vb,
@@ -485,7 +479,7 @@
 __vb_setctl(struct voicebus *vb, u32 addr, u32 val)
 {
 	wmb();
-	outl(cpu_to_le32(val), vb->iobase + addr);
+	outl(val, vb->iobase + addr);
 }
 
 /*!
@@ -494,7 +488,7 @@
 static inline void
 vb_setctl(struct voicebus *vb, u32 addr, u32 val)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	VBLOCK(vb);
 	__vb_setctl(vb, addr, val);
 	VBUNLOCK(vb);
@@ -531,7 +525,7 @@
 static void
 vb_setsdi(struct voicebus *vb, int addr, u16 val)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	u32 bits;
 	u32 sdi = 0;
 	/* Send preamble */
@@ -547,7 +541,7 @@
 static void
 vb_enable_io_access(struct voicebus *vb)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	u32 reg;
 	BUG_ON(!vb->pdev);
 	VBLOCK(vb);
@@ -555,17 +549,6 @@
 	reg |= 0x00000007;
 	pci_write_config_dword(vb->pdev, 0x0004, reg);
 	VBUNLOCK(vb);
-}
-
-/*! \todo Insert comments...
- * context: !in_interrupt()
- */
-void*
-voicebus_alloc(struct voicebus *vb)
-{
-	void *vbb;
-	vbb = kmem_cache_alloc(buffer_cache, VOICEBUS_ALLOC_FLAGS);
-	return vbb;
 }
 
 /*! \brief Resets the voicebus hardware interface. */
@@ -632,7 +615,7 @@
  *
  */
 static inline int
-vb_submit_rxb(struct voicebus *vb, void *vbb)
+vb_submit_rxb(struct voicebus *vb, struct vbb *vbb)
 {
 	struct voicebus_descriptor *d;
 	struct voicebus_descriptor_list *dl = &vb->rxd;
@@ -649,8 +632,8 @@
 
 	dl->pending[tail] = vbb;
 	dl->tail = (++tail) & DRING_MASK;
-	d->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
-				    VOICEBUS_SFRAME_SIZE, DMA_FROM_DEVICE);
+	d->buffer1 = dma_map_single(&vb->pdev->dev, vbb->data,
+				    sizeof(vbb->data), DMA_FROM_DEVICE);
 	SET_OWNED(d); /* That's it until the hardware is done with it. */
 	atomic_inc(&dl->count);
 	return 0;
@@ -659,7 +642,11 @@
 static void setup_descriptors(struct voicebus *vb)
 {
 	int i;
-	void *vbb;
+	struct vbb *vbb;
+	LIST_HEAD(buffers);
+	unsigned long flags;
+
+	might_sleep();
 
 	vb_cleanup_tx_descriptors(vb);
 	vb_cleanup_rx_descriptors(vb);
@@ -669,47 +656,71 @@
 	vb_setctl(vb, 0x0018, (u32)vb->rxd.desc_dma);
 
 	for (i = 0; i < DRING_SIZE; ++i) {
-		vbb = voicebus_alloc(vb);
-		if (unlikely(NULL == vbb)) {
+		vbb = kmem_cache_alloc(buffer_cache, GFP_KERNEL);
+		if (unlikely(NULL == vbb))
 			BUG_ON(1);
-			/* \todo I need to make sure the driver can recover
-			 * from this condition. .... */
-		} else {
-			vb_submit_rxb(vb, vbb);
-		}
-	}
+		list_add_tail(&vbb->entry, &buffers);
+	}
+
+	spin_lock_irqsave(&vb->lock, flags);
+	list_for_each_entry(vbb, &buffers, entry)
+		vb_submit_rxb(vb, vbb);
+	spin_unlock_irqrestore(&vb->lock, flags);
+
+	INIT_LIST_HEAD(&buffers);
 
 	for (i = 0; i < vb->min_tx_buffer_count; ++i) {
-		vbb = voicebus_alloc(vb);
-
+		vbb = kmem_cache_alloc(buffer_cache, GFP_KERNEL);
 		if (unlikely(NULL == vbb))
 			BUG_ON(1);
 		else
-			handle_transmit(vb, vbb);
-	}
-}
-
-static int
-vb_initialize_interface(struct voicebus *vb)
-{
-	u32 reg;
-
-	setup_descriptors(vb);
-
+			list_add_tail(&vbb->entry, &buffers);
+	}
+
+	tasklet_disable(&vb->tasklet);
+	handle_transmit(vb, &buffers);
+	tasklet_enable(&vb->tasklet);
+
+	spin_lock_irqsave(&vb->lock, flags);
+	list_for_each_entry(vbb, &buffers, entry)
+		voicebus_transmit(vb, vbb);
+	spin_unlock_irqrestore(&vb->lock, flags);
+}
+
+static void
+__vb_set_control_defaults(struct voicebus *vb)
+{
 	/* Pass bad packets, runt packets, disable SQE function,
 	 * store-and-forward */
 	vb_setctl(vb, 0x0030, 0x00280048);
 	/* ...disable jabber and the receive watchdog. */
 	vb_setctl(vb, 0x0078, 0x00000013);
+	vb_getctl(vb, 0x0078);
+}
+
+static void __vb_set_mac_only_mode(struct voicebus *vb)
+{
+	u32 reg;
+	reg = __vb_getctl(vb, 0x00fc);
+	__vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x4);
+	__vb_getctl(vb, 0x00fc);
+}
+
+static int
+vb_initialize_interface(struct voicebus *vb)
+{
+	u32 reg;
+
+	setup_descriptors(vb);
+
+	__vb_set_control_defaults(vb);
 
 	reg = vb_getctl(vb, 0x00fc);
 	vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x7);
 	vb_setsdi(vb, 0x00, 0x0100);
 	vb_setsdi(vb, 0x16, 0x2100);
 
-	reg = vb_getctl(vb, 0x00fc);
-
-	vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x4);
+	__vb_set_mac_only_mode(vb);
 	vb_setsdi(vb, 0x00, 0x0100);
 	vb_setsdi(vb, 0x16, 0x2100);
 	reg = vb_getctl(vb, 0x00fc);
@@ -735,7 +746,7 @@
 }
 
 static void
-show_buffer(struct voicebus *vb, void *vbb)
+show_buffer(struct voicebus *vb, struct vbb *vbb)
 {
 	int x;
 	unsigned char *c;
@@ -755,7 +766,7 @@
  * voicebus_transmit - Queue a buffer on the hardware descriptor ring.
  *
  */
-int voicebus_transmit(struct voicebus *vb, void *vbb)
+int voicebus_transmit(struct voicebus *vb, struct vbb *vbb)
 {
 	struct voicebus_descriptor *d;
 	struct voicebus_descriptor_list *dl = &vb->txd;
@@ -766,13 +777,16 @@
 		if (printk_ratelimit())
 			dev_warn(&vb->pdev->dev, "Dropping tx buffer buffer\n");
 		voicebus_free(vb, vbb);
+		/* Schedule the underrun handler to run here, since we'll need
+		 * to cleanup as best we can. */
+		schedule_work(&vb->underrun_work);
 		return -EFAULT;
 	}
 
 	dl->pending[dl->tail] = vbb;
+	d->buffer1 = dma_map_single(&vb->pdev->dev, vbb->data,
+				    sizeof(vbb->data), DMA_TO_DEVICE);
 	dl->tail = (++(dl->tail)) & DRING_MASK;
-	d->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
-				    VOICEBUS_SFRAME_SIZE, DMA_TO_DEVICE);
 	SET_OWNED(d); /* That's it until the hardware is done with it. */
 	atomic_inc(&dl->count);
 	return 0;
@@ -792,12 +806,12 @@
  *
  * \return Pointer to buffer, or NULL if not available.
  */
-static inline void *
+static void *
 vb_get_completed_txb(struct voicebus *vb)
 {
 	struct voicebus_descriptor_list *dl = &vb->txd;
 	struct voicebus_descriptor *d;
-	void *vbb;
+	struct vbb *vbb;
 	unsigned int head = dl->head;
 
 	d = vb_descriptor(dl, head);
@@ -806,9 +820,10 @@
 		return NULL;
 
 	dma_unmap_single(&vb->pdev->dev, d->buffer1,
-			 VOICEBUS_SFRAME_SIZE, DMA_TO_DEVICE);
+			 sizeof(vbb->data), DMA_TO_DEVICE);
 
 	vbb = dl->pending[head];
+	dl->pending[head] = vb->idle_vbb;
 	dl->head = (++head) & DRING_MASK;
 	d->buffer1 = vb->idle_vbb_dma_addr;
 	SET_OWNED(d);
@@ -816,13 +831,13 @@
 	return vbb;
 }
 
-static inline void *
+static void *
 vb_get_completed_rxb(struct voicebus *vb)
 {
 	struct voicebus_descriptor *d;
 	struct voicebus_descriptor_list *dl = &vb->rxd;
 	unsigned int head = dl->head;
-	void *vbb;
+	struct vbb *vbb;
 
 	d = vb_descriptor(dl, head);
 
@@ -830,7 +845,7 @@
 		return NULL;
 
 	dma_unmap_single(&vb->pdev->dev, d->buffer1,
-			 VOICEBUS_SFRAME_SIZE, DMA_FROM_DEVICE);
+			 sizeof(vbb->data), DMA_FROM_DEVICE);
 	vbb = dl->pending[head];
 	dl->head = (++head) & DRING_MASK;
 	d->buffer1 = 0;
@@ -843,7 +858,7 @@
  *
  */
 void
-voicebus_free(struct voicebus *vb, void *vbb)
+voicebus_free(struct voicebus *vb, struct vbb *vbb)
 {
 	kmem_cache_free(buffer_cache, vbb);
 }
@@ -882,7 +897,7 @@
 static void
 vb_disable_interrupts(struct voicebus *vb)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	VBLOCK(vb);
 	__vb_disable_interrupts(vb);
 	VBUNLOCK(vb);
@@ -890,13 +905,13 @@
 
 static void start_packet_processing(struct voicebus *vb)
 {
-	LOCKS_VOICEBUS;
+	LOCKS_VOICEBUS
 	u32 reg;
 
 	VBLOCK(vb);
 	clear_bit(STOP, &vb->flags);
 	clear_bit(STOPPED, &vb->flags);
-#if VOICEBUS_DEFERRED == TIMER
+#if defined(CONFIG_VOICEBUS_TIMER)
 	vb->timer.expires = jiffies + HZ/1000;
 	add_timer(&vb->timer);
 #else
@@ -948,28 +963,22 @@
 }
 EXPORT_SYMBOL(voicebus_start);
 
-static void
-vb_clear_start_transmit_bit(struct voicebus *vb)
-{
-	LOCKS_VOICEBUS;
+static void vb_stop_txrx_processors(struct voicebus *vb)
+{
+	unsigned long flags;
 	u32 reg;
-	VBLOCK(vb);
+	int i;
+
+	spin_lock_irqsave(&vb->lock, flags);
 	reg = __vb_getctl(vb, NAR_CSR6);
-	reg &= ~0x00002000;
+	reg &= ~(0x2002);
 	__vb_setctl(vb, NAR_CSR6, reg);
-	VBUNLOCK(vb);
-}
-
-static void
-vb_clear_start_receive_bit(struct voicebus *vb)
-{
-	LOCKS_VOICEBUS;
-	u32 reg;
-	VBLOCK(vb);
-	reg = __vb_getctl(vb, NAR_CSR6);
-	reg &= ~0x00000002;
-	__vb_setctl(vb, NAR_CSR6, reg);
-	VBUNLOCK(vb);
+	spin_unlock_irqrestore(&vb->lock, flags);
+
+	barrier();
+	i = 500;
+	while (--i && (__vb_getctl(vb, SR_CSR5) & (0x007e0000)))
+		udelay(10);
 }
 
 /*!
@@ -990,23 +999,29 @@
 	if (vb_is_stopped(vb))
 		return 0;
 
-	INIT_COMPLETION(vb->stopped_completion);
 	set_bit(STOP, &vb->flags);
-	vb_clear_start_transmit_bit(vb);
-	vb_clear_start_receive_bit(vb);
-	if (wait_for_completion_timeout(&vb->stopped_completion, HZ)) {
-		BUG_ON(!vb_is_stopped(vb));
-	} else {
-		dev_warn(&vb->pdev->dev, "Timeout while waiting for board to "
-			 "stop.\n");
-
-		vb_clear_start_transmit_bit(vb);
-		vb_clear_start_receive_bit(vb);
-		set_bit(STOPPED, &vb->flags);
-		vb_disable_interrupts(vb);
-	}
-
-#if VOICEBUS_DEFERRED == TIMER
+	vb_stop_txrx_processors(vb);
+
+	if (!vb_is_stopped(vb)) {
+		vb_reset_interface(vb);
+		__vb_set_control_defaults(vb);
+		__vb_set_mac_only_mode(vb);
+		return 0;
+	}
+
+	if (__vb_getctl(vb, IER_CSR7) & 0x10000) {
+		INIT_COMPLETION(vb->stopped_completion);
+		if (wait_for_completion_timeout(&vb->stopped_completion, HZ)) {
+			BUG_ON(!vb_is_stopped(vb));
+		} else {
+			dev_warn(&vb->pdev->dev, "Timeout while waiting for "
+				 "board to stop.\n");
+		}
+	}
+
+	set_bit(STOPPED, &vb->flags);
+
+#if defined(CONFIG_VOICEBUS_TIMER)
 	del_timer_sync(&vb->timer);
 #endif
 
@@ -1036,13 +1051,11 @@
 	cancel_work_sync(&vb->underrun_work);
 #endif
 
-#if VOICEBUS_DEFERRED == WORKQUEUE
-	destroy_workqueue(vb->workqueue);
-#elif VOICEBUS_DEFERRED == TASKLET
+	vb_reset_interface(vb);
+
 	tasklet_kill(&vb->tasklet);
-#endif
-	vb_reset_interface(vb);
-#if VOICEBUS_DEFERRED != TIMER
+
+#if !defined(CONFIG_VOICEBUS_TIMER)
 	free_irq(vb->pdev->irq, vb);
 #endif
 
@@ -1059,10 +1072,12 @@
 EXPORT_SYMBOL(voicebus_release);
 
 static void
-vb_increase_latency(struct voicebus *vb, unsigned int increase)
-{
-	void *vbb;
+vb_increase_latency(struct voicebus *vb, unsigned int increase,
+		    struct list_head *buffers)
+{
+	struct vbb *vbb;
 	int i;
+	LIST_HEAD(local);
 
 	if (0 == increase)
 		return;
@@ -1086,17 +1101,23 @@
 	/* 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. */
 	for (i = 0; i < increase; ++i) {
-		vbb = voicebus_alloc(vb);
+		vbb = kmem_cache_alloc(buffer_cache, GFP_ATOMIC);
 		WARN_ON(NULL == vbb);
 		if (likely(NULL != vbb))
-			handle_transmit(vb, vbb);
-	}
+			list_add_tail(&vbb->entry, &local);
+	}
+
+	handle_transmit(vb, &local);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
+	list_for_each_entry(vbb, &local, entry)
+		list_move_tail(&vbb->entry, buffers);
+#else
+	list_splice_tail(&local, buffers);
+#endif
 
 	/* Set the new latency (but we want to ensure that there aren't any
 	 * printks to the console, so we don't call the function) */
-	spin_lock(&vb->lock);
 	vb->min_tx_buffer_count += increase;
-	spin_unlock(&vb->lock);
 }
 
 static void vb_set_all_owned(struct voicebus *vb,
@@ -1117,142 +1138,19 @@
 }
 
 /**
- * vb_reset_tx_owned() - Reset the OWN bits on descriptors from tail to head.
- *
- * When there is a softunderun, this function will cleanup what should be the
- * idle buffers that we do not expect to be in progress.
- *
- */
-static void vb_reset_tx_owned(struct voicebus *vb)
-{
-	struct voicebus_descriptor_list *dl = &vb->txd;
-	struct voicebus_descriptor *d;
-	unsigned int tail = dl->tail;
-
-	while (tail != dl->head) {
-		d = vb_descriptor(dl, tail);
-		SET_OWNED(d);
-		++tail;
-		tail &= DRING_MASK;
-	}
-}
-
-/**
- * __vb_get_default_behind_count() - Returns how many idle buffers are loaded in tx fifo.
- *
- * These buffers are going to be set, but the AN983 does not clear the owned
- * bit on the descriptors until they've actually been sent around.
- *
- * If you do not check for both the current and next descriptors, you could have
- * a condition where idle buffers are being sent around, but we don't detect
- * them because our current descriptor always points to a non-idle buffer.
- */
-static unsigned int __vb_get_default_behind_count(const struct voicebus *vb)
-{
-	const struct voicebus_descriptor_list *const dl = &vb->txd;
-	const struct voicebus_descriptor *current_descriptor;
-	const struct voicebus_descriptor *next_descriptor;
-
-	current_descriptor = vb_descriptor(dl, dl->head);
-	if (current_descriptor->buffer1 == vb->idle_vbb_dma_addr)
-		return 2;
-
-	next_descriptor = vb_descriptor(dl, ((dl->head + 1) & DRING_MASK));
-	if (next_descriptor->buffer1 == vb->idle_vbb_dma_addr)
-		return 1;
-
-	return 0;
-}
-
-/**
- * vb_check_softunderrun() - Return true if the TX FIFO has underrun valid data.
- *
- * Returns true if we're processing the idle buffers, which means that the host
- * was not able to keep up with the hardware.  This differs from a normal
- * underrun in that the interface chip on the board still has descriptors to
- * transmit (just in this case, they are the idle buffers).
- *
- */
-static inline int vb_is_softunderrun(const struct voicebus *vb)
-{
-	return __vb_get_default_behind_count(vb) > 0;
-}
-
-/**
- * vb_recover_tx_descriptor_list() - Recovers descriptor list
- *
- * Returns the number of descriptors that we're behind.
- *
- * Called if the [head | head + 1] pointer points to one of the idle buffers.
- * This means that the host computer has failed to keep far enough ahead of the
- * voicebus card.  This function acks the completed idle descriptors and gets
- * everything setup for normal operation again.
- *
- */
-static unsigned int vb_recover_tx_descriptor_list(struct voicebus *vb)
-{
+ * vb_deferred() - Manage the transmit and receive descriptor rings.
+ *
+ */
+static void vb_deferred(struct voicebus *vb)
+{
+	int softunderrun;
+	LIST_HEAD(buffers);
+	struct vbb *vbb;
 	struct voicebus_descriptor_list *const dl = &vb->txd;
 	struct voicebus_descriptor *d;
-	struct vbb *vbb = NULL;
-	unsigned int behind = __vb_get_default_behind_count(vb);
-	WARN_ON(0 == behind);
-
-	d = vb_descriptor(dl, dl->head);
-
-	/* If we're only behind by one descriptor, we need to wait for all
-	 * descriptors to go owned so we're starting with a fresh slate. This
-	 * will also means we send an additional idle buffer. */
-	if (1 == behind) {
-		unsigned long stop;
-		stop = jiffies + HZ/100;
-		while (OWNED(d) && time_after(stop, jiffies))
-			continue;
-		WARN_ON(time_before(stop, jiffies));
-		WARN_ON(d->buffer1 == vb->idle_vbb_dma_addr);
-		WARN_ON(!dl->pending[dl->head]);
-		dma_unmap_single(&vb->pdev->dev, d->buffer1,
-				 VOICEBUS_SFRAME_SIZE, DMA_TO_DEVICE);
-		vbb = dl->pending[dl->head];
-		atomic_dec(&dl->count);
-		--behind;
-	}
-
-	/* First complete any "idle" buffers that the hardware was to actually
-	 * complete.  We've already preloaded the behind variable for the idle
-	 * buffers that are in progress but may not be complete. */
-	while (!OWNED(d)) {
-		d->buffer1 = vb->idle_vbb_dma_addr;
-		dl->pending[dl->head] = vb->idle_vbb;
-		SET_OWNED(d);
-		dl->head = ++dl->head & DRING_MASK;
-		d = vb_descriptor(dl, dl->head);
-		++behind;
-	}
-
-	/* Next get a little further ahead, because the hardware will be
-	 * currently working on one of the idle buffers that we can't detect is
-	 * completed yet in the previous block. Set the head and tail pointers
-	 * to this new position so that everything can pick up normally. */
-	dl->tail = dl->head = (dl->head + 10) & DRING_MASK;
-
-	if (NULL != vbb)
-		handle_transmit(vb, vbb);
-
-	return behind;
-}
-
-/**
- * vb_deferred() - Manage the transmit and receive descriptor rings.
- *
- */
-static void vb_deferred(struct voicebus *vb)
-{
-	unsigned int buffer_count;
-	unsigned int i;
-	unsigned int idle_buffers;
-	int softunderrun;
-
-	buffer_count = 0;
+	int behind = 0;
+	const int DEFAULT_COUNT = 5;
+	int count = DEFAULT_COUNT;
 
 	/* First, temporarily store any non-idle buffers that the hardware has
 	 * indicated it's finished transmitting.  Non idle buffers are those
@@ -1263,65 +1161,88 @@
 	 * 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 ((vb->vbb_stash[buffer_count] = vb_get_completed_txb(vb))) {
-		++buffer_count;
-		if (unlikely(VOICEBUS_DEFAULT_MAXLATENCY < buffer_count)) {
-			dev_warn(&vb->pdev->dev, "Critical problem detected "
-				 "in transmit ring descriptor\n");
-			if (buffer_count >= DRING_SIZE)
-				buffer_count = DRING_SIZE - 1;
-			break;
+	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);
+		if (1 == atomic_read(&dl->count)) {
+			unsigned long stop;
+			stop = jiffies + HZ/4;
+			while (OWNED(d) && time_after(stop, jiffies))
+				continue;
+			if (time_before(stop, jiffies))
+				goto tx_error_exit;
+
+			if (d->buffer1 == vb->idle_vbb_dma_addr)
+				goto tx_error_exit;
+
+			vbb = vb_get_completed_txb(vb);
+			list_add_tail(&vbb->entry, &vb->tx_complete);
+			behind = 1;
+		} else  {
+			behind = 2;
+			while (!OWNED(d)) {
+				if (d->buffer1 != vb->idle_vbb_dma_addr)
+					goto tx_error_exit;
+				SET_OWNED(d);
+				dl->head = ++dl->head & DRING_MASK;
+				d = vb_descriptor(dl, dl->head);
+				++behind;
+			}
 		}
-	}
-
-	vb->count += buffer_count;
-
-	/* Next, check to see if we're in a softunderrun condition.
-	 *
-	 * A soft under is when the hardware has possibly copied at least one of
-	 * the idle buffers into it's transmit queue.  Since all the buffers are
-	 * nearly always owned by the hardware, the way we detect this is by
-	 * checking if either of the next two buffers that we expect to complete
-	 * are idle buffers.  We need to check the next two, because the
-	 * hardware can read two buffers into it's tx fifo where they are
-	 * definitely going to be sent on the interface, but the hardware does
-	 * not flip the OWN bit on the descriptors until after the buffer has
-	 * finished being sent to the CPLD.  Therefore, just looking at the own
-	 * bit and the buffer pointed to by the dl->head is not enough.
-	 *
-	 * NOTE: Do not print anything to the console from the time a soft
-	 * underrun is detected 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_is_softunderrun(vb))) {
-		softunderrun = 1;
-		/* If we experienced a soft underrun, the recover function will
-		 * a) ensure that all non-idle buffers have been completely
-		 * tranmitted by the hardware b) Reset any idle buffers that
-		 * have been completely transmitted c) Reset the head and tail
-		 * pointers to somwhere in advance of where the hardware is
-		 * currently processing and d) return how many idle_buffers were
-		 * transmitted before our interrupt handler was called. */
-		idle_buffers = vb_recover_tx_descriptor_list(vb);
-		vb_increase_latency(vb, idle_buffers);
+
 	} else {
 		softunderrun = 0;
-		idle_buffers = 0;
-	}
-
-	/* Now we can process the completed non-idle buffers since we know at
-	 * this point that the transmit descriptor is in a "good" state. */
-	for (i = 0; i < buffer_count; ++i)
-		handle_transmit(vb, vb->vbb_stash[i]);
+	}
+
+	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(softunderrun)) {
+		int i;
+		vb_increase_latency(vb, behind, &buffers);
+
+		d = vb_descriptor(dl, dl->head);
+		while (!OWNED(d)) {
+			if (d->buffer1 != vb->idle_vbb_dma_addr)
+				goto tx_error_exit;
+			SET_OWNED(d);
+			dl->head = ++dl->head & DRING_MASK;
+			d = vb_descriptor(dl, dl->head);
+			++behind;
+		}
+		/* Now we'll get a little further ahead of the hardware. */
+		for (i = 0; i < 5; ++i) {
+			d = vb_descriptor(dl, dl->head);
+			d->buffer1 = vb->idle_vbb_dma_addr;
+			dl->pending[dl->head] = vb->idle_vbb;
+			d->des0 |= OWN_BIT;
+			dl->head = ++dl->head & DRING_MASK;
+		}
+		dl->tail = dl->head;
+	}
+
+	d = vb_descriptor(dl, dl->tail);
+	if (d->buffer1 != vb->idle_vbb_dma_addr)
+		goto tx_error_exit;
+
+	/* Now we can send all our buffers together in a group. */
+	list_for_each_entry(vbb, &buffers, entry)
+		voicebus_transmit(vb, vbb);
+	INIT_LIST_HEAD(&buffers);
 
 	/* 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(softunderrun)) {
-		vb_reset_tx_owned(vb);
+#if !defined(CONFIG_VOICEBUS_SYSFS)
 		if (!test_bit(LATENCY_LOCKED, &vb->flags) &&
 		    printk_ratelimit()) {
 			if (vb->max_latency != vb->min_tx_buffer_count) {
@@ -1336,18 +1257,34 @@
 					 "latency.\n", vb->max_latency);
 			}
 		}
-	}
-
-	/* And finally, pass up any receive buffers.  We also use vb->count to
-	 * make a half-hearted attempt to not pass any recieved idle buffers to
-	 * the caller, but this needs more work.... */
-	while ((vb->vbb_stash[0] = vb_get_completed_rxb(vb))) {
-		if (vb->count) {
-			vb->ops->handle_receive(vb, vb->vbb_stash[0]);
-			--vb->count;
-		}
-		vb_submit_rxb(vb, vb->vbb_stash[0]);
-	}
+#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(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)))
+		list_add_tail(&vbb->entry, &buffers);
+
+	handle_receive(vb, &buffers);
+	list_for_each_entry(vbb, &buffers, entry)
+		vb_submit_rxb(vb, vbb);
+	return;
+
+tx_error_exit:
+	vb_disable_interrupts(vb);
+	schedule_work(&vb->underrun_work);
+	while (!list_empty(&buffers)) {
+		vbb = list_entry(buffers.next, struct vbb, entry);
+		list_del(&vbb->entry);
+		kmem_cache_free(buffer_cache, vbb);
+	}
+	return;
 }
 
 /**
@@ -1365,11 +1302,15 @@
 	struct voicebus *vb = container_of(work, struct voicebus,
 					   underrun_work);
 #endif
+	if (test_bit(STOP, &vb->flags) || test_bit(STOPPED, &vb->flags))
+		return;
+
 	if (printk_ratelimit()) {
 		dev_info(&vb->pdev->dev, "Host failed to service "
 			 "card interrupt within %d ms which is a "
 			 "hardunderun.\n", DRING_SIZE);
 	}
+
 	voicebus_stop(vb);
 
 	if (vb->ops->handle_error)
@@ -1406,7 +1347,8 @@
 	if (!int_status)
 		return IRQ_NONE;
 
-	if (unlikely((int_status & TX_UNAVAILABLE_INTERRUPT) &&
+	if (unlikely((int_status &
+	    (TX_UNAVAILABLE_INTERRUPT|RX_UNAVAILABLE_INTERRUPT)) &&
 	    !test_bit(STOP, &vb->flags))) {
 		schedule_work(&vb->underrun_work);
 		__vb_setctl(vb, SR_CSR5, int_status);
@@ -1414,13 +1356,7 @@
 		/* ******************************************************** */
 		/* NORMAL INTERRUPT CASE				    */
 		/* ******************************************************** */
-#		if VOICEBUS_DEFERRED == WORKQUEUE
-		queue_work(vb->workqueue, &vb->workitem);
-#		elif VOICEBUS_DEFERRED == TASKLET
-		tasklet_schedule(&vb->tasklet);
-#		else
-		vb_deferred(vb);
-#		endif
+		tasklet_hi_schedule(&vb->tasklet);
 		__vb_setctl(vb, SR_CSR5, TX_COMPLETE_INTERRUPT);
 	} else {
 		if (int_status & FATAL_BUS_ERROR_INTERRUPT)
@@ -1428,16 +1364,18 @@
 
 		if (int_status & TX_STOPPED_INTERRUPT) {
 			BUG_ON(!test_bit(STOP, &vb->flags));
-			__vb_disable_interrupts(vb);
-			complete(&vb->stopped_completion);
-		}
-		if (int_status & RX_STOPPED_INTERRUPT) {
-			BUG_ON(!test_bit(STOP, &vb->flags));
-			if (vb_is_stopped(vb)) {
+			if (__vb_is_stopped(vb)) {
 				__vb_disable_interrupts(vb);
 				complete(&vb->stopped_completion);
 			}
 		}
+		if (int_status & RX_STOPPED_INTERRUPT) {
+			BUG_ON(!test_bit(STOP, &vb->flags));
+			if (__vb_is_stopped(vb)) {
+				__vb_disable_interrupts(vb);
+				complete(&vb->stopped_completion);
+			}
+		}
 
 		/* Clear the interrupt(s) */
 		__vb_setctl(vb, SR_CSR5, int_status);
@@ -1446,7 +1384,7 @@
 	return IRQ_HANDLED;
 }
 
-#if VOICEBUS_DEFERRED == TIMER
+#if defined(CONFIG_VOICEBUS_TIMER)
 /*! \brief Called if the deferred processing is to happen in the context of
  * the timer.
  */
@@ -1467,27 +1405,11 @@
 }
 #endif
 
-#if VOICEBUS_DEFERRED == WORKQUEUE
-static void
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-vb_workfunc(void *data)
-{
-	struct voicebus *vb = data;
-#else
-vb_workfunc(struct work_struct *work)
-{
-	struct voicebus *vb = container_of(work, struct voicebus, workitem);
-#endif
-	vb_deferred(vb);
-}
-#elif VOICEBUS_DEFERRED == TASKLET
-static void
-vb_tasklet(unsigned long data)
+static void vb_tasklet(unsigned long data)
 {
 	struct voicebus *vb = (struct voicebus *)data;
 	vb_deferred(vb);
 }
-#endif /* #if VOICEBUS_DEFERRED == WORKQUEUE */
 
 /*!
  * \brief Initalize the voicebus interface.
@@ -1517,23 +1439,10 @@
 	clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
 	vb->min_tx_buffer_count = VOICEBUS_DEFAULT_LATENCY;
 
-#if VOICEBUS_DEFERRED == WORKQUEUE
-	/* NOTE: This workqueue must be single threaded because locking is not
-	 * used when buffers are removed or added to the descriptor list, and
-	 * there should only be one producer / consumer (the hardware or the
-	 * deferred processing function). */
-	vb->workqueue = create_singlethread_workqueue(board_name);
-#	if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
-	INIT_WORK(&vb->workitem, vb_workfunc, vb);
-#	else
-	INIT_WORK(&vb->workitem, vb_workfunc);
-#	endif
-#	if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
-	vb_set_workqueue_priority(vb);
-#	endif
-#elif VOICEBUS_DEFERRED == TASKLET
+	INIT_LIST_HEAD(&vb->tx_complete);
 	tasklet_init(&vb->tasklet, vb_tasklet, (unsigned long)vb);
-#elif VOICEBUS_DEFERRED == TIMER
+
+#if defined(CONFIG_VOICEBUS_TIMER)
 	init_timer(&vb->timer);
 	vb->timer.function = vb_timer;
 	vb->timer.data = (unsigned long)vb;
@@ -1603,7 +1512,7 @@
 	if (retval)
 		goto cleanup;
 
-#if VOICEBUS_DEFERRED != TIMER
+#if !defined(CONFIG_VOICEBUS_TIMER)
 	retval = request_irq(vb->pdev->irq, vb_isr, DAHDI_IRQ_SHARED,
 			     board_name, vb);
 	if (retval) {
@@ -1615,14 +1524,9 @@
 	return retval;
 cleanup:
 
-#if VOICEBUS_DEFERRED == WORKQUEUE
-	if (vb->workqueue)
-		destroy_workqueue(vb->workqueue);
-#elif VOICEBUS_DEFERRED == TASKLET
 	tasklet_kill(&vb->tasklet);
-#endif
+
 	/* Cleanup memory and software resources. */
-
 	if (vb->txd.desc)
 		vb_free_descriptors(vb, &vb->txd);
 
@@ -1645,7 +1549,7 @@
 EXPORT_SYMBOL(voicebus_init);
 
 static spinlock_t loader_list_lock;
-static struct list_head binary_loader_list;
+static LIST_HEAD(binary_loader_list);
 
 /**
  * vpmadtreg_loadfirmware - Load the vpmadt032 firmware.
@@ -1740,7 +1644,7 @@
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
 	buffer_cache = kmem_cache_create(THIS_MODULE->name,
-					 VOICEBUS_SFRAME_SIZE, 0,
+					 sizeof(struct vbb), 0,
 #if defined(CONFIG_SLUB) && (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22))
 					 SLAB_HWCACHE_ALIGN |
 					 SLAB_STORE_USER, NULL,
@@ -1752,12 +1656,12 @@
 #else
 #ifdef DEBUG
 	buffer_cache = kmem_cache_create(THIS_MODULE->name,
-					 VOICEBUS_SFRAME_SIZE, 0,
+					 sizeof(struct vbb), 0,
 					 SLAB_HWCACHE_ALIGN | SLAB_STORE_USER |
 					 SLAB_POISON | SLAB_DEBUG_FREE, NULL);
 #else
 	buffer_cache = kmem_cache_create(THIS_MODULE->name,
-					 VOICEBUS_SFRAME_SIZE, 0,
+					 sizeof(struct vbb), 0,
 					 SLAB_HWCACHE_ALIGN, NULL);
 #endif
 #endif
@@ -1773,7 +1677,6 @@
 	 * dahdi.ko, so that when it is being unloded, this module will be
 	 * unloaded as well. */
 	dahdi_register(NULL, 0);
-	INIT_LIST_HEAD(&binary_loader_list);
 	spin_lock_init(&loader_list_lock);
 	res = vpmadt032_module_init();
 	if (res)

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=8095&r1=8094&r2=8095
==============================================================================
--- linux/trunk/drivers/dahdi/voicebus/voicebus.h (original)
+++ linux/trunk/drivers/dahdi/voicebus/voicebus.h Thu Feb 25 11:33:58 2010
@@ -29,6 +29,8 @@
 #ifndef __VOICEBUS_H__
 #define __VOICEBUS_H__
 
+#include <linux/interrupt.h>
+
 #define VOICEBUS_DEFAULT_LATENCY	3
 #define VOICEBUS_DEFAULT_MAXLATENCY	25
 #define VOICEBUS_MAXLATENCY_BUMP	6
@@ -42,22 +44,21 @@
 /* Define CONFIG_VOICEBUS_SYSFS to create some attributes under the pci device.
  * This is disabled by default because it hasn't been tested on the full range
  * of supported kernels. */
-#undef CONFIG_VOICEBUS_SYSFS
+#define CONFIG_VOICEBUS_SYSFS
 
-#define INTERRUPT 0	/* Run the deferred processing in the ISR. */
-#define TASKLET   1	/* Run in a tasklet. */
-#define TIMER	  2	/* Run in a system timer. */
-#define WORKQUEUE 3	/* Run in a workqueue. */
-
-#ifndef VOICEBUS_DEFERRED
-#define VOICEBUS_DEFERRED INTERRUPT
-#endif
+/* Do not generate interrupts on this interface, but instead just poll it */
+#undef CONFIG_VOICEBUS_TIMER
 
 struct voicebus;
 
+struct vbb {
+	u8 data[VOICEBUS_SFRAME_SIZE];
+	struct list_head entry;
+};
+
 struct voicebus_operations {
-	void (*handle_receive)(struct voicebus *vb, void *vbb);
-	void (*handle_transmit)(struct voicebus *vb, void *vbb);
+	void (*handle_receive)(struct voicebus *vb, struct list_head *buffers);
+	void (*handle_transmit)(struct voicebus *vb, struct list_head *buffers);
 	void (*handle_error)(struct voicebus *vb);
 };
 
@@ -77,41 +78,39 @@
 /**
  * struct voicebus - Represents physical interface to voicebus card.
  *
+ * @tx_complete: only used in the tasklet to temporarily hold complete tx
+ *		 buffers.
  */
 struct voicebus {
 	struct pci_dev		*pdev;
 	spinlock_t		lock;
 	struct voicebus_descriptor_list rxd;
 	struct voicebus_descriptor_list txd;
-	void			*idle_vbb;
+	u8			*idle_vbb;
 	dma_addr_t		idle_vbb_dma_addr;
 	const int		*debug;
 	u32			iobase;
-#if VOICEBUS_DEFERRED == WORKQUEUE
-	struct workqueue_struct *workqueue;
-	struct work_struct	workitem;
-#elif VOICEBUS_DEFERRED == TASKLET
 	struct tasklet_struct 	tasklet;
-#elif VOICEBUS_DEFERRED == TIMER
+
+#if defined(CONFIG_VOICEBUS_TIMER)
 	struct timer_list	timer;
 #endif
+
 	struct work_struct	underrun_work;
 	const struct voicebus_operations *ops;
 	struct completion	stopped_completion;
 	unsigned long		flags;
 	unsigned int		min_tx_buffer_count;
 	unsigned int		max_latency;
-	void			*vbb_stash[DRING_SIZE];
-	unsigned int		count;
+	struct list_head	tx_complete;
 };
 
 int voicebus_init(struct voicebus *vb, const char *board_name);
 void voicebus_release(struct voicebus *vb);
 int voicebus_start(struct voicebus *vb);
 int voicebus_stop(struct voicebus *vb);
-void *voicebus_alloc(struct voicebus* vb);
-void voicebus_free(struct voicebus *vb, void *vbb);
-int voicebus_transmit(struct voicebus *vb, void *vbb);
+void voicebus_free(struct voicebus *vb, struct vbb *vbb);
+int voicebus_transmit(struct voicebus *vb, struct vbb *vbb);
 int voicebus_set_minlatency(struct voicebus *vb, unsigned int milliseconds);
 int voicebus_current_latency(struct voicebus *vb);
 void voicebus_lock_latency(struct voicebus *vb);

Modified: linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c?view=diff&rev=8095&r1=8094&r2=8095
==============================================================================
--- linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c (original)
+++ linux/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c Thu Feb 25 11:33:58 2010
@@ -75,19 +75,23 @@
 	init_completion(&ctx->done);
 }
 
-static void handle_receive(struct voicebus *vb, void *vbb)
+static void handle_receive(struct voicebus *vb, struct list_head *buffers)
 {
 	struct private_context *ctx = pci_get_drvdata(vb->pdev);
-	__vpmadt032_receive(ctx->pvt, vbb);
-	if (__vpmadt032_done(ctx->pvt))
-		complete(&ctx->done);
+	struct vbb *vbb;
+	list_for_each_entry(vbb, buffers, entry) {
+		__vpmadt032_receive(ctx->pvt, vbb->data);
+		if (__vpmadt032_done(ctx->pvt))
+			complete(&ctx->done);
+	}
 }
 
-static void handle_transmit(struct voicebus *vb, void *vbb)

[... 183 lines stripped ...]



More information about the svn-commits mailing list