[svn-commits] sruffell: branch linux/sruffell/dahdi-linux-chainedvb r7090 - /linux/team/sru...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Thu Sep 3 15:30:35 CDT 2009
Author: sruffell
Date: Thu Sep 3 15:30:30 2009
New Revision: 7090
URL: http://svn.asterisk.org/svn-view/dahdi?view=rev&rev=7090
Log:
wip: The basic ring structure is in place...latency bumps are not tested.
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=7090&r1=7089&r2=7090
==============================================================================
--- linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c (original)
+++ linux/team/sruffell/dahdi-linux-chainedvb/drivers/dahdi/voicebus/voicebus.c Thu Sep 3 15:30:30 2009
@@ -67,6 +67,10 @@
#if defined(USE_CHAINED_DESCRIPTORS)
+/*
+ * DLIST_SIZE should be large enough to handle the worst case interrupt
+ * latency (in ms) on the host system.
+ */
#define DLIST_SIZE 128
#else
@@ -121,16 +125,42 @@
/* In memory structure shared by the host and the adapter. */
struct voicebus_descriptor {
- u32 des0;
- u32 des1;
- u32 buffer1;
- u32 buffer2; /* Unused */
+ __le32 volatile des0;
+ __le32 volatile des1;
+ __le32 volatile buffer1;
+ __le32 volatile buffer2;
} __attribute__((packed));
#if defined(USE_CHAINED_DESCRIPTORS)
+/**
+ * struct voicebus_chained_descriptor -
+ * @desc: Kernel virtual address of the descriptor.
+ * @desc_dma: Bus address of the desc to give to the hardware.
+ * @pending: Kernel virtual address desc->buffer1.
+ *
+ */
+struct voicebus_chained_descriptor {
+ struct voicebus_descriptor *desc;
+ dma_addr_t dma_addr;
+ struct list_head node;
+ void *pending;
+};
+
+/**
+ * struct voicebus_descriptor_list -
+ * @desc_list: Allocated buffer list.
+ * @head: Next buffer to complete.
+ * @tail: Next free buffer to use.
+ * @direction: DMA_FROM_DEVICE or DMA_TO_DEVICE
+ * @padding: Number of bytes to pad descriptors for cache alignment.
+ *
+ */
struct voicebus_descriptor_list {
- /*! The number of bytes to pad each descriptor for cache alignment. */
- unsigned int padding;
+ struct list_head desc_list;
+ struct voicebus_chained_descriptor *head;
+ struct voicebus_chained_descriptor *tail;
+ enum dma_data_direction direction;
+ unsigned int padding;
};
#else
struct voicebus_descriptor_list {
@@ -311,11 +341,135 @@
#endif
#if defined(USE_CHAINED_DESCRIPTORS)
+static struct voicebus_chained_descriptor *
+get_next_descriptor(struct voicebus_descriptor_list *dl,
+ 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) :
+ list_entry(d->node.next, typeof(*d), node);
+}
+
+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;
+
+ 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->desc->des0 &= ~OWN_BIT;
+ }
+ dl->head = list_entry(list->next, typeof(*d), node);
+ dl->tail = list_entry(list->next, typeof(*d), node);
+}
+#else
+static void
+vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+{
+ unsigned int i;
+ struct voicebus_descriptor *d;
+
+ assert(vb_is_stopped(vb));
+
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ if (d->buffer1) {
+ d->buffer1 = 0;
+ assert(dl->pending[i]);
+ voicebus_free(vb, dl->pending[i]);
+ dl->pending[i] = NULL;
+ }
+ d->des0 &= ~OWN_BIT;
+ }
+ dl->head = 0;
+ dl->tail = 0;
+ atomic_set(&dl->count, 0);
+}
+#endif
+
+#if defined(USE_CHAINED_DESCRIPTORS)
+static void
+vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+{
+ struct voicebus_chained_descriptor *d;
+ struct list_head *const list = &dl->desc_list;
+
+ while (!list_empty(list)) {
+ d = list_entry(list->next, struct voicebus_chained_descriptor, node);
+ list_del(&d->node);
+ dma_free_coherent(&vb->pdev->dev, sizeof(*d->desc),
+ d->desc, d->dma_addr);
+ kfree(d);
+ }
+}
+#else
+static void
+vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+{
+ if (NULL == dl->desc)
+ return;
+
+ vb_cleanup_descriptors(vb, dl);
+ pci_free_consistent(
+ vb->pdev,
+ (sizeof(struct voicebus_descriptor)+dl->padding)*DRING_SIZE,
+ dl->desc, dl->desc_dma);
+}
+#endif
+
+#if defined(USE_CHAINED_DESCRIPTORS)
static int
vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl,
u32 des1, unsigned int direction)
{
- return -EFAULT;
+ 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. */
+ dl->padding = 0;
+
+ INIT_LIST_HEAD(&dl->desc_list);
+
+ for (i = 0; i < DLIST_SIZE; ++i) {
+ d = kzalloc(sizeof(*d), GFP_KERNEL);
+ if (!d)
+ goto error_nomem;
+
+ d->desc = dma_alloc_coherent(&vb->pdev->dev, sizeof(*d->desc),
+ &d->dma_addr, GFP_KERNEL);
+ if (!d->desc) {
+ kfree(d);
+ 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;
+ d->desc->des1 |= cpu_to_le32(des1 | CHAINED);
+ prev = d;
+ }
+
+ return 0;
+
+error_nomem:
+ vb_free_descriptors(vb, dl);
+ return -ENOMEM;
}
#else
static int
@@ -329,14 +483,15 @@
assert(dl);
/*
- * Add some padding to each descriptor to ensure that they are
- * aligned on host system cache-line boundaries, but only for the
- * cache-line sizes that we support.
+ * Add some padding to each descriptor to ensure that they are aligned
+ * on host system cache-line boundaries, but only for the cache-line
+ * sizes that we support.
*
*/
- if ((0x08 == vb->cache_line_size) || (0x10 == vb->cache_line_size) ||
+ if ((0x08 == vb->cache_line_size) ||
+ (0x10 == vb->cache_line_size) ||
(0x20 == vb->cache_line_size)) {
- dl->padding = (vb->cache_line_size*sizeof(u32)) - sizeof(*d);
+ dl->padding = (vb->cache_line_size*sizeof(u32)) - sizeof(struct voicebus_descriptor);
} else {
dl->padding = 0;
}
@@ -375,13 +530,17 @@
/*! \brief Use to set the minimum number of buffers queued to the hardware
* before enabling interrupts.
*/
+#if defined(USE_CHAINED_DESCRIPTORS)
int
voicebus_set_minlatency(struct voicebus *vb, unsigned int ms)
{
-#if defined(USE_CHAINED_DESCRIPTORS)
dev_err(&vb->pdev->dev, "%s is not implemented.\n", __func__);
return -EFAULT;
-#else
+}
+#else
+int
+voicebus_set_minlatency(struct voicebus *vb, unsigned int ms)
+{
LOCKS_VOICEBUS;
/*
* One millisecond of latency means that we have 3 buffers pending,
@@ -401,8 +560,8 @@
vb->min_tx_buffer_count = ms;
VBUNLOCK(vb);
return 0;
-#endif
-}
+}
+#endif
EXPORT_SYMBOL(voicebus_set_minlatency);
void
@@ -491,48 +650,6 @@
reg = vb_getctl(vb, SR_CSR5);
reg = (reg >> 17) & 0x38;
return (0 == reg) ? 1 : 0;
-}
-
-static void
-vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
-{
-#if defined(USE_CHAINED_DESCRIPTORS)
-#else
- unsigned int i;
- struct voicebus_descriptor *d;
-
- assert(vb_is_stopped(vb));
-
- for (i = 0; i < DRING_SIZE; ++i) {
- d = vb_descriptor(dl, i);
- if (d->buffer1) {
- d->buffer1 = 0;
- assert(dl->pending[i]);
- voicebus_free(vb, dl->pending[i]);
- dl->pending[i] = NULL;
- }
- d->des0 &= ~OWN_BIT;
- }
- dl->head = 0;
- dl->tail = 0;
- atomic_set(&dl->count, 0);
-#endif
-}
-
-static void
-vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
-{
-#if defined(USE_CHAINED_DESCRIPTORS)
-#else
- if (NULL == dl->desc)
- return;
-
- vb_cleanup_descriptors(vb, dl);
- pci_free_consistent(
- vb->pdev,
- (sizeof(struct voicebus_descriptor)+dl->padding)*DRING_SIZE,
- dl->desc, dl->desc_dma);
-#endif
}
/*!
@@ -704,6 +821,9 @@
vb_setctl(vb, 0x0078, 0x00000013);
# if defined(USE_CHAINED_DESCRIPTORS)
+ /* Tell the card where the descriptors are in host memory. */
+ vb_setctl(vb, 0x0020, (u32)vb->txd.head->dma_addr);
+ vb_setctl(vb, 0x0018, (u32)vb->rxd.head->dma_addr);
# else
/* Tell the card where the descriptors are in host memory. */
vb_setctl(vb, 0x0020, (u32)vb->txd.desc_dma);
@@ -762,13 +882,56 @@
}
#endif
+#if defined(USE_CHAINED_DESCRIPTORS)
+
+static int vb_submit(struct voicebus *vb,
+ struct voicebus_descriptor_list *dl, void *vbb)
+{
+ struct voicebus_chained_descriptor *d;
+
+ d = dl->tail;
+
+ /* Do not overwrite a buffer that is still in progress. */
+ if (unlikely(d->desc->buffer1)) {
+ WARN_ON(1);
+ voicebus_free(vb, vbb);
+ }
+
+ dl->tail = get_next_descriptor(dl, d);
+ d->pending = vbb;
+ 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);
+ return -EFAULT;
+}
+
+static void* vb_retrieve(struct voicebus *vb,
+ struct voicebus_descriptor_list *dl)
+{
+ struct voicebus_chained_descriptor *d;
+ void *vbb;
+
+ assert_in_vb_deferred(vb);
+ d = dl->head;
+ if (d->desc->buffer1 && !OWNED(d->desc)) {
+ 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;
+ return vbb;
+ } else {
+ return NULL;
+ }
+}
+
+#else
+
static inline int
vb_submit(struct voicebus *vb, struct voicebus_descriptor_list *dl, void *vbb)
{
-#if defined(USE_CHAINED_DESCRIPTORS)
- dev_err(&vb->pdev->dev, "%s is not implemented.\n", __func__);
- return -EFAULT;
-#else
volatile struct voicebus_descriptor *d;
unsigned int tail = dl->tail;
assert_in_vb_deferred(vb);
@@ -789,16 +952,11 @@
SET_OWNED(d); /* That's it until the hardware is done with it. */
atomic_inc(&dl->count);
return 0;
-#endif
}
static inline void*
vb_retrieve(struct voicebus *vb, struct voicebus_descriptor_list *dl)
{
-#if defined(USE_CHAINED_DESCRIPTORS)
- dev_err(&vb->pdev->dev, "%s is not implemented.\n", __func__);
- return NULL;
-#else
volatile struct voicebus_descriptor *d;
void *vbb;
unsigned int head = dl->head;
@@ -815,8 +973,9 @@
} else {
return NULL;
}
-#endif
-}
+}
+
+#endif
/*!
* \brief Give a frame to the hardware to transmit.
More information about the svn-commits
mailing list