From a648cef0f6d4552f64bf3cd57561c0dcb0c89fed Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Tue, 5 Nov 2013 13:26:05 -0600 Subject: [PATCH] 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 --- drivers/dahdi/wct4xxp/base.c | 145 +++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 39 deletions(-) diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c index 0f9e750..e7aa8bd 100644 --- a/drivers/dahdi/wct4xxp/base.c +++ b/drivers/dahdi/wct4xxp/base.c @@ -299,6 +299,7 @@ struct t4_span { unsigned long alarmcheck_time; int spanflags; int syncpos; + #ifdef SUPPORT_GEN1 int e1check; /* E1 check */ #endif @@ -345,6 +346,7 @@ struct t4 { int irq; /* IRQ used by device */ int order; /* Order */ 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 t1e1:8; /* T1 / E1 select pins */ 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. * @wc: The card to configure. @@ -1902,6 +1931,7 @@ static void t4_serial_setup(struct t4 *wc) { unsigned long flags; unsigned int unit; + bool reset_required = false; if (debug) { dev_info(&wc->dev->dev, @@ -1909,6 +1939,14 @@ static void t4_serial_setup(struct t4 *wc) 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); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from * channel 0 */ @@ -2059,6 +2097,7 @@ static void t4_span_assigned(struct dahdi_span *span) struct t4 *wc = tspan->owner; struct dahdi_span *pos; unsigned int unassigned_spans = 0; + unsigned long flags; /* We use this to make sure all the spans are assigned before * running the serial setup. */ @@ -2067,8 +2106,14 @@ static void t4_span_assigned(struct dahdi_span *span) ++unassigned_spans; } - if (0 == unassigned_spans) + if (0 == unassigned_spans) { 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) @@ -2230,6 +2275,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) enum linemode mode; const char *old_name; static DEFINE_MUTEX(linemode_lock); + unsigned long flags; dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, dahdi_spantype2str(linemode)); @@ -2237,6 +2283,10 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) if (span->spantype == linemode) 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. */ mutex_lock(&linemode_lock); 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, 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", wc->numspans, unit + 1, framing, line, crc4); } @@ -4868,17 +4922,18 @@ cleanup: 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; int res; 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", (version & 0xf00) >> 8, version & 0xff); - } else { + } else if (first_time) { dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version); } 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); /* Read T1/E1 status */ - if (!strcasecmp("auto", default_linemode)) { - if (-1 == t1e1override) { - wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) & 0x0f00) >> 8); - wc->t1e1 &= 0xf; - if (is_octal(wc)) { - wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) & - 0x0f00) >> 4; + if (first_time) { + if (!strcasecmp("auto", default_linemode)) { + if (-1 == t1e1override) { + wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) & + 0x0f00) >> 8); + wc->t1e1 &= 0xf; + 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 { - dev_warn(&wc->dev->dev, "'t1e1override' is deprecated. " - "Please use 'default_linemode'.\n"); - wc->t1e1 = t1e1override & 0xf; + dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n", + default_linemode); + 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; @@ -4978,7 +5036,12 @@ static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags) 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; unsigned int regval; @@ -5010,13 +5073,14 @@ static int t4_hardware_init_2(struct t4 *wc) if (!is_octal(wc)) { 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 " "earlier\n"); } 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; - } else { + } else if (first_time) { dev_info(&wc->dev->dev, "FALC Framer Version: Unknown " "(VSTR = 0x%02x)\n", regval); } @@ -5036,14 +5100,24 @@ static int t4_hardware_init_2(struct t4 *wc) 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; } +static int t4_hardware_init_2(struct t4 *wc) +{ + return __t4_hardware_init_2(wc, true); +} + static int __devinit t4_launch(struct t4 *wc) { int x; int res; - unsigned long flags; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags)) return 0; @@ -5075,17 +5149,14 @@ static int __devinit t4_launch(struct t4 *wc) &wc->ddev->spans); } + tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc); + res = dahdi_register_device(wc->ddev, &wc->dev->dev); if (res) { dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n"); 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; } @@ -5299,10 +5370,6 @@ t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&wc->dev->dev, "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 if (!wc->vpm) {