wctdm24xxp: Probe for 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. When loading a single TDM2400 with 24 FXS ports before this change: # time modprobe wctdm24xxp vpmsupport=0 real 0m46.674s user 0m0.000s sys 0m0.520s And after this change: # time modprobe wctdm24xxp vpmsupport=0 real 0m7.900s user 0m0.000s sys 0m0.070s Note that the boards themselves are still configured serially. Board configuration can be parallelized once the assignment of board position is moved out of the function that is run in parallel. Otherwise it could be possible for board numbers to switch on repeated loads. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Acked-by: Russ Meyerriecks <rmeyerriecks@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10160 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
parent
cfafd3a7b7
commit
1d03f6f8a8
@ -448,15 +448,37 @@ setchanconfig_from_state(struct vpmadt032 *vpm, int channel,
|
|||||||
sizeof(chanconfig->EcanParametersB));
|
sizeof(chanconfig->EcanParametersB));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc)
|
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)
|
||||||
{
|
{
|
||||||
int res, i;
|
struct vpmadt032_channel_setup *setup = data;
|
||||||
GpakPortConfig_t portconfig = {0};
|
#else
|
||||||
gpakConfigPortStatus_t configportstatus;
|
static void vpm_setup_work_func(struct work_struct *work)
|
||||||
GPAK_PortConfigStat_t pstatus;
|
{
|
||||||
|
struct vpmadt032_channel_setup *setup =
|
||||||
|
container_of(work, struct vpmadt032_channel_setup, work);
|
||||||
|
#endif
|
||||||
|
int i;
|
||||||
|
int res;
|
||||||
GpakChannelConfig_t chanconfig;
|
GpakChannelConfig_t chanconfig;
|
||||||
GPAK_ChannelConfigStat_t cstatus;
|
GPAK_ChannelConfigStat_t cstatus;
|
||||||
GPAK_AlgControlStat_t algstatus;
|
GPAK_AlgControlStat_t algstatus;
|
||||||
|
GpakPortConfig_t portconfig = {0};
|
||||||
|
gpakConfigPortStatus_t configportstatus;
|
||||||
|
GPAK_PortConfigStat_t pstatus;
|
||||||
|
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 */
|
/* First Serial Port config */
|
||||||
portconfig.SlotsSelect1 = SlotCfgNone;
|
portconfig.SlotsSelect1 = SlotCfgNone;
|
||||||
@ -526,7 +548,7 @@ static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc)
|
|||||||
|
|
||||||
if ((configportstatus = gpakConfigurePorts(vpm->dspid, &portconfig, &pstatus))) {
|
if ((configportstatus = gpakConfigurePorts(vpm->dspid, &portconfig, &pstatus))) {
|
||||||
dev_notice(&wc->vb.pdev->dev, "Configuration of ports failed (%d)!\n", configportstatus);
|
dev_notice(&wc->vb.pdev->dev, "Configuration of ports failed (%d)!\n", configportstatus);
|
||||||
return -1;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (vpm->options.debug & DEBUG_ECHOCAN)
|
if (vpm->options.debug & DEBUG_ECHOCAN)
|
||||||
dev_info(&wc->vb.pdev->dev, "Configured McBSP ports successfully\n");
|
dev_info(&wc->vb.pdev->dev, "Configured McBSP ports successfully\n");
|
||||||
@ -535,45 +557,82 @@ static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc)
|
|||||||
res = gpakPingDsp(vpm->dspid, &vpm->version);
|
res = gpakPingDsp(vpm->dspid, &vpm->version);
|
||||||
if (res) {
|
if (res) {
|
||||||
dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res);
|
dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res);
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < vpm->options.channels; ++i) {
|
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].tap_length = 0;
|
||||||
vpm->curecstate[i].nlp_type = vpm->options.vpmnlptype;
|
vpm->curecstate[i].nlp_type = vpm->options.vpmnlptype;
|
||||||
vpm->curecstate[i].nlp_threshold = vpm->options.vpmnlpthresh;
|
vpm->curecstate[i].nlp_threshold = vpm->options.vpmnlpthresh;
|
||||||
vpm->curecstate[i].nlp_max_suppress = vpm->options.vpmnlpmaxsupp;
|
vpm->curecstate[i].nlp_max_suppress =
|
||||||
vpm->curecstate[i].companding = (chan->span->deflaw == DAHDI_LAW_ALAW) ? ADT_COMP_ALAW : ADT_COMP_ULAW;
|
vpm->options.vpmnlpmaxsupp;
|
||||||
/* set_vpmadt032_chanconfig_from_state(&vpm->curecstate[i], &vpm->options, i, &chanconfig); !!! */
|
vpm->curecstate[i].companding = ADT_COMP_ULAW;
|
||||||
vpm->setchanconfig_from_state(vpm, i, &chanconfig);
|
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);
|
res = gpakConfigureChannel(vpm->dspid, i, tdmToTdm,
|
||||||
if (res == 1) {
|
&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 ", reason %d", cstatus);
|
||||||
}
|
|
||||||
printk(KERN_CONT "\n");
|
printk(KERN_CONT "\n");
|
||||||
return -1;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = gpakAlgControl(vpm->dspid, i, BypassEcanA, &algstatus))) {
|
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);
|
if (res) {
|
||||||
return -1;
|
dev_notice(&wc->vb.pdev->dev,
|
||||||
|
"Unable to disable echo can on channel %d "
|
||||||
|
"(reason %d:%d)\n", i + 1, res, algstatus);
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = gpakAlgControl(vpm->dspid, i, BypassSwCompanding, &algstatus))) {
|
res = gpakAlgControl(vpm->dspid, i,
|
||||||
dev_notice(&wc->vb.pdev->dev, "Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
|
BypassSwCompanding, &algstatus);
|
||||||
return -1;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res = gpakPingDsp(vpm->dspid, &vpm->version))) {
|
res = gpakPingDsp(vpm->dspid, &vpm->version);
|
||||||
|
if (res) {
|
||||||
dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res);
|
dev_notice(&wc->vb.pdev->dev, "Error pinging DSP (%d)\n", res);
|
||||||
return -1;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bit(VPM150M_ACTIVE, &vpm->control);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4461,14 +4520,14 @@ static int wctdm_initialize_vpmadt032(struct wctdm *wc)
|
|||||||
options.vpmnlptype = vpmnlptype;
|
options.vpmnlptype = vpmnlptype;
|
||||||
options.vpmnlpthresh = vpmnlpthresh;
|
options.vpmnlpthresh = vpmnlpthresh;
|
||||||
options.vpmnlpmaxsupp = vpmnlpmaxsupp;
|
options.vpmnlpmaxsupp = vpmnlpmaxsupp;
|
||||||
options.channels = wc->avchannels;
|
options.channels = wc->desc->ports;
|
||||||
|
|
||||||
wc->vpmadt032 = vpmadt032_alloc(&options);
|
wc->vpmadt032 = vpmadt032_alloc(&options);
|
||||||
if (!wc->vpmadt032)
|
if (!wc->vpmadt032)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
wc->vpmadt032->setchanconfig_from_state = setchanconfig_from_state;
|
wc->vpmadt032->setchanconfig_from_state = setchanconfig_from_state;
|
||||||
/* wc->vpmadt032->context = wc; */
|
|
||||||
/* Pull the configuration information from the span holding
|
/* Pull the configuration information from the span holding
|
||||||
* the analog channels. */
|
* the analog channels. */
|
||||||
res = vpmadt032_test(wc->vpmadt032, &wc->vb);
|
res = vpmadt032_test(wc->vpmadt032, &wc->vb);
|
||||||
@ -4517,17 +4576,19 @@ static void wctdm_vpm_load_complete(struct device *dev, bool operational)
|
|||||||
vpmoct_free(vpm);
|
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;
|
int res = 0;
|
||||||
|
|
||||||
if (!vpmsupport)
|
if (!vpmsupport) {
|
||||||
return;
|
dev_notice(&wc->vb.pdev->dev, "VPM: Support Disabled\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
res = wctdm_initialize_vpmadt032(wc);
|
res = wctdm_initialize_vpmadt032(wc);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
wc->ctlreg |= 0x10;
|
wc->ctlreg |= 0x10;
|
||||||
return;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
struct vpmoct *vpm;
|
struct vpmoct *vpm;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -4536,7 +4597,7 @@ static void wctdm_initialize_vpm(struct wctdm *wc)
|
|||||||
if (!vpm) {
|
if (!vpm) {
|
||||||
dev_info(&wc->vb.pdev->dev,
|
dev_info(&wc->vb.pdev->dev,
|
||||||
"Unable to allocate memory for struct vpmoct\n");
|
"Unable to allocate memory for struct vpmoct\n");
|
||||||
return;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
vpm->dev = &wc->vb.pdev->dev;
|
vpm->dev = &wc->vb.pdev->dev;
|
||||||
@ -4555,13 +4616,151 @@ static void wctdm_initialize_vpm(struct wctdm *wc)
|
|||||||
vpmoct_free(vpm);
|
vpmoct_free(vpm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
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)
|
static void wctdm_identify_modules(struct wctdm *wc)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct bg *bg_work[ARRAY_SIZE(wc->mods)/4 + 1] = {NULL, };
|
||||||
|
|
||||||
wc->ctlreg = 0x00;
|
wc->ctlreg = 0x00;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4599,7 +4798,7 @@ static void wctdm_identify_modules(struct wctdm *wc)
|
|||||||
|
|
||||||
/* Wait just a bit; this makes sure that cmd_dequeue is emitting SPI
|
/* Wait just a bit; this makes sure that cmd_dequeue is emitting SPI
|
||||||
* commands in the appropriate mode(s). */
|
* commands in the appropriate mode(s). */
|
||||||
udelay(2000);
|
msleep(20);
|
||||||
|
|
||||||
/* Now that all the cards have been reset, we can stop checking them
|
/* Now that all the cards have been reset, we can stop checking them
|
||||||
* all if there aren't as many */
|
* all if there aren't as many */
|
||||||
@ -4607,106 +4806,18 @@ static void wctdm_identify_modules(struct wctdm *wc)
|
|||||||
wc->mods_per_board = wc->desc->ports;
|
wc->mods_per_board = wc->desc->ports;
|
||||||
spin_unlock_irqrestore(&wc->reglock, flags);
|
spin_unlock_irqrestore(&wc->reglock, flags);
|
||||||
|
|
||||||
/* Reset modules */
|
BUG_ON(wc->desc->ports % 4);
|
||||||
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))
|
/* Detecting and configuring the modules over voicebus takes a
|
||||||
break;
|
* significant amount of time. We can speed things up by performing
|
||||||
retry:
|
* this in parallel for each group of four modules. */
|
||||||
ret = wctdm_init_proslic(wc, mod, 0, 0, UNKNOWN);
|
for (x = 0; x < wc->desc->ports/4; x++)
|
||||||
if (!ret) {
|
bg_work[x] = bg_create(wc, __wctdm_identify_module_group, x*4);
|
||||||
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) {
|
for (x = 0; bg_work[x]; ++x)
|
||||||
/* Init with Manual Calibration */
|
bg_join(bg_work[x]);
|
||||||
if (!wctdm_init_proslic(wc, mod, 0, 1, SANE)) {
|
|
||||||
|
|
||||||
if (debug & DEBUG_CARD) {
|
wctdm_print_module_configuration(wc);
|
||||||
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...) */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pci_driver wctdm_driver;
|
static struct pci_driver wctdm_driver;
|
||||||
@ -5379,7 +5490,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
struct wctdm *wc;
|
struct wctdm *wc;
|
||||||
unsigned int pos;
|
unsigned int pos;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
struct bg *vpm_work;
|
||||||
int anamods, digimods, curchan, curspan;
|
int anamods, digimods, curchan, curspan;
|
||||||
|
|
||||||
neonmwi_offlimit_cycles = neonmwi_offlimit / MS_PER_HOOKCHECK;
|
neonmwi_offlimit_cycles = neonmwi_offlimit / MS_PER_HOOKCHECK;
|
||||||
@ -5511,6 +5622,12 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
/* first we have to make sure that we process all module data, we'll fine-tune it later in this routine. */
|
/* 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;
|
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 */
|
/* Now track down what modules are installed */
|
||||||
wctdm_identify_modules(wc);
|
wctdm_identify_modules(wc);
|
||||||
|
|
||||||
@ -5518,8 +5635,14 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
|
|
||||||
if (fatal_signal_pending(current)) {
|
if (fatal_signal_pending(current)) {
|
||||||
wctdm_back_out_gracefully(wc);
|
wctdm_back_out_gracefully(wc);
|
||||||
|
bg_join(vpm_work);
|
||||||
return -EINTR;
|
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.
|
* 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.
|
* Empty and analog modules get a common span which is allocated outside of this loop.
|
||||||
@ -5540,6 +5663,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
"detected on a non-hybrid card. "
|
"detected on a non-hybrid card. "
|
||||||
"This is unsupported.\n");
|
"This is unsupported.\n");
|
||||||
wctdm_back_out_gracefully(wc);
|
wctdm_back_out_gracefully(wc);
|
||||||
|
bg_join(vpm_work);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
wc->spans[curspan] = wctdm_init_span(wc, curspan,
|
wc->spans[curspan] = wctdm_init_span(wc, curspan,
|
||||||
@ -5547,6 +5671,7 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
pos);
|
pos);
|
||||||
if (!wc->spans[curspan]) {
|
if (!wc->spans[curspan]) {
|
||||||
wctdm_back_out_gracefully(wc);
|
wctdm_back_out_gracefully(wc);
|
||||||
|
bg_join(vpm_work);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
b4 = mod->mod.bri;
|
b4 = mod->mod.bri;
|
||||||
@ -5616,7 +5741,6 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
|
|
||||||
wc->avchannels = curchan;
|
wc->avchannels = curchan;
|
||||||
|
|
||||||
wctdm_initialize_vpm(wc);
|
|
||||||
|
|
||||||
#ifdef USE_ASYNC_INIT
|
#ifdef USE_ASYNC_INIT
|
||||||
async_synchronize_cookie(cookie);
|
async_synchronize_cookie(cookie);
|
||||||
@ -5722,8 +5846,9 @@ static void __devexit wctdm_remove_one(struct pci_dev *pdev)
|
|||||||
remove_sysfs_files(wc);
|
remove_sysfs_files(wc);
|
||||||
|
|
||||||
if (vpmadt032) {
|
if (vpmadt032) {
|
||||||
|
flush_workqueue(vpmadt032->wq);
|
||||||
clear_bit(VPM150M_ACTIVE, &vpmadt032->control);
|
clear_bit(VPM150M_ACTIVE, &vpmadt032->control);
|
||||||
flush_scheduled_work();
|
flush_workqueue(vpmadt032->wq);
|
||||||
} else if (vpmoct) {
|
} else if (vpmoct) {
|
||||||
while (wctdm_wait_for_ready(wc))
|
while (wctdm_wait_for_ready(wc))
|
||||||
schedule();
|
schedule();
|
||||||
|
Loading…
Reference in New Issue
Block a user