[dahdi-commits] fjoe: freebsd/trunk r7669 - in /freebsd/trunk: ./ drivers/dahdi/ drivers/dahd...
SVN commits to the DAHDI project
dahdi-commits at lists.digium.com
Tue Dec 8 10:40:19 CST 2009
Author: fjoe
Date: Tue Dec 8 10:40:14 2009
New Revision: 7669
URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=7669
Log:
Merge up to rev. 7668 from linux/trunk.
Removed:
freebsd/trunk/drivers/dahdi/xpp/.version
Modified:
freebsd/trunk/ (props changed)
freebsd/trunk/drivers/dahdi/dahdi-base.c
freebsd/trunk/drivers/dahdi/voicebus/GpakCust.c
freebsd/trunk/drivers/dahdi/voicebus/GpakCust.h
freebsd/trunk/drivers/dahdi/voicebus/voicebus.c
freebsd/trunk/drivers/dahdi/voicebus/voicebus.h
freebsd/trunk/drivers/dahdi/vpmadt032_loader/dahdi_vpmadt032_loader.c
freebsd/trunk/drivers/dahdi/wcb4xxp/Makefile (props changed)
freebsd/trunk/drivers/dahdi/wcb4xxp/base.c
freebsd/trunk/drivers/dahdi/wcb4xxp/wcb4xxp.h
freebsd/trunk/drivers/dahdi/wct4xxp/base.c
freebsd/trunk/drivers/dahdi/wctdm24xxp/base.c
freebsd/trunk/drivers/dahdi/wcte12xp/base.c
freebsd/trunk/drivers/dahdi/wcte12xp/wcte12xp.h
freebsd/trunk/drivers/dahdi/xpp/card_bri.c
freebsd/trunk/drivers/dahdi/xpp/card_global.c
freebsd/trunk/drivers/dahdi/xpp/card_pri.c
freebsd/trunk/drivers/dahdi/xpp/firmwares/PIC_TYPE_1.hex
freebsd/trunk/drivers/dahdi/xpp/firmwares/USB_FW.hex
freebsd/trunk/drivers/dahdi/xpp/xbus-pcm.c
freebsd/trunk/drivers/dahdi/xpp/xbus-pcm.h
freebsd/trunk/drivers/dahdi/xpp/xbus-sysfs.c
freebsd/trunk/drivers/dahdi/xpp/xpp.rules
freebsd/trunk/firmware.mk
freebsd/trunk/include/dahdi/kernel.h
Propchange: freebsd/trunk/
------------------------------------------------------------------------------
svn:mergeinfo = /linux/trunk:7418-7668
Modified: freebsd/trunk/drivers/dahdi/dahdi-base.c
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=7669&r1=7668&r2=7669
==============================================================================
--- freebsd/trunk/drivers/dahdi/dahdi-base.c (original)
+++ freebsd/trunk/drivers/dahdi/dahdi-base.c Tue Dec 8 10:40:14 2009
@@ -8580,6 +8580,7 @@
const unsigned long MAX_INTERVAL = 100000L;
const unsigned long FOURMS_INTERVAL = HZ/250;
const unsigned long ONESEC_INTERVAL = HZ;
+ const unsigned long MS_LIMIT = 3000;
now = current_kernel_time();
@@ -8594,6 +8595,23 @@
mod_timer(&core_timer.timer, jiffies + FOURMS_INTERVAL);
ms_since_start = core_diff_ms(&core_timer.start_interval, &now);
+
+ /*
+ * If the system time has changed, it is possible for us to be
+ * far behind. If we are more than MS_LIMIT milliseconds
+ * behind, just reset our time base and continue so that we do
+ * not hang the system here.
+ *
+ */
+ if (unlikely((ms_since_start - atomic_read(&core_timer.count)) > MS_LIMIT)) {
+ if (printk_ratelimit())
+ module_printk(KERN_INFO, "Detected time shift.\n");
+ atomic_set(&core_timer.count, 0);
+ atomic_set(&core_timer.last_count, 0);
+ core_timer.start_interval = now;
+ return;
+ }
+
while (ms_since_start > atomic_read(&core_timer.count))
process_masterspan();
Modified: freebsd/trunk/drivers/dahdi/voicebus/GpakCust.c
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/voicebus/GpakCust.c?view=diff&rev=7669&r1=7668&r2=7669
==============================================================================
--- freebsd/trunk/drivers/dahdi/voicebus/GpakCust.c (original)
+++ freebsd/trunk/drivers/dahdi/voicebus/GpakCust.c Tue Dec 8 10:40:14 2009
@@ -52,6 +52,9 @@
static rwlock_t ifacelock;
static struct vpmadt032 *ifaces[MAX_DSP_CORES];
+
+#define vpm_info(vpm, format, arg...) \
+ dev_info(&voicebus_get_pci_dev(vpm->vb)->dev , format , ## arg)
static inline struct vpmadt032 *find_iface(const unsigned short dspid)
{
@@ -212,26 +215,42 @@
return res;
}
-static int vpmadt032_enable_ec(struct vpmadt032 *vpm, int channel)
+struct change_order {
+ struct list_head node;
+ unsigned int channel;
+ struct adt_lec_params params;
+};
+
+static struct change_order *alloc_change_order(void)
+{
+ return kzalloc(sizeof(struct change_order), GFP_KERNEL);
+}
+
+static void free_change_order(struct change_order *order)
+{
+ kfree(order);
+}
+
+static int vpmadt032_enable_ec(struct vpmadt032 *vpm, int channel,
+ enum adt_companding companding)
{
int res;
GPAK_AlgControlStat_t pstatus;
GpakAlgCtrl_t control;
- control = (ADT_COMP_ALAW == vpm->desiredecstate[channel].companding) ?
- EnableALawSwCompanding :
- EnableMuLawSwCompanding;
+ control = (ADT_COMP_ALAW == companding) ? EnableALawSwCompanding :
+ EnableMuLawSwCompanding;
if (vpm->options.debug & DEBUG_ECHOCAN) {
const char *law;
law = (control == EnableMuLawSwCompanding) ? "MuLaw" : "ALaw";
- printk(KERN_DEBUG "Enabling ecan on channel: %d (%s)\n",
- channel, law);
+ vpm_info(vpm, "Enabling ecan on channel: %d (%s)\n",
+ channel, law);
}
res = gpakAlgControl(vpm->dspid, channel, control, &pstatus);
if (res) {
- printk(KERN_WARNING "Unable to set SW Companding on " \
- "channel %d (reason %d)\n", channel, res);
+ vpm_info(vpm, "Unable to set SW Companding on "
+ "channel %d (reason %d)\n", channel, res);
}
res = gpakAlgControl(vpm->dspid, channel, EnableEcanA, &pstatus);
return res;
@@ -243,16 +262,96 @@
GPAK_AlgControlStat_t pstatus;
if (vpm->options.debug & DEBUG_ECHOCAN)
- printk(KERN_DEBUG "Disabling ecan on channel: %d\n", channel);
+ vpm_info(vpm, "Disabling ecan on channel: %d\n", channel);
res = gpakAlgControl(vpm->dspid, channel, BypassSwCompanding, &pstatus);
if (res) {
- printk(KERN_WARNING "Unable to disable sw companding on " \
- "echo cancellation channel %d (reason %d)\n",
- channel, res);
+ vpm_info(vpm, "Unable to disable sw companding on "
+ "echo cancellation channel %d (reason %d)\n",
+ channel, res);
}
res = gpakAlgControl(vpm->dspid, channel, BypassEcanA, &pstatus);
return res;
+}
+
+static struct change_order *get_next_order(struct vpmadt032 *vpm)
+{
+ struct change_order *order;
+
+ spin_lock(&vpm->change_list_lock);
+ if (!list_empty(&vpm->change_list)) {
+ order = list_entry(vpm->change_list.next,
+ struct change_order, node);
+ list_del(&order->node);
+ } else {
+ order = NULL;
+ }
+ spin_unlock(&vpm->change_list_lock);
+
+ return order;
+}
+
+static int nlp_settings_changed(const struct adt_lec_params *a,
+ const struct adt_lec_params *b)
+{
+ return ((a->nlp_type != b->nlp_type) ||
+ (a->nlp_threshold != b->nlp_threshold) ||
+ (a->nlp_max_suppress != b->nlp_max_suppress));
+}
+
+static int echocan_on(const struct adt_lec_params *new,
+ const struct adt_lec_params *old)
+{
+ return ((new->tap_length != old->tap_length) &&
+ (new->tap_length > 0));
+}
+
+static int echocan_off(const struct adt_lec_params *new,
+ const struct adt_lec_params *old)
+{
+ return ((new->tap_length != old->tap_length) &&
+ (0 == new->tap_length));
+}
+
+static void update_channel_config(struct vpmadt032 *vpm, unsigned int channel,
+ struct adt_lec_params *desired)
+{
+ int res;
+ GPAK_AlgControlStat_t pstatus;
+ GPAK_ChannelConfigStat_t cstatus;
+ GPAK_TearDownChanStat_t tstatus;
+ GpakChannelConfig_t chanconfig;
+
+ if (vpm->options.debug & DEBUG_ECHOCAN) {
+ vpm_info(vpm, "Reconfiguring chan %d for nlp %d, "
+ "nlp_thresh %d, and max_supp %d\n", channel + 1,
+ desired->nlp_type, desired->nlp_threshold,
+ desired->nlp_max_suppress);
+ }
+
+ vpm->setchanconfig_from_state(vpm, channel, &chanconfig);
+
+ res = gpakTearDownChannel(vpm->dspid, channel, &tstatus);
+ if (res)
+ return;
+
+ res = gpakConfigureChannel(vpm->dspid, channel, tdmToTdm,
+ &chanconfig, &cstatus);
+ if (res)
+ return;
+
+ if (!desired->tap_length) {
+ res = gpakAlgControl(vpm->dspid, channel,
+ BypassSwCompanding, &pstatus);
+ if (res) {
+ vpm_info(vpm, "Unable to disable sw companding on "
+ "echo cancellation channel %d (reason %d)\n",
+ channel, res);
+ }
+ gpakAlgControl(vpm->dspid, channel, BypassEcanA, &pstatus);
+ }
+
+ return;
}
/**
@@ -272,97 +371,81 @@
{
struct vpmadt032 *vpm = container_of(data, struct vpmadt032, work);
#endif
- struct adt_lec_params *curstate, *desiredstate;
- int channel;
-
- /* Sweep through all the echo can channels on the VPMADT032 module,
- * looking for ones where the desired state does not match the current
- * state.
- */
- for (channel = 0; channel < vpm->options.channels; channel++) {
- GPAK_AlgControlStat_t pstatus;
- int res = 1;
- curstate = &vpm->curecstate[channel];
- desiredstate = &vpm->desiredecstate[channel];
-
- if ((desiredstate->nlp_type != curstate->nlp_type) ||
- (desiredstate->nlp_threshold != curstate->nlp_threshold) ||
- (desiredstate->nlp_max_suppress != curstate->nlp_max_suppress)) {
-
- GPAK_ChannelConfigStat_t cstatus;
- GPAK_TearDownChanStat_t tstatus;
- GpakChannelConfig_t chanconfig;
-
- if (vpm->options.debug & DEBUG_ECHOCAN)
- printk(KERN_DEBUG "Reconfiguring chan %d for nlp %d, nlp_thresh %d, and max_supp %d\n", channel + 1, vpm->desiredecstate[channel].nlp_type,
- desiredstate->nlp_threshold, desiredstate->nlp_max_suppress);
-
- vpm->setchanconfig_from_state(vpm, channel, &chanconfig);
-
- res = gpakTearDownChannel(vpm->dspid, channel, &tstatus);
- if (res)
- goto vpm_bh_out;
-
- res = gpakConfigureChannel(vpm->dspid, channel, tdmToTdm, &chanconfig, &cstatus);
- if (res)
- goto vpm_bh_out;
-
- if (!desiredstate->tap_length) {
- res = gpakAlgControl(vpm->dspid, channel, BypassSwCompanding, &pstatus);
- if (res)
- printk("Unable to disable sw companding on echo cancellation channel %d (reason %d)\n", channel, res);
- res = gpakAlgControl(vpm->dspid, channel, BypassEcanA, &pstatus);
- }
-
- } else if (desiredstate->tap_length != curstate->tap_length) {
- if (desiredstate->tap_length)
- res = vpmadt032_enable_ec(vpm, channel);
- else
- res = vpmadt032_disable_ec(vpm, channel);
- }
-vpm_bh_out:
- if (!res)
- *curstate = *desiredstate;
- }
- return;
-}
+ struct change_order *order;
+
+ while ((order = get_next_order(vpm))) {
+
+ struct adt_lec_params *old;
+ struct adt_lec_params *new;
+ unsigned int channel;
+
+ channel = order->channel;
+ BUG_ON(channel >= ARRAY_SIZE(vpm->curecstate));
+ old = &vpm->curecstate[channel];
+ new = &order->params;
+
+ if (nlp_settings_changed(new, old))
+ update_channel_config(vpm, channel, new);
+ else if (echocan_on(new, old))
+ vpmadt032_enable_ec(vpm, channel, new->companding);
+ else if (echocan_off(new, old))
+ vpmadt032_disable_ec(vpm, channel);
+
+ *old = order->params;
+ free_change_order(order);
+ }
+}
+
#include "adt_lec.c"
-static void vpmadt032_check_and_schedule_update(struct vpmadt032 *vpm, int channo)
-{
- int update;
- /* Only update the parameters if the new state of the echo canceller
- * is different than the current state. */
- update = memcmp(&vpm->curecstate[channo],
- &vpm->desiredecstate[channo],
- sizeof(vpm->curecstate[channo]));
- if (update && test_bit(VPM150M_ACTIVE, &vpm->control)) {
- /* Since updating the parameters can take a bit of time while
- * the driver sends messages to the VPMADT032 and waits for
- * their responses, we'll push the work of updating the
- * parameters to a work queue so the caller can continue to
- * proceed with setting up the call.
- */
- queue_work(vpm->wq, &vpm->work);
- }
+static void vpmadt032_check_and_schedule_update(struct vpmadt032 *vpm,
+ struct change_order *order)
+{
+ struct change_order *cur;
+ struct change_order *n;
+
+ INIT_LIST_HEAD(&order->node);
+ spin_lock(&vpm->change_list_lock);
+ list_for_each_entry_safe(cur, n, &vpm->change_list, node) {
+ if (cur->channel == order->channel) {
+ list_replace(&cur->node, &order->node);
+ free_change_order(cur);
+ break;
+ }
+ }
+ if (list_empty(&order->node))
+ list_add_tail(&order->node, &vpm->change_list);
+ spin_unlock(&vpm->change_list_lock);
+
+ queue_work(vpm->wq, &vpm->work);
}
int vpmadt032_echocan_create(struct vpmadt032 *vpm, int channo,
struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p)
{
unsigned int ret;
-
- ret = adt_lec_parse_params(&vpm->desiredecstate[channo], ecp, p);
- if (ret)
+ struct change_order *order = alloc_change_order();
+ if (!order)
+ return -ENOMEM;
+
+ memcpy(&order->params, &vpm->curecstate[channo], sizeof(order->params));
+ ret = adt_lec_parse_params(&order->params, ecp, p);
+ if (ret) {
+ free_change_order(order);
return ret;
-
- if (vpm->options.debug & DEBUG_ECHOCAN)
- printk(KERN_DEBUG "echocan: Channel is %d length %d\n", channo, ecp->tap_length);
+ }
+
+ if (vpm->options.debug & DEBUG_ECHOCAN) {
+ vpm_info(vpm, "Channel is %d length %d\n",
+ channo, ecp->tap_length);
+ }
/* The driver cannot control the number of taps on the VPMADT032
* module. Instead, it uses tap_length to enable or disable the echo
* cancellation. */
- vpm->desiredecstate[channo].tap_length = (ecp->tap_length) ? 1 : 0;
-
- vpmadt032_check_and_schedule_update(vpm, channo);
+ order->params.tap_length = (ecp->tap_length) ? 1 : 0;
+ order->params.companding = vpm->companding;
+ order->channel = channo;
+
+ vpmadt032_check_and_schedule_update(vpm, order);
return 0;
}
EXPORT_SYMBOL(vpmadt032_echocan_create);
@@ -370,15 +453,22 @@
void vpmadt032_echocan_free(struct vpmadt032 *vpm, int channo,
struct dahdi_echocan_state *ec)
{
- adt_lec_init_defaults(&vpm->desiredecstate[channo], 0);
- vpm->desiredecstate[channo].nlp_type = vpm->options.vpmnlptype;
- vpm->desiredecstate[channo].nlp_threshold = vpm->options.vpmnlpthresh;
- vpm->desiredecstate[channo].nlp_max_suppress = vpm->options.vpmnlpmaxsupp;
+ struct change_order *order;
+ order = alloc_change_order();
+ WARN_ON(!order);
+ if (!order)
+ return;
+
+ adt_lec_init_defaults(&order->params, 0);
+ order->params.nlp_type = vpm->options.vpmnlptype;
+ order->params.nlp_threshold = vpm->options.vpmnlpthresh;
+ order->params.nlp_max_suppress = vpm->options.vpmnlpmaxsupp;
+ order->channel = channo;
if (vpm->options.debug & DEBUG_ECHOCAN)
- printk(KERN_DEBUG "echocan: Channel is %d length 0\n", channo);
-
- vpmadt032_check_and_schedule_update(vpm, channo);
+ vpm_info(vpm, "Channel is %d length 0\n", channo);
+
+ vpmadt032_check_and_schedule_update(vpm, order);
}
EXPORT_SYMBOL(vpmadt032_echocan_free);
@@ -410,6 +500,8 @@
/* Init our vpmadt032 struct */
memcpy(&vpm->options, options, sizeof(*options));
spin_lock_init(&vpm->list_lock);
+ spin_lock_init(&vpm->change_list_lock);
+ INIT_LIST_HEAD(&vpm->change_list);
INIT_LIST_HEAD(&vpm->free_cmds);
INIT_LIST_HEAD(&vpm->pending_cmds);
INIT_LIST_HEAD(&vpm->active_cmds);
@@ -443,8 +535,6 @@
kfree(vpm);
printk(KERN_NOTICE "Unable to initialize another vpmadt032 modules\n");
vpm = NULL;
- } else if (vpm->options.debug & DEBUG_ECHOCAN) {
- printk(KERN_DEBUG "Setting VPMADT032 DSP ID to %d\n", vpm->dspid);
}
return vpm;
@@ -461,6 +551,9 @@
BUG_ON(!vpm->setchanconfig_from_state);
BUG_ON(!vpm->wq);
+ BUG_ON(!vb);
+
+ vpm->vb = vb;
might_sleep();
@@ -521,8 +614,9 @@
return res;
}
vpm->curpage = -1;
+
+ dev_info(&voicebus_get_pci_dev(vb)->dev, "Booting VPMADT032\n");
set_bit(VPM150M_SWRESET, &vpm->control);
-
while (test_bit(VPM150M_SWRESET, &vpm->control))
msleep(1);
@@ -561,7 +655,7 @@
p->EcanDblTalkThresh = 6;
p->EcanMaxDoubleTalkThres = 40;
p->EcanNlpThreshold = DEFAULT_NLPTHRESH;
- p->EcanNlpConv = 0;
+ p->EcanNlpConv = 18;
p->EcanNlpUnConv = 12;
p->EcanNlpMaxSuppress = DEFAULT_NLPMAXSUPP;
p->EcanCngThreshold = 43;
@@ -579,6 +673,7 @@
{
unsigned long flags;
struct vpmadt032_cmd *cmd;
+ struct change_order *order;
LIST_HEAD(local_list);
BUG_ON(!vpm);
@@ -597,6 +692,16 @@
cmd = list_entry(local_list.next, struct vpmadt032_cmd, node);
list_del(&cmd->node);
kfree(cmd);
+ }
+
+ spin_lock(&vpm->change_list_lock);
+ list_splice(&vpm->change_list, &local_list);
+ spin_unlock(&vpm->change_list_lock);
+
+ while (!list_empty(&local_list)) {
+ order = list_entry(local_list.next, struct change_order, node);
+ list_del(&order->node);
+ kfree(order);
}
BUG_ON(ifaces[vpm->dspid] != vpm);
Modified: freebsd/trunk/drivers/dahdi/voicebus/GpakCust.h
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/voicebus/GpakCust.h?view=diff&rev=7669&r1=7668&r2=7669
==============================================================================
--- freebsd/trunk/drivers/dahdi/voicebus/GpakCust.h (original)
+++ freebsd/trunk/drivers/dahdi/voicebus/GpakCust.h Tue Dec 8 10:40:14 2009
@@ -105,9 +105,8 @@
struct GpakChannelConfig;
-#define MAX_CHANNELS_PER_SPAN 32
struct vpmadt032 {
- void *context;
+ struct voicebus *vb;
struct work_struct work;
struct workqueue_struct *wq;
int dspid;
@@ -115,8 +114,10 @@
unsigned long control;
unsigned char curpage;
unsigned short version;
- struct adt_lec_params curecstate[MAX_CHANNELS_PER_SPAN];
- struct adt_lec_params desiredecstate[MAX_CHANNELS_PER_SPAN];
+ enum adt_companding companding;
+ struct adt_lec_params curecstate[MAX_CHANNELS];
+ spinlock_t change_list_lock;
+ struct list_head change_list;
spinlock_t list_lock;
/* Commands that are ready to be used. */
struct list_head free_cmds;
@@ -124,7 +125,6 @@
struct list_head pending_cmds;
/* Commands that are currently in progress by the VPM module */
struct list_head active_cmds;
- unsigned char curtone[MAX_CHANNELS_PER_SPAN];
struct vpmadt032_options options;
void (*setchanconfig_from_state)(struct vpmadt032 *vpm, int channel, struct GpakChannelConfig *chanconfig);
/* This must be last */
Modified: freebsd/trunk/drivers/dahdi/voicebus/voicebus.c
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/voicebus/voicebus.c?view=diff&rev=7669&r1=7668&r2=7669
==============================================================================
--- freebsd/trunk/drivers/dahdi/voicebus/voicebus.c (original)
+++ freebsd/trunk/drivers/dahdi/voicebus/voicebus.c Tue Dec 8 10:40:14 2009
@@ -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 @@
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 @@
/*! 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,11 +193,17 @@
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
@@ -218,15 +231,13 @@
#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 @@
#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 @@
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 @@
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 @@
*/
#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 @@
}
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 @@
}
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;
- 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 && (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;
+
+ 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;
}
@@ -480,6 +567,15 @@
dl->head = 0;
dl->tail = 0;
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
@@ -519,30 +615,30 @@
}
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 &= ~CSR9_MMC;
- __vb_setctl(vb, 0x0048, vb->sdi);
+__vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count, u32 *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;
-
- __vb_sdi_clk(vb);
+ *sdi &= ~CSR9_MDO;
+
+ __vb_sdi_clk(vb, sdi);
}
}
@@ -551,13 +647,14 @@
{
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 @@
{
LOCKS_VOICEBUS;
u32 reg;
- assert(vb->pdev);
+ BUG_ON(!vb->pdev);
VBLOCK(vb);
pci_read_config_dword(vb->pdev, 0x0004, ®);
reg |= 0x00000007;
@@ -620,11 +717,12 @@
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 @@
} 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 @@
{
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 @@
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,12 +815,44 @@
}
#endif
+/**
+ * voicebus_transmit - Queue a buffer on the hardware descriptor ring.
+ *
+ */
+int voicebus_transmit(struct voicebus *vb, void *vbb)
+{
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->txd;
+
+ d = vb_descriptor(dl, dl->tail);
+
+ 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 -EFAULT;
+ }
+
+ 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;
+}
+EXPORT_SYMBOL(voicebus_transmit);
+
+/*!
+ * \brief Give a frame to the hardware to use for receiving.
+ *
+ */
static inline int
-vb_submit(struct voicebus *vb, struct voicebus_descriptor_list *dl, void *vbb)
-{
- volatile struct voicebus_descriptor *d;
+vb_submit_rxb(struct voicebus *vb, void *vbb)
+{
+ struct voicebus_descriptor *d;
+ struct voicebus_descriptor_list *dl = &vb->rxd;
unsigned int tail = dl->tail;
- assert_in_vb_deferred(vb);
d = vb_descriptor(dl, tail);
@@ -738,53 +865,11 @@
dl->pending[tail] = vbb;
dl->tail = (++tail) & DRING_MASK;
- d->buffer1 = dma_map_single(
- &vb->pdev->dev, vbb, vb->framesize, dl->direction);
+ 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;
-}
-
-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);
-
-/*!
- * \brief Give a frame to the hardware to use for receiving.
- *
- */
-static inline int
-vb_submit_rxb(struct voicebus *vb, void *vbb)
-{
- return vb_submit(vb, &vb->rxd, vbb);
}
/*!
@@ -803,13 +888,47 @@
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 @@
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 @@
* 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 @@
if (unlikely(NULL == vbb))
BUG_ON(1);
else
- vb->handle_transmit(vbb, vb->context);
-
- }
- stop_vb_deferred(vb);
+ handle_transmit(vb, vbb);
+
+ }
VBLOCK(vb);
clear_bit(STOP, &vb->flags);
@@ -971,7 +1090,7 @@
__vb_tx_demand_poll(vb);
VBUNLOCK(vb);
- assert(!vb_is_stopped(vb));
+ BUG_ON(vb_is_stopped(vb));
return 0;
}
@@ -1033,8 +1152,6 @@
int
voicebus_stop(struct voicebus *vb)
{
- assert(!in_interrupt());
-
if (vb_is_stopped(vb))
return 0;
@@ -1043,11 +1160,10 @@
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 @@
}
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 @@
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 @@
/* 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,102 +1240,290 @@
EXPORT_SYMBOL(voicebus_release);
static void
-__vb_increase_latency(struct voicebus *vb)
-{
- static int __warn_once = 1;
+vb_increase_latency(struct voicebus *vb, unsigned int increase)
+{
void *vbb;
- int latency;
-
- assert_in_vb_deferred(vb);
-
- 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;
+ int i;
+
+ if (0 == increase)
+ return;
+
+ 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);
+ }
+
+ /* 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);
+ }
+}
+
+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.
+ *
+ * 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 unsigned int __vb_get_default_behind_count(const struct voicebus *vb)
+{
[... 3586 lines stripped ...]
More information about the dahdi-commits
mailing list