[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