wct4xxp: If linemode changed via sysfs, reset the complete part.

This works around some issues with older versions of the firmware not
working properly after the linemode is changed via sysfs. Basically the
intent is to simulate redoing a complete driver reload with a new
linemode.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
This commit is contained in:
Shaun Ruffell 2013-11-05 13:26:05 -06:00
parent a5a52dbe94
commit a648cef0f6

View File

@ -299,6 +299,7 @@ struct t4_span {
unsigned long alarmcheck_time; unsigned long alarmcheck_time;
int spanflags; int spanflags;
int syncpos; int syncpos;
#ifdef SUPPORT_GEN1 #ifdef SUPPORT_GEN1
int e1check; /* E1 check */ int e1check; /* E1 check */
#endif #endif
@ -345,6 +346,7 @@ struct t4 {
int irq; /* IRQ used by device */ int irq; /* IRQ used by device */
int order; /* Order */ int order; /* Order */
const struct devtype *devtype; const struct devtype *devtype;
unsigned int reset_required:1; /* If reset needed in serial_setup */
unsigned int falc31:1; /* are we falc v3.1 (atomic not necessary) */ unsigned int falc31:1; /* are we falc v3.1 (atomic not necessary) */
unsigned int t1e1:8; /* T1 / E1 select pins */ unsigned int t1e1:8; /* T1 / E1 select pins */
int ledreg; /* LED Register */ int ledreg; /* LED Register */
@ -1893,6 +1895,33 @@ static void setup_chunks(struct t4 *wc, int which)
} }
} }
static int __t4_hardware_init_1(struct t4 *wc, unsigned int cardflags,
bool first_time);
static int __t4_hardware_init_2(struct t4 *wc, bool first_time);
static int t4_hardware_stop(struct t4 *wc);
static void t4_framer_reset(struct t4 *wc)
{
const bool first_time = false;
bool have_vpm = wc->vpm != NULL;
if (have_vpm) {
release_vpm450m(wc->vpm);
wc->vpm = NULL;
}
t4_hardware_stop(wc);
__t4_set_sclk_src(wc, WC_SELF, 0, 0);
__t4_hardware_init_1(wc, wc->devtype->flags, first_time);
__t4_hardware_init_2(wc, first_time);
if (have_vpm) {
t4_vpm_init(wc);
wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0;
t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
}
setup_chunks(wc, 0);
wc->lastindex = 0;
}
/** /**
* t4_serial_setup - Setup serial parameters and system interface. * t4_serial_setup - Setup serial parameters and system interface.
* @wc: The card to configure. * @wc: The card to configure.
@ -1902,6 +1931,7 @@ static void t4_serial_setup(struct t4 *wc)
{ {
unsigned long flags; unsigned long flags;
unsigned int unit; unsigned int unit;
bool reset_required = false;
if (debug) { if (debug) {
dev_info(&wc->dev->dev, dev_info(&wc->dev->dev,
@ -1909,6 +1939,14 @@ static void t4_serial_setup(struct t4 *wc)
wc->numspans); wc->numspans);
} }
spin_lock_irqsave(&wc->reglock, flags);
reset_required = wc->reset_required > 0;
wc->reset_required = 0;
spin_unlock_irqrestore(&wc->reglock, flags);
if (reset_required)
t4_framer_reset(wc);
spin_lock_irqsave(&wc->reglock, flags); spin_lock_irqsave(&wc->reglock, flags);
/* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from
* channel 0 */ * channel 0 */
@ -2059,6 +2097,7 @@ static void t4_span_assigned(struct dahdi_span *span)
struct t4 *wc = tspan->owner; struct t4 *wc = tspan->owner;
struct dahdi_span *pos; struct dahdi_span *pos;
unsigned int unassigned_spans = 0; unsigned int unassigned_spans = 0;
unsigned long flags;
/* We use this to make sure all the spans are assigned before /* We use this to make sure all the spans are assigned before
* running the serial setup. */ * running the serial setup. */
@ -2067,8 +2106,14 @@ static void t4_span_assigned(struct dahdi_span *span)
++unassigned_spans; ++unassigned_spans;
} }
if (0 == unassigned_spans) if (0 == unassigned_spans) {
t4_serial_setup(wc); t4_serial_setup(wc);
set_bit(T4_CHECK_TIMING, &wc->checkflag);
spin_lock_irqsave(&wc->reglock, flags);
__t4_set_sclk_src(wc, WC_SELF, 0, 0);
spin_unlock_irqrestore(&wc->reglock, flags);
}
} }
static void free_wc(struct t4 *wc) static void free_wc(struct t4 *wc)
@ -2230,6 +2275,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
enum linemode mode; enum linemode mode;
const char *old_name; const char *old_name;
static DEFINE_MUTEX(linemode_lock); static DEFINE_MUTEX(linemode_lock);
unsigned long flags;
dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name,
dahdi_spantype2str(linemode)); dahdi_spantype2str(linemode));
@ -2237,6 +2283,10 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
if (span->spantype == linemode) if (span->spantype == linemode)
return 0; return 0;
spin_lock_irqsave(&wc->reglock, flags);
wc->reset_required = 1;
spin_unlock_irqrestore(&wc->reglock, flags);
/* Do not allow the t1e1 member to be changed by multiple threads. */ /* Do not allow the t1e1 member to be changed by multiple threads. */
mutex_lock(&linemode_lock); mutex_lock(&linemode_lock);
old_name = dahdi_spantype2str(span->spantype); old_name = dahdi_spantype2str(span->spantype);
@ -2833,6 +2883,10 @@ static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig)
__t4_framer_out(wc, unit, 0x17, 0x04 | imr3extra); /* IMR3: AIS */ __t4_framer_out(wc, unit, 0x17, 0x04 | imr3extra); /* IMR3: AIS */
__t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: We care about slips on transmit */ __t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: We care about slips on transmit */
__t4_framer_out(wc, unit, 0x2f, 0x00);
__t4_framer_out(wc, unit, 0x30, 0x00);
__t4_framer_out(wc, unit, 0x31, 0x00);
dev_info(&wc->dev->dev, "TE%dXXP: Span %d configured for %s/%s%s\n", dev_info(&wc->dev->dev, "TE%dXXP: Span %d configured for %s/%s%s\n",
wc->numspans, unit + 1, framing, line, crc4); wc->numspans, unit + 1, framing, line, crc4);
} }
@ -4868,17 +4922,18 @@ cleanup:
return res; return res;
} }
static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags) static int
__t4_hardware_init_1(struct t4 *wc, unsigned int cardflags, bool first_time)
{ {
unsigned int version; unsigned int version;
int res; int res;
version = t4_pci_in(wc, WC_VERSION); version = t4_pci_in(wc, WC_VERSION);
if (is_octal(wc)) { if (is_octal(wc) && first_time) {
dev_info(&wc->dev->dev, "Firmware Version: %01x.%02x\n", dev_info(&wc->dev->dev, "Firmware Version: %01x.%02x\n",
(version & 0xf00) >> 8, (version & 0xf00) >> 8,
version & 0xff); version & 0xff);
} else { } else if (first_time) {
dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version); dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version);
} }
if (debug) { if (debug) {
@ -4926,30 +4981,33 @@ static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
t4_pci_out(wc, WC_INTR, 0x00000000); t4_pci_out(wc, WC_INTR, 0x00000000);
/* Read T1/E1 status */ /* Read T1/E1 status */
if (!strcasecmp("auto", default_linemode)) { if (first_time) {
if (-1 == t1e1override) { if (!strcasecmp("auto", default_linemode)) {
wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) & 0x0f00) >> 8); if (-1 == t1e1override) {
wc->t1e1 &= 0xf; wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) &
if (is_octal(wc)) { 0x0f00) >> 8);
wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) & wc->t1e1 &= 0xf;
0x0f00) >> 4; if (is_octal(wc)) {
wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) &
0x0f00) >> 4;
}
} else {
dev_warn(&wc->dev->dev,
"'t1e1override' is deprecated. Please use 'default_linemode'.\n");
wc->t1e1 = t1e1override & 0xf;
} }
} else if (!strcasecmp("t1", default_linemode)) {
wc->t1e1 = 0;
} else if (!strcasecmp("e1", default_linemode)) {
wc->t1e1 = 0xff;
} else if (!strcasecmp("j1", default_linemode)) {
wc->t1e1 = 0;
j1mode = 1;
} else { } else {
dev_warn(&wc->dev->dev, "'t1e1override' is deprecated. " dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n",
"Please use 'default_linemode'.\n"); default_linemode);
wc->t1e1 = t1e1override & 0xf; wc->t1e1 = 0;
} }
} else if (!strcasecmp("t1", default_linemode)) {
wc->t1e1 = 0;
} else if (!strcasecmp("e1", default_linemode)) {
wc->t1e1 = 0xff;
} else if (!strcasecmp("j1", default_linemode)) {
wc->t1e1 = 0;
j1mode = 1;
} else {
dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n",
default_linemode);
wc->t1e1 = 0;
} }
wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28; wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28;
@ -4978,7 +5036,12 @@ static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
return 0; return 0;
} }
static int t4_hardware_init_2(struct t4 *wc) static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
{
return __t4_hardware_init_1(wc, cardflags, true);
}
static int __t4_hardware_init_2(struct t4 *wc, bool first_time)
{ {
int x; int x;
unsigned int regval; unsigned int regval;
@ -5010,13 +5073,14 @@ static int t4_hardware_init_2(struct t4 *wc)
if (!is_octal(wc)) { if (!is_octal(wc)) {
regval = t4_framer_in(wc, 0, 0x4a); regval = t4_framer_in(wc, 0, 0x4a);
if (regval == 0x05) { if (first_time && regval == 0x05) {
dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or " dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or "
"earlier\n"); "earlier\n");
} else if (regval == 0x20) { } else if (regval == 0x20) {
dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n"); if (first_time)
dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n");
wc->falc31 = 1; wc->falc31 = 1;
} else { } else if (first_time) {
dev_info(&wc->dev->dev, "FALC Framer Version: Unknown " dev_info(&wc->dev->dev, "FALC Framer Version: Unknown "
"(VSTR = 0x%02x)\n", regval); "(VSTR = 0x%02x)\n", regval);
} }
@ -5036,14 +5100,24 @@ static int t4_hardware_init_2(struct t4 *wc)
t4_pci_in(wc, x)); t4_pci_in(wc, x));
} }
} }
wc->gpio = 0x00000000;
t4_pci_out(wc, WC_GPIO, wc->gpio);
t4_gpio_setdir(wc, (1 << 17), (1 << 17));
t4_gpio_setdir(wc, (0xff), (0xff));
return 0; return 0;
} }
static int t4_hardware_init_2(struct t4 *wc)
{
return __t4_hardware_init_2(wc, true);
}
static int __devinit t4_launch(struct t4 *wc) static int __devinit t4_launch(struct t4 *wc)
{ {
int x; int x;
int res; int res;
unsigned long flags;
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags)) if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags))
return 0; return 0;
@ -5075,17 +5149,14 @@ static int __devinit t4_launch(struct t4 *wc)
&wc->ddev->spans); &wc->ddev->spans);
} }
tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
res = dahdi_register_device(wc->ddev, &wc->dev->dev); res = dahdi_register_device(wc->ddev, &wc->dev->dev);
if (res) { if (res) {
dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n"); dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n");
return res; return res;
} }
set_bit(T4_CHECK_TIMING, &wc->checkflag);
spin_lock_irqsave(&wc->reglock, flags);
__t4_set_sclk_src(wc, WC_SELF, 0, 0);
spin_unlock_irqrestore(&wc->reglock, flags);
tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
return 0; return 0;
} }
@ -5299,10 +5370,6 @@ t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&wc->dev->dev, dev_info(&wc->dev->dev,
"Found a Wildcard: %s\n", wc->devtype->desc); "Found a Wildcard: %s\n", wc->devtype->desc);
} }
wc->gpio = 0x00000000;
t4_pci_out(wc, WC_GPIO, wc->gpio);
t4_gpio_setdir(wc, (1 << 17), (1 << 17));
t4_gpio_setdir(wc, (0xff), (0xff));
#ifdef VPM_SUPPORT #ifdef VPM_SUPPORT
if (!wc->vpm) { if (!wc->vpm) {