summaryrefslogtreecommitdiff
path: root/drivers/dahdi/voicebus/voicebus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dahdi/voicebus/voicebus.c')
-rw-r--r--drivers/dahdi/voicebus/voicebus.c848
1 files changed, 605 insertions, 243 deletions
diff --git a/drivers/dahdi/voicebus/voicebus.c b/drivers/dahdi/voicebus/voicebus.c
index d794365..70a1128 100644
--- a/drivers/dahdi/voicebus/voicebus.c
+++ b/drivers/dahdi/voicebus/voicebus.c
@@ -41,8 +41,6 @@
#include "vpmadtreg.h"
#include "GpakCust.h"
-#define assert(__x__) BUG_ON(!(__x__))
-
#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. */
@@ -56,6 +54,11 @@
#define VOICEBUS_ALLOC_FLAGS GFP_ATOMIC
#endif
+/* 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
+
#if VOICEBUS_DEFERRED == TIMER
#if HZ < 1000
/* \todo Put an error message here. */
@@ -63,7 +66,7 @@
#endif
/*! The number of descriptors in both the tx and rx descriptor ring. */
-#define DRING_SIZE (1 << 5) /* Must be a power of 2 */
+#define DRING_SIZE (1 << 7) /* Must be a power of 2 */
#define DRING_MASK (DRING_SIZE-1)
/* Interrupt status' reported in SR_CSR5 */
@@ -110,10 +113,10 @@
/* In memory structure shared by the host and the adapter. */
struct voicebus_descriptor {
- u32 des0;
- u32 des1;
- u32 buffer1;
- u32 container; /* Unused */
+ volatile __le32 des0;
+ volatile __le32 des1;
+ volatile __le32 buffer1;
+ volatile __le32 container; /* Unused */
} __attribute__((packed));
struct voicebus_descriptor_list {
@@ -127,20 +130,22 @@ struct voicebus_descriptor_list {
void *pending[DRING_SIZE];
/* PCI Bus address of the descriptor list. */
dma_addr_t desc_dma;
- /*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
- unsigned int direction;
/*! The number of buffers currently submitted to the hardware. */
atomic_t count;
/*! The number of bytes to pad each descriptor for cache alignment. */
unsigned int padding;
};
-
-/*! * \brief Represents a VoiceBus interface on a Digium telephony card.
+/**
+ * struct voicebus -
+ *
+ * @tx_idle_vbb:
+ * @tx_idle_vbb_dma_addr:
+ * @max_latency: Do not allow the driver to automatically insert more than this
+ * much latency to the tdm stream by default.
+ * @count: The number of non-idle buffers that we should be expecting.
*/
struct voicebus {
- /*! Name of this card. */
- const char *board_name;
/*! The system pci device for this VoiceBus interface. */
struct pci_dev *pdev;
/*! Protects access to card registers and this structure. You should
@@ -154,6 +159,8 @@ struct voicebus {
/*! 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;
/*! Level of debugging information. 0=None, 5=Insane. */
atomic_t debuglevel;
/*! Cache of buffer objects. */
@@ -186,12 +193,18 @@ struct voicebus {
struct completion stopped_completion;
/*! Flags */
unsigned long flags;
- /* \todo see about removing this... */
- u32 sdi;
/*! Number of tx buffers to queue up before enabling interrupts. */
unsigned int min_tx_buffer_count;
+ unsigned int max_latency;
+ void *vbb_stash[DRING_SIZE];
+ unsigned int count;
};
+static inline void handle_transmit(struct voicebus *vb, void *vbb)
+{
+ vb->handle_transmit(vbb, vb->context);
+}
+
/*
* Use the following macros to lock the VoiceBus interface, and it won't
* matter if the deferred processing is running inside the interrupt handler,
@@ -218,15 +231,13 @@ struct voicebus {
#define VBUNLOCK_FROM_DEFERRED(_vb_) spin_lock(&((_vb_)->lock))
#endif
-#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
+#define LATENCY_LOCKED 6
#if VOICEBUS_DEFERRED == WORKQUEUE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
@@ -257,32 +268,9 @@ vb_set_workqueue_priority(struct voicebus *vb)
#endif
#endif
-#ifdef DBG
-static inline int
-assert_in_vb_deferred(struct voicebus *vb)
-{
- assert(test_bit(IN_DEFERRED_PROCESSING, &vb->flags));
-}
-
-static inline void
-start_vb_deferred(struct voicebus *vb)
-{
- set_bit(IN_DEFERRED_PROCESSING, &vb->flags);
-}
-
-static inline void
-stop_vb_deferred(struct voicebus *vb)
-{
- clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
-}
-#else
-#define assert_in_vb_deferred(_x_) do {; } while (0)
-#define start_vb_deferred(_x_) do {; } while (0)
-#define stop_vb_deferred(_x_) do {; } while (0)
-#endif
-
static inline struct voicebus_descriptor *
-vb_descriptor(struct voicebus_descriptor_list *dl, int index)
+vb_descriptor(const struct voicebus_descriptor_list *dl,
+ const unsigned int index)
{
struct voicebus_descriptor *d;
d = (struct voicebus_descriptor *)((u8*)dl->desc +
@@ -298,7 +286,7 @@ vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *
struct voicebus_descriptor *d;
const u32 END_OF_RING = 0x02000000;
- assert(dl);
+ BUG_ON(!dl);
/*
* Add some padding to each descriptor to ensure that they are
@@ -324,16 +312,55 @@ vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *
d->des1 = des1;
}
d->des1 |= cpu_to_le32(END_OF_RING);
- dl->direction = direction;
atomic_set(&dl->count, 0);
return 0;
}
+#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
+#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0)
+
static int
vb_initialize_tx_descriptors(struct voicebus *vb)
{
- return vb_initialize_descriptors(
- vb, &vb->txd, 0xe4800000 | vb->framesize, DMA_TO_DEVICE);
+ int i;
+ int des1 = 0xe4800000 | vb->framesize;
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->txd;
+ const u32 END_OF_RING = 0x02000000;
+
+ WARN_ON(!dl);
+ WARN_ON((NULL == vb->idle_vbb) || (0 == vb->idle_vbb_dma_addr));
+
+ /*
+ * 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) ||
+ (0x20 == vb->cache_line_size)) {
+ dl->padding = (vb->cache_line_size*sizeof(u32)) - sizeof(*d);
+ } else {
+ dl->padding = 0;
+ }
+
+ dl->desc = pci_alloc_consistent(vb->pdev,
+ (sizeof(*d) + dl->padding) *
+ DRING_SIZE, &dl->desc_dma);
+ if (!dl->desc)
+ return -ENOMEM;
+
+ memset(dl->desc, 0, (sizeof(*d) + dl->padding) * DRING_SIZE);
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ d->des1 = des1;
+ d->buffer1 = vb->idle_vbb_dma_addr;
+ dl->pending[i] = vb->idle_vbb;
+ SET_OWNED(d);
+ }
+ d->des1 |= cpu_to_le32(END_OF_RING);
+ atomic_set(&dl->count, 0);
+ return 0;
}
static int
@@ -358,10 +385,10 @@ voicebus_set_minlatency(struct voicebus *vb, unsigned int ms)
*/
#define MESSAGE "%d ms is an invalid value for minumum latency. Setting to %d ms.\n"
if (DRING_SIZE < ms) {
- VB_PRINTK(vb, WARNING, MESSAGE, ms, DRING_SIZE);
+ dev_warn(&vb->pdev->dev, MESSAGE, ms, DRING_SIZE);
return -EINVAL;
} else if (VOICEBUS_DEFAULT_LATENCY > ms) {
- VB_PRINTK(vb, WARNING, MESSAGE, ms, VOICEBUS_DEFAULT_LATENCY);
+ dev_warn(&vb->pdev->dev, MESSAGE, ms, VOICEBUS_DEFAULT_LATENCY);
return -EINVAL;
}
VBLOCK(vb);
@@ -419,6 +446,36 @@ voicebus_current_latency(struct voicebus *vb)
}
EXPORT_SYMBOL(voicebus_current_latency);
+/**
+ * voicebus_lock_latency() - Do not increase the latency during underruns.
+ *
+ */
+void voicebus_lock_latency(struct voicebus *vb)
+{
+ set_bit(LATENCY_LOCKED, &vb->flags);
+}
+EXPORT_SYMBOL(voicebus_lock_latency);
+
+/**
+ * voicebus_unlock_latency() - Bump up the latency during underruns.
+ *
+ */
+void voicebus_unlock_latency(struct voicebus *vb)
+{
+ clear_bit(LATENCY_LOCKED, &vb->flags);
+}
+EXPORT_SYMBOL(voicebus_unlock_latency);
+
+/**
+ * voicebus_is_latency_locked() - Return 1 if latency is currently locked.
+ *
+ */
+int voicebus_is_latency_locked(const struct voicebus *vb)
+{
+ return test_bit(LATENCY_LOCKED, &vb->flags);
+}
+EXPORT_SYMBOL(voicebus_is_latency_locked);
+
/*!
* \brief Read one of the hardware control registers without acquiring locks.
*/
@@ -460,18 +517,48 @@ vb_is_stopped(struct voicebus *vb)
}
static void
-vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+vb_cleanup_tx_descriptors(struct voicebus *vb)
+{
+ unsigned int i;
+ struct voicebus_descriptor_list *dl = &vb->txd;
+ struct voicebus_descriptor *d;
+
+ BUG_ON(!vb_is_stopped(vb));
+
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ if (d->buffer1 && (d->buffer1 != vb->idle_vbb_dma_addr)) {
+ WARN_ON(!dl->pending[i]);
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_TO_DEVICE);
+ voicebus_free(vb, dl->pending[i]);
+ }
+ 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;
+ atomic_set(&dl->count, 0);
+}
+
+static void
+vb_cleanup_rx_descriptors(struct voicebus *vb)
{
unsigned int i;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
struct voicebus_descriptor *d;
- assert(vb_is_stopped(vb));
+ BUG_ON(!vb_is_stopped(vb));
for (i = 0; i < DRING_SIZE; ++i) {
d = vb_descriptor(dl, i);
if (d->buffer1) {
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_FROM_DEVICE);
d->buffer1 = 0;
- assert(dl->pending[i]);
+ BUG_ON(!dl->pending[i]);
voicebus_free(vb, dl->pending[i]);
dl->pending[i] = NULL;
}
@@ -482,6 +569,15 @@ vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
atomic_set(&dl->count, 0);
}
+static void vb_cleanup_descriptors(struct voicebus *vb,
+ struct voicebus_descriptor_list *dl)
+{
+ if (dl == &vb->txd)
+ vb_cleanup_tx_descriptors(vb);
+ else
+ vb_cleanup_rx_descriptors(vb);
+}
+
static void
vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
{
@@ -519,30 +615,30 @@ vb_setctl(struct voicebus *vb, u32 addr, u32 val)
}
static int
-__vb_sdi_clk(struct voicebus *vb)
+__vb_sdi_clk(struct voicebus *vb, u32 *sdi)
{
unsigned int ret;
- vb->sdi &= ~CSR9_MDC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+ *sdi &= ~CSR9_MDC;
+ __vb_setctl(vb, 0x0048, *sdi);
ret = __vb_getctl(vb, 0x0048);
- vb->sdi |= CSR9_MDC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+ *sdi |= CSR9_MDC;
+ __vb_setctl(vb, 0x0048, *sdi);
return (ret & CSR9_MDI) ? 1 : 0;
}
static void
-__vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count)
+__vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count, u32 *sdi)
{
- vb->sdi &= ~CSR9_MMC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+ *sdi &= ~CSR9_MMC;
+ __vb_setctl(vb, 0x0048, *sdi);
while (count--) {
if (bits & (1 << count))
- vb->sdi |= CSR9_MDO;
+ *sdi |= CSR9_MDO;
else
- vb->sdi &= ~CSR9_MDO;
+ *sdi &= ~CSR9_MDO;
- __vb_sdi_clk(vb);
+ __vb_sdi_clk(vb, sdi);
}
}
@@ -551,13 +647,14 @@ vb_setsdi(struct voicebus *vb, int addr, u16 val)
{
LOCKS_VOICEBUS;
u32 bits;
+ u32 sdi = 0;
/* Send preamble */
bits = 0xffffffff;
VBLOCK(vb);
- __vb_sdi_sendbits(vb, bits, 32);
+ __vb_sdi_sendbits(vb, bits, 32, &sdi);
bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2;
- __vb_sdi_sendbits(vb, bits, 16);
- __vb_sdi_sendbits(vb, val, 16);
+ __vb_sdi_sendbits(vb, bits, 16, &sdi);
+ __vb_sdi_sendbits(vb, val, 16, &sdi);
VBUNLOCK(vb);
}
@@ -566,7 +663,7 @@ vb_enable_io_access(struct voicebus *vb)
{
LOCKS_VOICEBUS;
u32 reg;
- assert(vb->pdev);
+ BUG_ON(!vb->pdev);
VBLOCK(vb);
pci_read_config_dword(vb->pdev, 0x0004, &reg);
reg |= 0x00000007;
@@ -620,11 +717,12 @@ vb_reset_interface(struct voicebus *vb)
pci_access = DEFAULT_PCI_ACCESS | (0x3 << 14);
break;
default:
- if (atomic_read(&vb->debuglevel))
- VB_PRINTK(vb, WARNING, "Host system set a cache size "\
- "of %d which is not supported. " \
- "Disabling memory write line and memory read line.\n",
- vb->cache_line_size);
+ if (atomic_read(&vb->debuglevel)) {
+ dev_warn(&vb->pdev->dev, "Host system set a cache "
+ "size of %d which is not supported. "
+ "Disabling memory write line and memory "
+ "read line.\n", vb->cache_line_size);
+ }
pci_access = 0xfe584202;
break;
}
@@ -640,8 +738,8 @@ vb_reset_interface(struct voicebus *vb)
} while ((reg & 0x00000001) && time_before(jiffies, timeout));
if (reg & 0x00000001) {
- VB_PRINTK(vb, ERR, "Hardware did not come out of reset "\
- "within 100ms!");
+ dev_warn(&vb->pdev->dev, "Hardware did not come out of reset "
+ "within 100ms!");
return -EIO;
}
@@ -655,8 +753,8 @@ vb_initialize_interface(struct voicebus *vb)
{
u32 reg;
- vb_cleanup_descriptors(vb, &vb->txd);
- vb_cleanup_descriptors(vb, &vb->rxd);
+ vb_cleanup_tx_descriptors(vb);
+ vb_cleanup_rx_descriptors(vb);
/* Pass bad packets, runt packets, disable SQE function,
* store-and-forward */
@@ -689,12 +787,9 @@ vb_initialize_interface(struct voicebus *vb)
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)
+dump_descriptor(struct voicebus *vb, struct voicebus_descriptor *d)
{
VB_PRINTK(vb, DEBUG, "Displaying descriptor at address %08x\n", (unsigned int)d);
VB_PRINTK(vb, DEBUG, " des0: %08x\n", d->des0);
@@ -720,61 +815,32 @@ show_buffer(struct voicebus *vb, void *vbb)
}
#endif
-static inline int
-vb_submit(struct voicebus *vb, struct voicebus_descriptor_list *dl, void *vbb)
+/**
+ * voicebus_transmit - Queue a buffer on the hardware descriptor ring.
+ *
+ */
+int voicebus_transmit(struct voicebus *vb, void *vbb)
{
- volatile struct voicebus_descriptor *d;
- unsigned int tail = dl->tail;
- assert_in_vb_deferred(vb);
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->txd;
- d = vb_descriptor(dl, tail);
+ d = vb_descriptor(dl, dl->tail);
- if (unlikely(d->buffer1)) {
- /* Do not overwrite a buffer that is still in progress. */
- WARN_ON(1);
+ if (unlikely(d->buffer1 != vb->idle_vbb_dma_addr)) {
+ if (printk_ratelimit())
+ dev_warn(&vb->pdev->dev, "Dropping tx buffer buffer\n");
voicebus_free(vb, vbb);
- return -EBUSY;
+ return -EFAULT;
}
- dl->pending[tail] = vbb;
- dl->tail = (++tail) & DRING_MASK;
- d->buffer1 = dma_map_single(
- &vb->pdev->dev, vbb, vb->framesize, dl->direction);
+ dl->pending[dl->tail] = vbb;
+ dl->tail = (++(dl->tail)) & DRING_MASK;
+ d->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
+ vb->framesize, DMA_TO_DEVICE);
SET_OWNED(d); /* That's it until the hardware is done with it. */
atomic_inc(&dl->count);
return 0;
}
-
-static inline void*
-vb_retrieve(struct voicebus *vb, struct voicebus_descriptor_list *dl)
-{
- volatile struct voicebus_descriptor *d;
- void *vbb;
- unsigned int head = dl->head;
- assert_in_vb_deferred(vb);
- d = vb_descriptor(dl, head);
- if (d->buffer1 && !OWNED(d)) {
- dma_unmap_single(&vb->pdev->dev, d->buffer1,
- vb->framesize, dl->direction);
- vbb = dl->pending[head];
- dl->head = (++head) & DRING_MASK;
- d->buffer1 = 0;
- atomic_dec(&dl->count);
- return vbb;
- } else {
- return NULL;
- }
-}
-
-/*!
- * \brief Give a frame to the hardware to transmit.
- *
- */
-int
-voicebus_transmit(struct voicebus *vb, void *vbb)
-{
- return vb_submit(vb, &vb->txd, vbb);
-}
EXPORT_SYMBOL(voicebus_transmit);
/*!
@@ -784,7 +850,26 @@ EXPORT_SYMBOL(voicebus_transmit);
static inline int
vb_submit_rxb(struct voicebus *vb, void *vbb)
{
- return vb_submit(vb, &vb->rxd, vbb);
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
+ unsigned int tail = dl->tail;
+
+ d = vb_descriptor(dl, tail);
+
+ if (unlikely(d->buffer1)) {
+ /* Do not overwrite a buffer that is still in progress. */
+ WARN_ON(1);
+ voicebus_free(vb, vbb);
+ return -EBUSY;
+ }
+
+ dl->pending[tail] = vbb;
+ dl->tail = (++tail) & DRING_MASK;
+ d->buffer1 = dma_map_single(&vb->pdev->dev, vbb,
+ vb->framesize, DMA_FROM_DEVICE);
+ SET_OWNED(d); /* That's it until the hardware is done with it. */
+ atomic_inc(&dl->count);
+ return 0;
}
/*!
@@ -803,13 +888,47 @@ vb_submit_rxb(struct voicebus *vb, void *vbb)
static inline void *
vb_get_completed_txb(struct voicebus *vb)
{
- return vb_retrieve(vb, &vb->txd);
+ struct voicebus_descriptor_list *dl = &vb->txd;
+ struct voicebus_descriptor *d;
+ void *vbb;
+ unsigned int head = dl->head;
+
+ d = vb_descriptor(dl, head);
+
+ if (OWNED(d) || (d->buffer1 == vb->idle_vbb_dma_addr))
+ return NULL;
+
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_TO_DEVICE);
+
+ vbb = dl->pending[head];
+ dl->head = (++head) & DRING_MASK;
+ d->buffer1 = vb->idle_vbb_dma_addr;
+ SET_OWNED(d);
+ atomic_dec(&dl->count);
+ return vbb;
}
static inline void *
vb_get_completed_rxb(struct voicebus *vb)
{
- return vb_retrieve(vb, &vb->rxd);
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
+ unsigned int head = dl->head;
+ void *vbb;
+
+ d = vb_descriptor(dl, head);
+
+ if ((0 == d->buffer1) || OWNED(d))
+ return NULL;
+
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, DMA_FROM_DEVICE);
+ vbb = dl->pending[head];
+ dl->head = (++head) & DRING_MASK;
+ d->buffer1 = 0;
+ atomic_dec(&dl->count);
+ return vbb;
}
/*!
@@ -905,7 +1024,9 @@ voicebus_start(struct voicebus *vb)
void *vbb;
int ret;
- assert(!in_interrupt());
+ WARN_ON(pci_get_drvdata(vb->pdev) != vb);
+ if (pci_get_drvdata(vb->pdev) != vb)
+ return -EFAULT;
if (!vb_is_stopped(vb))
return -EBUSY;
@@ -928,7 +1049,6 @@ voicebus_start(struct voicebus *vb)
* is known to not be running at this point, it is safe to call the
* handle transmit as if it were.
*/
- start_vb_deferred(vb);
/* Ensure that all the rx slots are ready for a buffer. */
for (i = 0; i < DRING_SIZE; ++i) {
vbb = voicebus_alloc(vb);
@@ -947,10 +1067,9 @@ voicebus_start(struct voicebus *vb)
if (unlikely(NULL == vbb))
BUG_ON(1);
else
- vb->handle_transmit(vbb, vb->context);
+ handle_transmit(vb, vbb);
}
- stop_vb_deferred(vb);
VBLOCK(vb);
clear_bit(STOP, &vb->flags);
@@ -971,7 +1090,7 @@ voicebus_start(struct voicebus *vb)
__vb_tx_demand_poll(vb);
VBUNLOCK(vb);
- assert(!vb_is_stopped(vb));
+ BUG_ON(vb_is_stopped(vb));
return 0;
}
@@ -1033,8 +1152,6 @@ vb_wait_for_completion_timeout(struct completion *x, unsigned long timeout)
int
voicebus_stop(struct voicebus *vb)
{
- assert(!in_interrupt());
-
if (vb_is_stopped(vb))
return 0;
@@ -1043,11 +1160,10 @@ voicebus_stop(struct voicebus *vb)
vb_clear_start_transmit_bit(vb);
vb_clear_start_receive_bit(vb);
if (vb_wait_for_completion_timeout(&vb->stopped_completion, HZ)) {
- assert(vb_is_stopped(vb));
+ BUG_ON(!vb_is_stopped(vb));
} else {
- VB_PRINTK(vb, WARNING, "Timeout while waiting for board to "\
- "stop.\n");
-
+ 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);
@@ -1063,6 +1179,24 @@ voicebus_stop(struct voicebus *vb)
}
EXPORT_SYMBOL(voicebus_stop);
+#ifdef CONFIG_VOICEBUS_SYSFS
+static ssize_t
+voicebus_current_latency_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ struct voicebus *vb = dev_get_drvdata(dev);
+ unsigned int current_latency;
+ spin_lock_irqsave(&vb->lock, flags);
+ current_latency = vb->min_tx_buffer_count;
+ spin_unlock_irqrestore(&vb->lock, flags);
+ return sprintf(buf, "%d\n", current_latency);
+}
+
+DEVICE_ATTR(voicebus_current_latency, 0444,
+ voicebus_current_latency_show, NULL);
+#endif
+
/*!
* \brief Prepare the interface for module unload.
*
@@ -1075,7 +1209,9 @@ EXPORT_SYMBOL(voicebus_stop);
void
voicebus_release(struct voicebus *vb)
{
- assert(!in_interrupt());
+#ifdef CONFIG_VOICEBUS_SYSFS
+ device_remove_file(&vb->pdev->dev, &dev_attr_voicebus_current_latency);
+#endif
/* quiesce the hardware */
voicebus_stop(vb);
@@ -1092,6 +1228,10 @@ voicebus_release(struct voicebus *vb)
/* Cleanup memory and software resources. */
vb_free_descriptors(vb, &vb->txd);
vb_free_descriptors(vb, &vb->rxd);
+ if (vb->idle_vbb_dma_addr) {
+ dma_free_coherent(&vb->pdev->dev, vb->framesize,
+ vb->idle_vbb, vb->idle_vbb_dma_addr);
+ }
kmem_cache_destroy(vb->buffer_cache);
release_region(vb->iobase, 0xff);
pci_disable_device(vb->pdev);
@@ -1100,103 +1240,291 @@ voicebus_release(struct voicebus *vb)
EXPORT_SYMBOL(voicebus_release);
static void
-__vb_increase_latency(struct voicebus *vb)
+vb_increase_latency(struct voicebus *vb, unsigned int increase)
{
- static int __warn_once = 1;
void *vbb;
- int latency;
+ int i;
- assert_in_vb_deferred(vb);
+ if (0 == increase)
+ return;
- latency = atomic_read(&vb->txd.count);
- if (DRING_SIZE == latency) {
- if (__warn_once) {
- /* We must subtract two from this number since there
- * are always two buffers in the TX FIFO.
- */
- VB_PRINTK(vb, ERR,
- "ERROR: Unable to service card within %d ms "\
- "and unable to further increase latency.\n",
- DRING_SIZE-2);
- __warn_once = 0;
- }
- } else {
- /* Because there are 2 buffers in the transmit FIFO on the
- * hardware, setting 3 ms of latency means that the host needs
- * to be able to service the cards within 1ms. This is because
- * the interface will load up 2 buffers into the TX FIFO then
- * attempt to read the 3rd descriptor. If the OWN bit isn't
- * set, then the hardware will set the TX descriptor not
- * available interrupt.
- */
- VB_PRINTK(vb, INFO, "Missed interrupt. " \
- "Increasing latency to %d ms in order to compensate.\n",
- latency+1);
- /* 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);
+ if (test_bit(LATENCY_LOCKED, &vb->flags))
+ return;
+
+ if (unlikely(increase > VOICEBUS_MAXLATENCY_BUMP))
+ increase = VOICEBUS_MAXLATENCY_BUMP;
+
+ if ((increase + vb->min_tx_buffer_count) > vb->max_latency)
+ increase = vb->max_latency - vb->min_tx_buffer_count;
+
+ /* Because there are 2 buffers in the transmit FIFO on the hardware,
+ * setting 3 ms of latency means that the host needs to be able to
+ * service the cards within 1ms. This is because the interface will
+ * load up 2 buffers into the TX FIFO then attempt to read the 3rd
+ * descriptor. If the OWN bit isn't set, then the hardware will set the
+ * TX descriptor not available interrupt. */
+
+ /* 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);
+ WARN_ON(NULL == vbb);
+ if (likely(NULL != vbb))
+ handle_transmit(vb, vbb);
+ }
- if (unlikely(NULL == vbb))
- BUG_ON(1);
- else
- vb->handle_transmit(vbb, vb->context);
+ /* 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,
+ struct voicebus_descriptor_list *dl)
+{
+ int i;
+ struct voicebus_descriptor *d;
+
+ for (i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ SET_OWNED(d);
}
}
-/*!
- * \brief Actually process the completed transmit and receive buffers.
+static inline void vb_set_all_tx_owned(struct voicebus *vb)
+{
+ vb_set_all_owned(vb, &vb->txd);
+}
+
+/**
+ * __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.
*
- * NOTE: This function may be called either from a tasklet, workqueue, or
- * directly in the interrupt service routine depending on
- * VOICEBUS_DEFERRED.
+ * 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 inline void
-vb_deferred(struct voicebus *vb)
+static unsigned int __vb_get_default_behind_count(const struct voicebus *vb)
{
- void *vbb;
-#ifdef DBG
- static int count;
-#endif
+ 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)
+{
+ 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,
+ vb->framesize, 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;
+
int underrun = test_bit(TX_UNDERRUN, &vb->flags);
+ buffer_count = 0;
- start_vb_deferred(vb);
- if (unlikely(underrun)) {
- /* When we've underrun our FIFO, for some reason we're not
- * able to keep enough transmit descriptors pending. This can
- * happen if either interrupts or this deferred processing
- * function is not run soon enough (within 1ms when using the
- * default 3 transmit buffers to start). In this case, we'll
- * insert an additional transmit buffer onto the descriptor
- * list which decreases the sensitivity to latency, but also
- * adds more delay to the TDM and SPI data.
- */
- __vb_increase_latency(vb);
+ /* 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 ((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;
+ }
}
- /* Always handle the transmit buffers first. */
- while ((vbb = vb_get_completed_txb(vb)))
- vb->handle_transmit(vbb, vb->context);
+ 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]);
+
+ /* If underrun is set, it means that the hardware signalled that it
+ * completely ran out of transmit descriptors. This is what we are
+ * trying to avoid with all this racy softunderun business, but alas,
+ * it's still possible to happen if interrupts are locked longer than
+ * DRING_SIZE milliseconds for some reason. We should have already fixed
+ * up the descriptor ring in this case, so let's just tell the hardware
+ * to reread what it believes the next descriptor is. */
if (unlikely(underrun)) {
+ if (printk_ratelimit()) {
+ dev_info(&vb->pdev->dev, "Host failed to service "
+ "card interrupt within %d ms which is a "
+ "hardunderun.\n", DRING_SIZE);
+ }
vb_rx_demand_poll(vb);
vb_tx_demand_poll(vb);
clear_bit(TX_UNDERRUN, &vb->flags);
}
- while ((vbb = vb_get_completed_rxb(vb))) {
- vb->handle_receive(vbb, vb->context);
- vb_submit_rxb(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(softunderrun &&
+ !test_bit(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);
+ }
}
- stop_vb_deferred(vb);
+ /* 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->handle_receive(vb->vbb_stash[0], vb->context);
+ --vb->count;
+ }
+ vb_submit_rxb(vb, vb->vbb_stash[0]);
+ }
}
-
/*!
* \brief Interrupt handler for VoiceBus interface.
*
@@ -1262,15 +1590,15 @@ vb_isr(int irq, void *dev_id)
}
if (int_status & FATAL_BUS_ERROR_INTERRUPT)
- VB_PRINTK(vb, ERR, "Fatal Bus Error detected!\n");
+ dev_err(&vb->pdev->dev, "Fatal Bus Error detected!\n");
if (int_status & TX_STOPPED_INTERRUPT) {
- assert(test_bit(STOP, &vb->flags));
+ BUG_ON(!test_bit(STOP, &vb->flags));
__vb_disable_interrupts(vb);
complete(&vb->stopped_completion);
}
if (int_status & RX_STOPPED_INTERRUPT) {
- assert(test_bit(STOP, &vb->flags));
+ BUG_ON(!test_bit(STOP, &vb->flags));
if (vb_is_stopped(vb)) {
__vb_disable_interrupts(vb);
complete(&vb->stopped_completion);
@@ -1334,8 +1662,7 @@ vb_tasklet(unsigned long data)
* \todo Complete this description.
*/
int
-voicebus_init(struct pci_dev *pdev, u32 framesize,
- const char *board_name,
+voicebus_init(struct pci_dev *pdev, u32 framesize, const char *board_name,
void (*handle_receive)(void *vbb, void *context),
void (*handle_transmit)(void *vbb, void *context),
void *context,
@@ -1346,11 +1673,11 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
int retval = 0;
struct voicebus *vb;
- assert(NULL != pdev);
- assert(NULL != board_name);
- assert(framesize);
- assert(NULL != handle_receive);
- assert(NULL != handle_transmit);
+ BUG_ON(NULL == pdev);
+ BUG_ON(NULL == board_name);
+ BUG_ON(0 == framesize);
+ BUG_ON(NULL == handle_receive);
+ BUG_ON(NULL == handle_transmit);
/* ----------------------------------------------------------------
Initialize the pure software constructs.
@@ -1358,20 +1685,19 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
*vbp = NULL;
vb = kmalloc(sizeof(*vb), GFP_KERNEL);
if (NULL == vb) {
- VB_PRINTK(vb, DEBUG, "Failed to allocate memory for voicebus "\
- "interface.\n");
+ dev_dbg(&vb->pdev->dev, "Failed to allocate memory for "
+ "voicebus interface.\n");
retval = -ENOMEM;
goto cleanup;
}
memset(vb, 0, sizeof(*vb));
+ vb->pdev = pdev;
+ pci_set_drvdata(pdev, vb);
voicebus_setdebuglevel(vb, debuglevel);
- /* \todo make sure there is a note that the caller needs to make sure
- * board_name stays in memory until voicebus_release is called.
- */
- vb->board_name = board_name;
+ vb->max_latency = VOICEBUS_DEFAULT_MAXLATENCY;
+
spin_lock_init(&vb->lock);
init_completion(&vb->stopped_completion);
- vb->pdev = pdev;
set_bit(STOP, &vb->flags);
clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
vb->framesize = framesize;
@@ -1413,26 +1739,46 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
SLAB_HWCACHE_ALIGN, NULL, NULL);
#endif
#else
+#ifdef DEBUG
+ vb->buffer_cache = kmem_cache_create(board_name, vb->framesize, 0,
+ SLAB_HWCACHE_ALIGN | SLAB_STORE_USER |
+ SLAB_POISON | SLAB_DEBUG_FREE, NULL);
+#else
vb->buffer_cache = kmem_cache_create(board_name, vb->framesize, 0,
SLAB_HWCACHE_ALIGN, NULL);
#endif
+#endif
if (NULL == vb->buffer_cache) {
- VB_PRINTK(vb, ERR, "Failed to allocate buffer cache.\n");
+ dev_err(&vb->pdev->dev, "Failed to allocate buffer cache.\n");
goto cleanup;
}
-
+#ifdef CONFIG_VOICEBUS_SYSFS
+ dev_dbg(&vb->pdev->dev, "Creating sysfs attributes.\n");
+ retval = device_create_file(&vb->pdev->dev,
+ &dev_attr_voicebus_current_latency);
+ if (retval) {
+ dev_dbg(&vb->pdev->dev,
+ "Failed to create device attributes.\n");
+ goto cleanup;
+ }
+#endif
/* ----------------------------------------------------------------
Configure the hardware / kernel module interfaces.
---------------------------------------------------------------- */
+ if (pci_set_dma_mask(vb->pdev, DMA_BIT_MASK(32))) {
+ dev_err(&vb->pdev->dev, "No suitable DMA available.\n");
+ goto cleanup;
+ }
+
if (pci_read_config_byte(vb->pdev, 0x0c, &vb->cache_line_size)) {
- VB_PRINTK(vb, ERR, "Failed read of cache line " \
- "size from PCI configuration space.\n");
+ dev_err(&vb->pdev->dev, "Failed read of cache line "
+ "size from PCI configuration space.\n");
goto cleanup;
}
if (pci_enable_device(pdev)) {
- VB_PRINTK(vb, ERR, "Failed call to pci_enable_device.\n");
+ dev_err(&vb->pdev->dev, "Failed call to pci_enable_device.\n");
retval = -EIO;
goto cleanup;
}
@@ -1440,18 +1786,21 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
/* \todo This driver should be modified to use the memory mapped I/O
as opposed to IO space for portability and performance. */
if (0 == (pci_resource_flags(pdev, 0)&IORESOURCE_IO)) {
- VB_PRINTK(vb, ERR, "BAR0 is not IO Memory.\n");
+ dev_err(&vb->pdev->dev, "BAR0 is not IO Memory.\n");
retval = -EIO;
goto cleanup;
}
vb->iobase = pci_resource_start(pdev, 0);
if (NULL == request_region(vb->iobase, 0xff, board_name)) {
- VB_PRINTK(vb, ERR, "IO Registers are in use by another " \
+ dev_err(&vb->pdev->dev, "IO Registers are in use by another "
"module.\n");
retval = -EIO;
goto cleanup;
}
+ vb->idle_vbb = dma_alloc_coherent(&vb->pdev->dev, vb->framesize,
+ &vb->idle_vbb_dma_addr, GFP_KERNEL);
+
retval = vb_initialize_tx_descriptors(vb);
if (retval)
goto cleanup;
@@ -1463,18 +1812,20 @@ voicebus_init(struct pci_dev *pdev, u32 framesize,
/* ----------------------------------------------------------------
Configure the hardware interface.
---------------------------------------------------------------- */
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ release_region(vb->iobase, 0xff);
+ dev_warn(&vb->pdev->dev, "No suitable DMA available.\n");
+ goto cleanup;
+ }
+
pci_set_master(pdev);
vb_enable_io_access(vb);
#if VOICEBUS_DEFERRED != TIMER
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-# define VB_IRQ_SHARED SA_SHIRQ
-#else
-# define VB_IRQ_SHARED IRQF_SHARED
-#endif
- if (request_irq(pdev->irq, vb_isr, VB_IRQ_SHARED, vb->board_name,
- vb)) {
- assert(0);
+ retval = request_irq(pdev->irq, vb_isr, DAHDI_IRQ_SHARED,
+ board_name, vb);
+ if (retval) {
+ dev_warn(&vb->pdev->dev, "Failed to request interrupt line.\n");
goto cleanup;
}
#endif
@@ -1501,6 +1852,9 @@ cleanup:
if (vb->rxd.desc)
vb_free_descriptors(vb, &vb->rxd);
+ dma_free_coherent(&vb->pdev->dev, vb->framesize,
+ vb->idle_vbb, vb->idle_vbb_dma_addr);
+
if (vb->buffer_cache)
kmem_cache_destroy(vb->buffer_cache);
@@ -1511,7 +1865,7 @@ cleanup:
pci_disable_device(vb->pdev);
kfree(vb);
- assert(0 != retval);
+ WARN_ON(0 == retval);
return retval;
}
EXPORT_SYMBOL(voicebus_init);
@@ -1525,6 +1879,12 @@ voicebus_get_pci_dev(struct voicebus *vb)
}
EXPORT_SYMBOL(voicebus_get_pci_dev);
+void *voicebus_pci_dev_to_context(struct pci_dev *pdev)
+{
+ return ((struct voicebus *)pci_get_drvdata(pdev))->context;
+}
+EXPORT_SYMBOL(voicebus_pci_dev_to_context);
+
static spinlock_t loader_list_lock;
static struct list_head binary_loader_list;
@@ -1560,12 +1920,14 @@ int vpmadtreg_loadfirmware(struct voicebus *vb)
module_put(loader->owner);
} else {
spin_unlock(&loader_list_lock);
- printk(KERN_INFO "Failed to find a registered loader after loading module.\n");
+ dev_info(&vb->pdev->dev, "Failed to find a "
+ "registered loader after loading module.\n");
ret = -ENODEV;
}
} else {
spin_unlock(&loader_list_lock);
- printk(KERN_INFO "Failed to find a registered loader after loading module.\n");
+ dev_info(&vb->pdev->dev, "Failed to find a registered "
+ "loader after loading module.\n");
ret = -1;
}
return ret;