[dahdi-commits] sruffell: branch linux/sruffell/dahdi-linux-chainedvb r7090 - /linux/team/sru...

SVN commits to the DAHDI project dahdi-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 dahdi-commits mailing list