[svn-commits] sruffell: branch linux/sruffell/dahdi-linux-chainedvb r7107 - /linux/team/sru...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Sep 9 01:13:23 CDT 2009
Author: sruffell
Date: Wed Sep 9 01:13:21 2009
New Revision: 7107
URL: http://svn.asterisk.org/svn-view/dahdi?view=rev&rev=7107
Log:
wip: Shifting gears..not sure I even need chained descriptors.
This starts the process of keeping all the "idle" buffers on the same list, in
normal order as with the ring descriptors. An "underrun" condition is detected
when the the driver detects that it's completing a descriptor that points to the
idle buffer. This still doesn't work, just saving off a checkpoint.
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://svn.asterisk.org/svn-view/dahdi/linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c?view=diff&rev=7107&r1=7106&r2=7107
==============================================================================
--- linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c Wed Sep 9 01:13:21 2009
@@ -26,6 +26,9 @@
* Free Software Foundation. See the LICENSE file included with
* this program for more details.
*/
+
+#define DEBUG
+#define HERE() printk(KERN_DEBUG "HERE: %s:%d\n", __FILE__, __LINE__)
#include <linux/version.h>
#include <linux/slab.h>
@@ -149,7 +152,7 @@
/**
* struct voicebus_descriptor_list -
- * @desc_list: Allocated buffer list.
+ * @list: Allocated buffer list.
* @head: Next buffer to complete.
* @tail: Next free buffer to use.
* @direction: DMA_FROM_DEVICE or DMA_TO_DEVICE
@@ -157,7 +160,7 @@
*
*/
struct voicebus_descriptor_list {
- struct list_head desc_list;
+ struct list_head list;
struct voicebus_chained_descriptor *head;
struct voicebus_chained_descriptor *tail;
enum dma_data_direction direction;
@@ -186,7 +189,12 @@
#endif
-/*! * \brief Represents a VoiceBus interface on a Digium telephony card.
+/**
+ * struct voicebus -
+ *
+ * @tx_idle_vbb:
+ * @tx_idle_vbb_dma_addr:
+ *
*/
struct voicebus {
/*! Name of this card. */
@@ -204,6 +212,9 @@
/*! Pool to allocate memory for the tx and rx descriptor rings. */
struct voicebus_descriptor_list rxd;
struct voicebus_descriptor_list txd;
+ void *idle_vbb;
+ dma_addr_t idle_vbb_dma_addr;
+ int underruncount;
/*! Level of debugging information. 0=None, 5=Insane. */
atomic_t debuglevel;
/*! Cache of buffer objects. */
@@ -235,6 +246,14 @@
void *context;
struct completion stopped_completion;
/*! Flags */
+
+#define TX_UNDERRUN 1
+#define RX_UNDERRUN 2
+#define IN_DEFERRED_PROCESSING 3
+#define STOP 4
+#define STOPPED 5
+#define TX_RECOVERING 6
+
unsigned long flags;
/* \todo see about removing this... */
u32 sdi;
@@ -271,12 +290,6 @@
#define VB_PRINTK(_vb, _lvl, _fmt, _args...) \
printk(KERN_##_lvl "%s: " _fmt, (_vb)->board_name, ## _args)
-/* Bit definitions for struct voicebus.flags */
-#define TX_UNDERRUN 1
-#define RX_UNDERRUN 2
-#define IN_DEFERRED_PROCESSING 3
-#define STOP 4
-#define STOPPED 5
#if VOICEBUS_DEFERRED == WORKQUEUE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
@@ -348,25 +361,38 @@
struct voicebus_chained_descriptor *d)
{
/* Skip the head of the list if necessary. */
- return (d->node.next == &dl->desc_list) ?
- list_entry(dl->desc_list.next, typeof(*d), node) :
+ return (d->node.next == &dl->list) ?
+ list_entry(dl->list.next, typeof(*d), node) :
list_entry(d->node.next, typeof(*d), node);
}
+
+static struct voicebus_chained_descriptor *
+get_prev_descriptor(struct voicebus_descriptor_list *dl,
+ struct voicebus_chained_descriptor *d)
+{
+ /* Skip the head of the list if necessary. */
+ return (d->node.prev == &dl->list) ?
+ list_entry(dl->list.prev, typeof(*d), node) :
+ list_entry(d->node.prev, typeof(*d), node);
+}
+
+#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
+#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0)
static void vb_cleanup_descriptors(struct voicebus *vb,
struct voicebus_descriptor_list *dl)
{
struct voicebus_chained_descriptor *d;
- struct list_head *const list = &dl->desc_list;
+ struct list_head *const list = &dl->list;
list_for_each_entry(d, list, node) {
if (d->desc->buffer1) {
- d->desc->buffer1 = 0;
BUG_ON(!d->pending);
voicebus_free(vb, d->pending);
- d->pending = NULL;
+ d->pending = vb->idle_vbb;
+ d->desc->buffer1 = vb->idle_vbb_dma_addr;
}
- d->desc->des0 &= ~OWN_BIT;
+ SET_OWNED(d->desc);
}
dl->head = list_entry(list->next, typeof(*d), node);
dl->tail = list_entry(list->next, typeof(*d), node);
@@ -402,9 +428,10 @@
vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
{
struct voicebus_chained_descriptor *d;
- struct list_head *const list = &dl->desc_list;
+ struct list_head *const list = &dl->list;
vb_cleanup_descriptors(vb, dl);
+
while (!list_empty(list)) {
d = list_entry(list->next, typeof(*d), node);
list_del(&d->node);
@@ -436,13 +463,11 @@
int i;
const u32 CHAINED = 0x01000000;
struct voicebus_chained_descriptor *d;
- struct voicebus_chained_descriptor *prev;
-
- /* Since we're passing each descriptor address explicitly, we don't
- * need any padding for the chained descriptor. */
+ struct voicebus_chained_descriptor *prev = NULL;
+
dl->padding = 0;
- INIT_LIST_HEAD(&dl->desc_list);
+ INIT_LIST_HEAD(&dl->list);
for (i = 0; i < DLIST_SIZE; ++i) {
d = kzalloc(sizeof(*d), GFP_KERNEL);
@@ -456,18 +481,15 @@
goto error_nomem;
}
- list_add_tail(&d->node, &dl->desc_list);
- }
-
- dl->head = list_entry(dl->desc_list.next, typeof(*d), node);
- dl->tail = dl->head;
-
- prev = dl->head;
- list_for_each_entry_reverse(d, &dl->desc_list, node) {
- d->desc->buffer2 = prev->dma_addr;
+ if (prev)
+ d->desc->buffer2 = prev->dma_addr;
d->desc->des1 |= cpu_to_le32(des1 | CHAINED);
prev = d;
- }
+ list_add(&d->node, &dl->list);
+ }
+
+ dl->head = list_entry(dl->list.next, typeof(*d), node);
+ dl->tail = dl->head;
atomic_set(&dl->count, 0);
return 0;
@@ -521,8 +543,29 @@
static int
vb_initialize_tx_descriptors(struct voicebus *vb)
{
- return vb_initialize_descriptors(
- vb, &vb->txd, 0xe4800000 | vb->framesize, DMA_TO_DEVICE);
+ int res;
+ struct voicebus_chained_descriptor *d;
+
+ res = vb_initialize_descriptors(vb, &vb->txd,
+ 0xe4800000 | vb->framesize,
+ DMA_TO_DEVICE);
+ if (res) {
+ dev_dbg(&vb->pdev->dev, "Failed to initialize tx descriptor ring.\n");
+ return res;
+ }
+
+ if (!vb->idle_vbb || !vb->idle_vbb_dma_addr) {
+ dev_dbg(&vb->pdev->dev, "idle vbb not allocated.\n");
+ return -EFAULT;
+ }
+
+ list_for_each_entry(d, &vb->txd.list, node) {
+ d->desc->buffer1 = vb->idle_vbb_dma_addr;
+ d->pending = vb->idle_vbb;
+ SET_OWNED(d->desc);
+ }
+
+ return 0;
}
static int
@@ -847,9 +890,6 @@
return ((reg&0x7) == 0x4) ? 0 : -EIO;
}
-#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
-#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0)
-
#ifdef DBG
static void
dump_descriptor(struct voicebus *vb, volatile struct voicebus_descriptor *d)
@@ -880,7 +920,7 @@
#if defined(USE_CHAINED_DESCRIPTORS)
-static int vb_submit(struct voicebus *vb,
+static int vb_chained_submit(struct voicebus *vb,
struct voicebus_descriptor_list *dl, void *vbb)
{
struct voicebus_chained_descriptor *d;
@@ -904,7 +944,8 @@
return -EFAULT;
}
-static void* vb_retrieve(struct voicebus *vb,
+#if 0
+static void* vb_chained_retrieve(struct voicebus *vb,
struct voicebus_descriptor_list *dl)
{
struct voicebus_chained_descriptor *d;
@@ -924,6 +965,7 @@
return NULL;
}
}
+#endif
#else
@@ -975,6 +1017,46 @@
#endif
+#if defined(USE_CHAINED_DESCRIPTORS)
+
+int voicebus_transmit(struct voicebus *vb, void *vbb)
+{
+ struct voicebus_chained_descriptor *d;
+ struct voicebus_descriptor_list *const dl = &vb->txd;
+
+ d = dl->tail;
+
+ if (printk_ratelimit())
+ dev_dbg(&vb->pdev->dev, "d->desc->buffer1 = %08x\n", d->desc->buffer1);
+ /* Do not overwrite a buffer that is still in progress. */
+ if (unlikely(d->desc->buffer1 != vb->idle_vbb_dma_addr)) {
+ voicebus_free(vb, vbb);
+ return -EFAULT;
+ }
+
+ dl->tail = get_next_descriptor(dl, d);
+ d->pending = vbb;
+ d->desc->buffer2 = dl->tail->dma_addr;
+ d->desc->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
+ vb->framesize, dl->direction);
+
+ /* That's it until the hardware is done with it. */
+ SET_OWNED(d->desc);
+ atomic_inc(&dl->count);
+ return 0;
+}
+EXPORT_SYMBOL(voicebus_transmit);
+
+/*!
+ * \brief Give a frame to the hardware to use for receiving.
+ *
+ */
+static inline int vb_submit_rxb(struct voicebus *vb, void *vbb)
+{
+ return vb_chained_submit(vb, &vb->rxd, vbb);
+}
+
+#else
/*!
* \brief Give a frame to the hardware to transmit.
*
@@ -995,6 +1077,7 @@
{
return vb_submit(vb, &vb->rxd, vbb);
}
+#endif
/*!
* \brief Remove the next completed transmit buffer (txb) from the tx
@@ -1009,6 +1092,114 @@
*
* \return Pointer to buffer, or NULL if not available.
*/
+#if defined(USE_CHAINED_DESCRIPTORS)
+
+/**
+ * recover_transmit_descriptor_list() -
+ * @vb:
+ * @d:
+ *
+ * Called when the driver determined that the hardware has transmitted one of
+ * the "idle" buffers.
+ *
+ */
+static void
+start_tx_descriptor_list_recovery(struct voicebus *vb,
+ struct voicebus_chained_descriptor *d)
+{
+ struct voicebus_descriptor_list *const dl = &vb->txd;
+ struct voicebus_chained_descriptor *next;
+ int count = 1;
+
+ next = get_next_descriptor(dl, d);
+ while (!OWNED(next->desc)) {
+ next->desc->buffer1 = vb->idle_vbb_dma_addr;
+ d->pending = vb->idle_vbb;
+ SET_OWNED(next->desc);
+ next = get_next_descriptor(dl, next);
+ ++count;
+ }
+
+ vb->underruncount = count;
+
+ count = 3;
+ while (--count)
+ next = get_next_descriptor(dl, next);
+
+ vb->txd.tail = next;
+
+ WARN_ON(!OWNED(get_prev_descriptor(&vb->txd, next)->desc));
+ set_bit(TX_RECOVERING, &vb->flags);
+}
+
+static void stop_tx_descriptor_list_recovery(struct voicebus *vb)
+{
+ clear_bit(TX_RECOVERING, &vb->flags);
+}
+
+static int tx_descriptor_list_recovering(struct voicebus *vb)
+{
+ return test_bit(TX_RECOVERING, &vb->flags);
+}
+
+static void* vb_get_completed_txb(struct voicebus *vb)
+{
+ struct voicebus_chained_descriptor *d;
+ struct voicebus_descriptor_list *const dl = &vb->txd;
+ void *vbb;
+
+ assert_in_vb_deferred(vb);
+ d = dl->head;
+ if (printk_ratelimit())
+ dev_dbg(&vb->pdev->dev, "buffer1: %08x idle: %08x\n", d->desc->buffer1, (u32)vb->idle_vbb_dma_addr);
+
+ if (d->desc->buffer1 == vb->idle_vbb_dma_addr) {
+ if (unlikely(!OWNED(d->desc))) {
+ if (!tx_descriptor_list_recovering(vb))
+ start_tx_descriptor_list_recovery(vb, d);
+ SET_OWNED(d->desc);
+ }
+ return NULL;
+ }
+
+ dma_unmap_single(&vb->pdev->dev, d->desc->buffer1,
+ vb->framesize, dl->direction);
+ vbb = d->pending;
+
+ d->desc->buffer1 = vb->idle_vbb_dma_addr;
+ SET_OWNED(d->desc);
+
+ dl->head = get_next_descriptor(dl, d);
+ atomic_dec(&dl->count);
+
+ if (unlikely(tx_descriptor_list_recovering(vb)))
+ stop_tx_descriptor_list_recovery(vb);
+
+ return vbb;
+}
+
+static void* vb_get_completed_rxb(struct voicebus *vb)
+{
+ struct voicebus_chained_descriptor *d;
+ struct voicebus_descriptor_list *const dl = &vb->rxd;
+ void *vbb;
+
+ assert_in_vb_deferred(vb);
+ d = dl->head;
+ if (!d->desc->buffer1 || OWNED(d->desc))
+ return NULL;
+
+ dma_unmap_single(&vb->pdev->dev, d->desc->buffer1,
+ vb->framesize, dl->direction);
+ vbb = d->pending;
+ dl->head = get_next_descriptor(dl, d);
+ d->desc->buffer1 = 0;
+ atomic_dec(&dl->count);
+ return vbb;
+}
+
+#else
+
static inline void *
vb_get_completed_txb(struct voicebus *vb)
{
@@ -1020,6 +1211,7 @@
{
return vb_retrieve(vb, &vb->rxd);
}
+#endif
/*!
* \brief Free a buffer for reuse.
@@ -1304,6 +1496,8 @@
#endif
/* Cleanup memory and software resources. */
+ dma_free_coherent(&vb->pdev->dev, vb->framesize,
+ vb->idle_vbb, vb->idle_vbb_dma_addr);
vb_free_descriptors(vb, &vb->txd);
vb_free_descriptors(vb, &vb->rxd);
kmem_cache_destroy(vb->buffer_cache);
@@ -1314,7 +1508,7 @@
EXPORT_SYMBOL(voicebus_release);
static void
-__vb_increase_latency(struct voicebus *vb)
+__vb_increase_latency(struct voicebus *vb, int increase)
{
static int __warn_once = 1;
void *vbb;
@@ -1345,12 +1539,12 @@
*/
VB_PRINTK(vb, INFO, "Missed interrupt. " \
"Increasing latency to %d ms in order to compensate.\n",
- latency+1);
+ latency + increase);
/* 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.
*/
- voicebus_set_minlatency(vb, latency+1);
+ voicebus_set_minlatency(vb, latency + increase);
vbb = voicebus_alloc(vb);
if (unlikely(NULL == vbb))
@@ -1372,11 +1566,9 @@
vb_deferred(struct voicebus *vb)
{
void *vbb;
-#ifdef DBG
- static int count;
-#endif
+
int underrun = test_bit(TX_UNDERRUN, &vb->flags);
-
+ int limit = DLIST_SIZE;
start_vb_deferred(vb);
if (unlikely(underrun)) {
@@ -1389,12 +1581,19 @@
* list which decreases the sensitivity to latency, but also
* adds more delay to the TDM and SPI data.
*/
- __vb_increase_latency(vb);
+ __vb_increase_latency(vb, 1);
}
/* Always handle the transmit buffers first. */
- while ((vbb = vb_get_completed_txb(vb)))
+ while ((vbb = vb_get_completed_txb(vb)) && --limit) {
vb->handle_transmit(vbb, vb->context);
+ }
+
+ if (unlikely(vb->underruncount)) {
+ dev_dbg(&vb->pdev->dev, "underrun: %d\n", vb->underruncount);
+ __vb_increase_latency(vb, vb->underruncount);
+ vb->underruncount = 0;
+ }
if (unlikely(underrun)) {
vb_rx_demand_poll(vb);
@@ -1666,6 +1865,14 @@
goto cleanup;
}
+ vb->idle_vbb = dma_alloc_coherent(&vb->pdev->dev, vb->framesize,
+ &vb->idle_vbb_dma_addr, GFP_KERNEL);
+ if (!vb->idle_vbb) {
+ retval = -ENOMEM;
+ goto cleanup;
+ }
+ memset(vb->idle_vbb, 0, vb->framesize);
+
retval = vb_initialize_tx_descriptors(vb);
if (retval)
goto cleanup;
@@ -1707,8 +1914,9 @@
#elif VOICEBUS_DEFERRED == TASKLET
tasklet_kill(&vb->tasklet);
#endif
+ dma_free_coherent(&vb->pdev->dev, vb->framesize,
+ vb->idle_vbb, vb->idle_vbb_dma_addr);
/* Cleanup memory and software resources. */
-
vb_free_descriptors(vb, &vb->txd);
vb_free_descriptors(vb, &vb->rxd);
More information about the svn-commits
mailing list