[svn-commits] sruffell: branch linux/sruffell/wctdm24xxp-updates r10123 - /linux/team/sruff...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Fri Aug 12 19:35:54 CDT 2011
Author: sruffell
Date: Fri Aug 12 19:35:50 2011
New Revision: 10123
URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=10123
Log:
wctdm24xxp: Probe and configure modules in parallel.
Use the newly create bg_create and bg_join to actually probe / configure
groups of 4 modules in parallel. This currently has to be done in groups of
four due to the way 4-port modules are identified relative to single port
modules.
This provides a dramatic improvement in driver load time.
Signed-off-by: Shaun Ruffell <sruffell at digium.com>
Modified:
linux/team/sruffell/wctdm24xxp-updates/drivers/dahdi/wctdm24xxp/base.c
Modified: linux/team/sruffell/wctdm24xxp-updates/drivers/dahdi/wctdm24xxp/base.c
URL: http://svnview.digium.com/svn/dahdi/linux/team/sruffell/wctdm24xxp-updates/drivers/dahdi/wctdm24xxp/base.c?view=diff&rev=10123&r1=10122&r2=10123
==============================================================================
--- linux/team/sruffell/wctdm24xxp-updates/drivers/dahdi/wctdm24xxp/base.c (original)
+++ linux/team/sruffell/wctdm24xxp-updates/drivers/dahdi/wctdm24xxp/base.c Fri Aug 12 19:35:50 2011
@@ -448,15 +448,37 @@
sizeof(chanconfig->EcanParametersB));
}
-static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc)
-{
- int res, i;
+struct vpmadt032_channel_setup {
+ struct work_struct work;
+ struct wctdm *wc;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void vpm_setup_work_func(void *data)
+{
+ struct vpmadt032_channel_setup *setup = data;
+#else
+static void vpm_setup_work_func(struct work_struct *work)
+{
+ struct vpmadt032_channel_setup *setup =
+ container_of(work, struct vpmadt032_channel_setup, work);
+#endif
+ int i;
+ int res;
+ GpakChannelConfig_t chanconfig;
+ GPAK_ChannelConfigStat_t cstatus;
+ GPAK_AlgControlStat_t algstatus;
GpakPortConfig_t portconfig = {0};
gpakConfigPortStatus_t configportstatus;
GPAK_PortConfigStat_t pstatus;
- GpakChannelConfig_t chanconfig;
- GPAK_ChannelConfigStat_t cstatus;
- GPAK_AlgControlStat_t algstatus;
+ struct vpmadt032 *vpm;
+ struct wctdm *const wc = setup->wc;
+
+ WARN_ON(!wc);
+ WARN_ON(!wc->vpmadt032);
+ if (unlikely(!wc || !wc->vpmadt032))
+ return;
+ vpm = wc->vpmadt032;
/* First Serial Port config */
portconfig.SlotsSelect1 = SlotCfgNone;
@@ -526,7 +548,7 @@
if ((configportstatus = gpakConfigurePorts(vpm->dspid, &portconfig, &pstatus))) {
dev_notice(&wc->vb.pdev->dev, "Configuration of ports failed (%d)!\n", configportstatus);
- return -1;
+ return;
} else {
if (vpm->options.debug & DEBUG_ECHOCAN)
dev_info(&wc->vb.pdev->dev, "Configured McBSP ports successfully\n");
@@ -535,44 +557,81 @@
res = gpakPingDsp(vpm->dspid, &vpm->version);
if (res) {
dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res);
- return -1;
+ return;
}
for (i = 0; i < vpm->options.channels; ++i) {
- struct dahdi_chan *const chan = &wc->chans[i]->chan;
vpm->curecstate[i].tap_length = 0;
vpm->curecstate[i].nlp_type = vpm->options.vpmnlptype;
vpm->curecstate[i].nlp_threshold = vpm->options.vpmnlpthresh;
- vpm->curecstate[i].nlp_max_suppress = vpm->options.vpmnlpmaxsupp;
- vpm->curecstate[i].companding = (chan->span->deflaw == DAHDI_LAW_ALAW) ? ADT_COMP_ALAW : ADT_COMP_ULAW;
- /* set_vpmadt032_chanconfig_from_state(&vpm->curecstate[i], &vpm->options, i, &chanconfig); !!! */
+ vpm->curecstate[i].nlp_max_suppress =
+ vpm->options.vpmnlpmaxsupp;
+ vpm->curecstate[i].companding = ADT_COMP_ULAW;
vpm->setchanconfig_from_state(vpm, i, &chanconfig);
- if ((res = gpakConfigureChannel(vpm->dspid, i, tdmToTdm, &chanconfig, &cstatus))) {
- dev_notice(&wc->vb.pdev->dev, "Unable to configure channel #%d (%d)", i, res);
- if (res == 1) {
+
+ res = gpakConfigureChannel(vpm->dspid, i, tdmToTdm,
+ &chanconfig, &cstatus);
+ if (res) {
+ dev_notice(&wc->vb.pdev->dev,
+ "Unable to configure channel #%d (%d)",
+ i, res);
+ if (res == 1)
printk(KERN_CONT ", reason %d", cstatus);
- }
printk(KERN_CONT "\n");
- return -1;
- }
-
- if ((res = gpakAlgControl(vpm->dspid, i, BypassEcanA, &algstatus))) {
- dev_notice(&wc->vb.pdev->dev, "Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
- return -1;
- }
-
- if ((res = gpakAlgControl(vpm->dspid, i, BypassSwCompanding, &algstatus))) {
- dev_notice(&wc->vb.pdev->dev, "Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
- return -1;
- }
- }
-
- if ((res = gpakPingDsp(vpm->dspid, &vpm->version))) {
+ goto exit;
+ }
+
+ res = gpakAlgControl(vpm->dspid, i, BypassEcanA, &algstatus);
+ if (res) {
+ dev_notice(&wc->vb.pdev->dev,
+ "Unable to disable echo can on channel %d "
+ "(reason %d:%d)\n", i + 1, res, algstatus);
+ goto exit;
+ }
+
+ res = gpakAlgControl(vpm->dspid, i,
+ BypassSwCompanding, &algstatus);
+ if (res) {
+ dev_notice(&wc->vb.pdev->dev,
+ "Unable to disable echo can on channel %d "
+ "(reason %d:%d)\n", i + 1, res, algstatus);
+ goto exit;
+ }
+ }
+
+ res = gpakPingDsp(vpm->dspid, &vpm->version);
+ if (res) {
dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res);
- return -1;
+ goto exit;
}
set_bit(VPM150M_ACTIVE, &vpm->control);
+
+exit:
+ kfree(setup);
+}
+
+static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc)
+{
+ struct vpmadt032_channel_setup *setup;
+
+ /* Because the channel configuration can take such a long time, let's
+ * move this out onto the VPM workqueue so the system can proceeded
+ * with startup. */
+
+ setup = kzalloc(sizeof(*setup), GFP_KERNEL);
+ if (!setup)
+ return -ENOMEM;
+
+ setup->wc = wc;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&setup->work, vpm_setup_work_func, setup);
+#else
+ INIT_WORK(&setup->work, vpm_setup_work_func);
+#endif
+
+ queue_work(vpm->wq, &setup->work);
return 0;
}
@@ -4448,14 +4507,14 @@
options.vpmnlptype = vpmnlptype;
options.vpmnlpthresh = vpmnlpthresh;
options.vpmnlpmaxsupp = vpmnlpmaxsupp;
- options.channels = wc->avchannels;
+ options.channels = wc->desc->ports;
wc->vpmadt032 = vpmadt032_alloc(&options);
if (!wc->vpmadt032)
return -ENOMEM;
wc->vpmadt032->setchanconfig_from_state = setchanconfig_from_state;
- /* wc->vpmadt032->context = wc; */
+
/* Pull the configuration information from the span holding
* the analog channels. */
res = vpmadt032_test(wc->vpmadt032, &wc->vb);
@@ -4504,17 +4563,19 @@
vpmoct_free(vpm);
}
-static void wctdm_initialize_vpm(struct wctdm *wc)
+static int wctdm_initialize_vpm(struct wctdm *wc, unsigned long unused)
{
int res = 0;
- if (!vpmsupport)
- return;
+ if (!vpmsupport) {
+ dev_notice(&wc->vb.pdev->dev, "VPM: Support Disabled\n");
+ return 0;
+ }
res = wctdm_initialize_vpmadt032(wc);
if (!res) {
wc->ctlreg |= 0x10;
- return;
+ return 0;
} else {
struct vpmoct *vpm;
unsigned long flags;
@@ -4523,7 +4584,7 @@
if (!vpm) {
dev_info(&wc->vb.pdev->dev,
"Unable to allocate memory for struct vpmoct\n");
- return;
+ return -ENOMEM;
}
vpm->dev = &wc->vb.pdev->dev;
@@ -4542,13 +4603,151 @@
vpmoct_free(vpm);
}
}
- return;
-}
-
-static void wctdm_identify_modules(struct wctdm *wc)
+ return 0;
+}
+
+static int __wctdm_identify_module_group(struct wctdm *wc, unsigned long base)
{
int x;
unsigned long flags;
+
+ for (x = base; x < base + 4; ++x) {
+ struct wctdm_module *const mod = &wc->mods[x];
+ enum {SANE = 1, UNKNOWN = 0};
+ int ret = 0, readi = 0;
+ bool altcs = false;
+
+ if (fatal_signal_pending(current))
+ break;
+retry:
+ ret = wctdm_init_proslic(wc, mod, 0, 0, UNKNOWN);
+ if (!ret) {
+ if (debug & DEBUG_CARD) {
+ readi = wctdm_getreg(wc, mod, LOOP_I_LIMIT);
+ dev_info(&wc->vb.pdev->dev,
+ "Proslic module %d loop current "
+ "is %dmA\n", x, ((readi*3) + 20));
+ }
+ continue;
+ }
+
+ if (ret != -2) {
+ /* Init with Manual Calibration */
+ if (!wctdm_init_proslic(wc, mod, 0, 1, SANE)) {
+
+ if (debug & DEBUG_CARD) {
+ readi = wctdm_getreg(wc, mod,
+ LOOP_I_LIMIT);
+ dev_info(&wc->vb.pdev->dev,
+ "Proslic module %d loop "
+ "current is %dmA\n", x,
+ ((readi*3)+20));
+ }
+ } else {
+ dev_notice(&wc->vb.pdev->dev,
+ "Port %d: FAILED FXS (%s)\n",
+ x + 1, fxshonormode ?
+ fxo_modes[_opermode].name : "FCC");
+ }
+ continue;
+ }
+
+ ret = wctdm_init_voicedaa(wc, mod, 0, 0, UNKNOWN);
+ if (!ret)
+ continue;
+
+ if (!wctdm_init_qrvdri(wc, x))
+ continue;
+
+ if (is_hx8(wc) && !wctdm_init_b400m(wc, x))
+ continue;
+
+ if ((wc->desc->ports != 24) && ((x&0x3) == 1) && !altcs) {
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ set_offsets(mod, 2);
+ altcs = true;
+
+ if (wc->desc->ports == 4) {
+ set_offsets(&wc->mods[x+1], 3);
+ set_offsets(&wc->mods[x+2], 3);
+ }
+
+ mod->type = FXSINIT;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ udelay(1000);
+ udelay(1000);
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ mod->type = FXS;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ if (debug & DEBUG_CARD) {
+ dev_info(&wc->vb.pdev->dev,
+ "Trying port %d with alternate chip "
+ "select\n", x + 1);
+ }
+ goto retry;
+ }
+
+ mod->type = NONE;
+ }
+ return 0;
+}
+
+/**
+ * wctdm_print_moule_configuration - Print the configuration to the kernel log
+ * @wc: The card we're interested in.
+ *
+ * This is to ensure that the module configuration from each card shows up
+ * sequentially in the kernel log, as opposed to interleaved with one another.
+ *
+ */
+static void wctdm_print_module_configuration(const struct wctdm *const wc)
+{
+ int i;
+ static DEFINE_MUTEX(print);
+
+ mutex_lock(&print);
+ for (i = 0; i < wc->mods_per_board; ++i) {
+ const struct wctdm_module *const mod = &wc->mods[i];
+
+ switch (mod->type) {
+ case FXO:
+ dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- "
+ "AUTO FXO (%s mode)\n", i + 1,
+ fxo_modes[_opermode].name);
+ break;
+ case FXS:
+ dev_info(&wc->vb.pdev->dev,
+ "Port %d: Installed -- AUTO FXS/DPO\n", i + 1);
+ break;
+ case BRI:
+ dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- BRI "
+ "quad-span module\n", i + 1);
+ break;
+ case QRV:
+ dev_info(&wc->vb.pdev->dev,
+ "Port %d: Installed -- QRV DRI card\n", i + 1);
+ break;
+ case NONE:
+ dev_info(&wc->vb.pdev->dev,
+ "Port %d: Not installed\n", i + 1);
+ break;
+ case FXSINIT:
+ break;
+ }
+ }
+ mutex_unlock(&print);
+}
+
+static void wctdm_identify_modules(struct wctdm *wc)
+{
+ int x;
+ unsigned long flags;
+ struct bg *bg_work[ARRAY_SIZE(wc->mods)/4 + 1] = {NULL, };
+
wc->ctlreg = 0x00;
/*
@@ -4586,7 +4785,7 @@
/* Wait just a bit; this makes sure that cmd_dequeue is emitting SPI
* commands in the appropriate mode(s). */
- udelay(2000);
+ msleep(20);
/* Now that all the cards have been reset, we can stop checking them
* all if there aren't as many */
@@ -4594,106 +4793,18 @@
wc->mods_per_board = wc->desc->ports;
spin_unlock_irqrestore(&wc->reglock, flags);
- /* Reset modules */
- for (x = 0; x < wc->mods_per_board; x++) {
- struct wctdm_module *const mod = &wc->mods[x];
- enum {SANE = 1, UNKNOWN = 0};
- int ret = 0, readi = 0;
- bool altcs = false;
-
- if (fatal_signal_pending(current))
- break;
-retry:
- ret = wctdm_init_proslic(wc, mod, 0, 0, UNKNOWN);
- if (!ret) {
- if (debug & DEBUG_CARD) {
- readi = wctdm_getreg(wc, mod, LOOP_I_LIMIT);
- dev_info(&wc->vb.pdev->dev,
- "Proslic module %d loop current "
- "is %dmA\n", x, ((readi*3) + 20));
- }
- dev_info(&wc->vb.pdev->dev,
- "Port %d: Installed -- AUTO FXS/DPO\n", x + 1);
- continue;
- }
-
- if (ret != -2) {
- /* Init with Manual Calibration */
- if (!wctdm_init_proslic(wc, mod, 0, 1, SANE)) {
-
- if (debug & DEBUG_CARD) {
- readi = wctdm_getreg(wc, mod,
- LOOP_I_LIMIT);
- dev_info(&wc->vb.pdev->dev,
- "Proslic module %d loop "
- "current is %dmA\n", x,
- ((readi*3)+20));
- }
-
- dev_info(&wc->vb.pdev->dev,
- "Port %d: Installed -- MANUAL FXS\n",
- x + 1);
- } else {
- dev_notice(&wc->vb.pdev->dev,
- "Port %d: FAILED FXS (%s)\n",
- x + 1, fxshonormode ?
- fxo_modes[_opermode].name : "FCC");
- }
- continue;
- }
-
- ret = wctdm_init_voicedaa(wc, mod, 0, 0, UNKNOWN);
- if (!ret) {
- dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- "
- "AUTO FXO (%s mode)\n", x + 1,
- fxo_modes[_opermode].name);
- continue;
- }
-
- if (!wctdm_init_qrvdri(wc, x)) {
- dev_info(&wc->vb.pdev->dev,
- "Port %d: Installed -- QRV DRI card\n", x + 1);
- continue;
- }
-
- if (is_hx8(wc) && !wctdm_init_b400m(wc, x)) {
- dev_info(&wc->vb.pdev->dev, "Port %d: Installed -- BRI "
- "quad-span module\n", x + 1);
- continue;
- }
-
- if ((wc->desc->ports != 24) && ((x&0x3) == 1) && !altcs) {
-
- spin_lock_irqsave(&wc->reglock, flags);
- set_offsets(mod, 2);
- altcs = true;
-
- if (wc->desc->ports == 4) {
- set_offsets(&wc->mods[x+1], 3);
- set_offsets(&wc->mods[x+2], 3);
- }
-
- mod->type = FXSINIT;
- spin_unlock_irqrestore(&wc->reglock, flags);
-
- udelay(1000);
- udelay(1000);
-
- spin_lock_irqsave(&wc->reglock, flags);
- mod->type = FXS;
- spin_unlock_irqrestore(&wc->reglock, flags);
-
- if (debug & DEBUG_CARD) {
- dev_info(&wc->vb.pdev->dev,
- "Trying port %d with alternate chip "
- "select\n", x + 1);
- }
- goto retry;
- }
-
- mod->type = NONE;
- dev_info(&wc->vb.pdev->dev, "Port %d: Not installed\n", x + 1);
- } /* for (x...) */
+ BUG_ON(wc->desc->ports % 4);
+
+ /* Detecting and configuring the modules over voicebus takes a
+ * significant amount of time. We can speed things up by performing
+ * this in parallel for each group of four modules. */
+ for (x = 0; x < wc->desc->ports/4; x++)
+ bg_work[x] = bg_create(wc, __wctdm_identify_module_group, x*4);
+
+ for (x = 0; bg_work[x]; ++x)
+ bg_join(bg_work[x]);
+
+ wctdm_print_module_configuration(wc);
}
static struct pci_driver wctdm_driver;
@@ -5332,7 +5443,7 @@
struct wctdm *wc;
unsigned int pos;
int i, ret;
-
+ struct bg *vpm_work;
int anamods, digimods, curchan, curspan;
neonmwi_offlimit_cycles = neonmwi_offlimit / MS_PER_HOOKCHECK;
@@ -5463,6 +5574,12 @@
/* first we have to make sure that we process all module data, we'll fine-tune it later in this routine. */
wc->avchannels = NUM_MODULES;
+ vpm_work = bg_create(wc, wctdm_initialize_vpm, 0);
+ if (!vpm_work) {
+ wctdm_back_out_gracefully(wc);
+ return -ENOMEM;
+ }
+
/* Now track down what modules are installed */
wctdm_identify_modules(wc);
@@ -5470,8 +5587,14 @@
if (fatal_signal_pending(current)) {
wctdm_back_out_gracefully(wc);
+ bg_join(vpm_work);
return -EINTR;
}
+
+ /* We need to wait for the vpm thread to finish before we setup the
+ * spans in order to ensure they are named properly. */
+ bg_join(vpm_work);
+
/*
* Walk the module list and create a 3-channel span for every BRI module found.
* Empty and analog modules get a common span which is allocated outside of this loop.
@@ -5492,6 +5615,7 @@
"detected on a non-hybrid card. "
"This is unsupported.\n");
wctdm_back_out_gracefully(wc);
+ bg_join(vpm_work);
return -EIO;
}
wc->spans[curspan] = wctdm_init_span(wc, curspan,
@@ -5499,6 +5623,7 @@
pos);
if (!wc->spans[curspan]) {
wctdm_back_out_gracefully(wc);
+ bg_join(vpm_work);
return -EIO;
}
b4 = mod->mod.bri;
@@ -5568,7 +5693,6 @@
wc->avchannels = curchan;
- wctdm_initialize_vpm(wc);
#ifdef USE_ASYNC_INIT
async_synchronize_cookie(cookie);
@@ -5673,8 +5797,9 @@
remove_sysfs_files(wc);
if (vpmadt032) {
+ flush_workqueue(vpmadt032->wq);
clear_bit(VPM150M_ACTIVE, &vpmadt032->control);
- flush_scheduled_work();
+ flush_workqueue(vpmadt032->wq);
} else if (vpmoct) {
while (wctdm_wait_for_ready(wc))
schedule();
More information about the svn-commits
mailing list