From fc5e9b162bdb70b77afef47dde086b0edc0d2273 Mon Sep 17 00:00:00 2001 From: mattf Date: Sat, 28 Apr 2007 21:07:35 +0000 Subject: Fix for potential deadlock in wct4xxp driver git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@2469 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wct4xxp/base.c | 152 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 63 deletions(-) (limited to 'wct4xxp') diff --git a/wct4xxp/base.c b/wct4xxp/base.c index 5f3e89a..8ad1b56 100644 --- a/wct4xxp/base.c +++ b/wct4xxp/base.c @@ -360,8 +360,8 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data); static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan); static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan); static void __t4_set_timing_source(struct t4 *wc, int unit); -static void __t4_check_alarms(struct t4 *wc, int span); -static void __t4_check_sigbits(struct t4 *wc, int span); +static void t4_check_alarms(struct t4 *wc, int span); +static void t4_check_sigbits(struct t4 *wc, int span); #define WC_RDADDR 0 #define WC_WRADDR 1 @@ -747,7 +747,7 @@ static void t4_check_vpm450(struct t4 *wc) } } -static void __t4_check_vpm400(struct t4 *wc, unsigned int newio) +static void t4_check_vpm400(struct t4 *wc, unsigned int newio) { unsigned int digit, regval = 0; unsigned int regbyte; @@ -755,12 +755,14 @@ static void __t4_check_vpm400(struct t4 *wc, unsigned int newio) short energy=0; static unsigned int lastio = 0; struct t4_span *ts; + unsigned long flags; if (debug && (newio != lastio)) printk("Last was %08x, new is %08x\n", lastio, newio); lastio = newio; + spin_lock_irqsave(&wc->reglock, flags); for(x = 0; x < 8; x++) { if (newio & (1 << (7 - x))) continue; @@ -789,23 +791,33 @@ static void __t4_check_vpm400(struct t4 *wc, unsigned int newio) } ts->dtmfactive |= (1 << base); if (ts->dtmfdigit[base]) { - if (ts->dtmfmask & (1 << base)) + if (ts->dtmfmask & (1 << base)) { + spin_unlock_irqrestore(&wc->reglock, flags); zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFUP | ts->dtmfdigit[base])); + spin_lock_irqsave(&wc->reglock, flags); + } } ts->dtmfdigit[base] = digit; - if (ts->dtmfmask & (1 << base)) + if (ts->dtmfmask & (1 << base)) { + spin_unlock_irqrestore(&wc->reglock, flags); zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFDOWN | digit)); + spin_lock_irqsave(&wc->reglock, flags); + } if (ts->dtmfmutemask & (1 << base)) { /* Mute active receive buffer*/ - unsigned long flags; + unsigned long flags2; struct zt_chan *chan = &ts->span.chans[base]; int y; - spin_lock_irqsave(&chan->lock, flags); + /* We can't hold the reglock and the channel lock at the same time. If we do so, + * we can cause a deadlock scenario */ + spin_unlock_irqrestore(&wc->reglock, flags); + spin_lock_irqsave(&chan->lock, flags2); for (y=0;ynumbufs;y++) { if ((chan->inreadbuf > -1) && (chan->readidx[y])) memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]); } - spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock_irqrestore(&chan->lock, flags2); + spin_lock_irqsave(&wc->reglock, flags); } if (debug) printk("Digit Seen: %d, Span: %d, channel: %d, energy: %02x, 'channel %d' chip %d\n", digit, x % 4, base + 1, energy, channel, x); @@ -833,8 +845,11 @@ static void __t4_check_vpm400(struct t4 *wc, unsigned int newio) base -= 4; ts->dtmfactive &= ~(1 << base); if (ts->dtmfdigit[base]) { - if (ts->dtmfmask & (1 << base)) + if (ts->dtmfmask & (1 << base)) { + spin_unlock_irqrestore(&wc->reglock, flags); zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFUP | ts->dtmfdigit[base])); + spin_lock_irqsave(&wc->reglock, flags); + } } digit = ts->dtmfdigit[base]; ts->dtmfdigit[base] = 0; @@ -846,6 +861,7 @@ static void __t4_check_vpm400(struct t4 *wc, unsigned int newio) } } + spin_unlock_irqrestore(&wc->reglock, flags); } #endif @@ -1545,11 +1561,6 @@ static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlev __t4_framer_out(wc, unit, 0x18, 0xff); /* IMR4: We don't care about slips on transmit */ } - if (!polling) { - __t4_check_alarms(wc, unit); - __t4_check_sigbits(wc, unit); - } - printk("TE%dXXP: Span %d configured for %s/%s\n", wc->numspans, unit + 1, framing, line); } @@ -1632,10 +1643,6 @@ static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig) __t4_framer_out(wc, unit, 0x17, 0xc7 | imr3extra); /* IMR3: We care about AIS and friends */ __t4_framer_out(wc, unit, 0x18, 0xff); /* IMR4: We don't care about slips on transmit */ } - if (!polling) { - __t4_check_alarms(wc, unit); - __t4_check_sigbits(wc, unit); - } printk("TE%dXXP: Span %d configured for %s/%s%s\n", wc->numspans, unit + 1, framing, line, crc4); } @@ -1700,13 +1707,13 @@ static int t4_startup(struct zt_span *span) if (noburst) wc->dmactrl |= (1 << 26); __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); - if (!polling) { - __t4_check_alarms(wc, span->offset); - __t4_check_sigbits(wc, span->offset); - } } spin_unlock_irqrestore(&wc->reglock, flags); + + t4_check_alarms(wc, span->offset); + t4_check_sigbits(wc, span->offset); + if (wc->tspans[0]->sync == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno); if (wc->tspans[1]->sync == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno); if (wc->numspans == 4) { @@ -1963,7 +1970,7 @@ static void t4_transmitprep(struct t4 *wc, int irq) } #endif -static void __t4_check_sigbits(struct t4 *wc, int span) +static void t4_check_sigbits(struct t4 *wc, int span) { int a,i,rxs; struct t4_span *ts = wc->tspans[span]; @@ -1973,9 +1980,10 @@ static void __t4_check_sigbits(struct t4 *wc, int span) if (!(ts->span.flags & ZT_FLAG_RUNNING)) return; + if (ts->spantype == TYPE_E1) { for (i = 0; i < 15; i++) { - a = __t4_framer_in(wc, span, 0x71 + i); + a = t4_framer_in(wc, span, 0x71 + i); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(ts->span.chans[i+16].sig & ZT_SIG_CLEAR)) { @@ -1990,7 +1998,7 @@ static void __t4_check_sigbits(struct t4 *wc, int span) } } else if (ts->span.lineconfig & ZT_CONFIG_D4) { for (i = 0; i < 24; i+=4) { - a = __t4_framer_in(wc, span, 0x70 + (i>>2)); + a = t4_framer_in(wc, span, 0x70 + (i>>2)); /* Get high channel in low bits */ rxs = (a & 0x3) << 2; if (!(ts->span.chans[i+3].sig & ZT_SIG_CLEAR)) { @@ -2015,7 +2023,7 @@ static void __t4_check_sigbits(struct t4 *wc, int span) } } else { for (i = 0; i < 24; i+=2) { - a = __t4_framer_in(wc, span, 0x70 + (i>>1)); + a = t4_framer_in(wc, span, 0x70 + (i>>1)); /* Get high channel in low bits */ rxs = (a & 0xf); if (!(ts->span.chans[i+1].sig & ZT_SIG_CLEAR)) { @@ -2035,16 +2043,19 @@ static void __t4_check_sigbits(struct t4 *wc, int span) } } -static void __t4_check_alarms(struct t4 *wc, int span) +static void t4_check_alarms(struct t4 *wc, int span) { unsigned char c,d; int alarms; int x,j; struct t4_span *ts = wc->tspans[span]; + unsigned long flags; if (!(ts->span.flags & ZT_FLAG_RUNNING)) return; + spin_lock_irqsave(&wc->reglock, flags); + c = __t4_framer_in(wc, span, 0x4c); d = __t4_framer_in(wc, span, 0x4d); @@ -2154,15 +2165,21 @@ static void __t4_check_alarms(struct t4 *wc, int span) if (ts->span.mainttimer || ts->span.maintstat) alarms |= ZT_ALARM_LOOPBACK; ts->span.alarms = alarms; + + spin_unlock_irqrestore(&wc->reglock, flags); + zt_alarm_notify(&ts->span); } -static void __t4_do_counters(struct t4 *wc) +static void t4_do_counters(struct t4 *wc) { int span; + unsigned long flags; + for (span=0;spannumspans;span++) { struct t4_span *ts = wc->tspans[span]; int docheck=0; + spin_lock_irqsave(&wc->reglock, flags); if (ts->loopupcnt || ts->loopdowncnt) docheck++; if (ts->alarmtimer) { @@ -2171,9 +2188,10 @@ static void __t4_do_counters(struct t4 *wc) ts->span.alarms &= ~(ZT_ALARM_RECOVER); } } + spin_unlock_irqrestore(&wc->reglock, flags); if (docheck) { if (!polling) - __t4_check_alarms(wc, span); + t4_check_alarms(wc, span); zt_alarm_notify(&ts->span); } } @@ -2301,11 +2319,7 @@ ZAP_IRQ_HANDLER(t4_interrupt) } } #endif - spin_lock_irqsave(&wc->reglock, flags); - - __handle_leds(wc); - - __t4_do_counters(wc); + t4_do_counters(wc); x = wc->intcount & 15 /* 63 */; switch(x) { @@ -2313,18 +2327,23 @@ ZAP_IRQ_HANDLER(t4_interrupt) case 1: case 2: case 3: - __t4_check_sigbits(wc, x); + t4_check_sigbits(wc, x); break; case 4: case 5: case 6: case 7: - __t4_check_alarms(wc, x - 4); + t4_check_alarms(wc, x - 4); break; } + spin_lock_irqsave(&wc->reglock, flags); + + __handle_leds(wc); + if (wc->checktiming > 0) __t4_set_timing_source_auto(wc); + spin_unlock_irqrestore(&wc->reglock, flags); #ifdef LINUX26 return IRQ_RETVAL(1); @@ -2332,7 +2351,7 @@ ZAP_IRQ_HANDLER(t4_interrupt) } #endif -static inline void __t4_framer_interrupt(struct t4 *wc, int span) +static inline void t4_framer_interrupt(struct t4 *wc, int span) { /* Check interrupts for a given span */ unsigned char gis, isr0=0, isr1=0, isr2=0, isr3=0, isr4; @@ -2342,40 +2361,40 @@ static inline void __t4_framer_interrupt(struct t4 *wc, int span) printk("framer interrupt span %d:%d!\n", wc->num, span + 1); ts = wc->tspans[span]; - gis = __t4_framer_in(wc, span, 0x6e); + gis = t4_framer_in(wc, span, 0x6e); if (ts->spantype == TYPE_E1) { /* E1 checks */ if (gis & 0x1) - isr0 = __t4_framer_in(wc, span, 0x68); + isr0 = t4_framer_in(wc, span, 0x68); if (gis & 0x2) - isr1 = __t4_framer_in(wc, span, 0x69); + isr1 = t4_framer_in(wc, span, 0x69); if (gis & 0x4) - isr2 = __t4_framer_in(wc, span, 0x6a); + isr2 = t4_framer_in(wc, span, 0x6a); if (gis & 0x8) - isr3 = __t4_framer_in(wc, span, 0x6b); + isr3 = t4_framer_in(wc, span, 0x6b); if (isr0) - __t4_check_sigbits(wc, span); + t4_check_sigbits(wc, span); if ((isr3 & 0x38) || isr2 || isr1) - __t4_check_alarms(wc, span); + t4_check_alarms(wc, span); if (debug & DEBUG_FRAMER) printk("gis: %02x, isr0: %02x, isr1: %02x, isr2: %02x, isr3: %02x\n", gis, isr0, isr1, isr2, isr3); } else { /* T1 checks */ if (gis & 0x1) - isr0 = __t4_framer_in(wc, span, 0x68); + isr0 = t4_framer_in(wc, span, 0x68); if (gis & 0x4) - isr2 = __t4_framer_in(wc, span, 0x6a); + isr2 = t4_framer_in(wc, span, 0x6a); if (gis & 0x8) - isr3 = __t4_framer_in(wc, span, 0x6b); + isr3 = t4_framer_in(wc, span, 0x6b); if (isr0) - __t4_check_sigbits(wc, span); + t4_check_sigbits(wc, span); if (isr2 || (isr3 & 0x08)) - __t4_check_alarms(wc, span); + t4_check_alarms(wc, span); if (debug & DEBUG_FRAMER) printk("gis: %02x, isr0: %02x, isr1: %02x, irs2: %02x, isr3: %02x\n", gis, isr0, isr1, isr2, isr3); } @@ -2385,7 +2404,7 @@ static inline void __t4_framer_interrupt(struct t4 *wc, int span) if (isr3 & 0x01) printk("TE%d10P: RECEIVE slip POSITIVE on span %d\n", wc->numspans, span + 1); if (gis & 0x10) - isr4 = __t4_framer_in(wc, span, 0x6c); + isr4 = t4_framer_in(wc, span, 0x6c); else isr4 = 0; if (isr4 & 0x80) @@ -2472,10 +2491,8 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) #endif } - spin_lock_irqsave(&wc->reglock, flags); - if (status & 0x2) - __t4_do_counters(wc); + t4_do_counters(wc); if (polling && (status & 0x2)) { x = wc->intcount & 15 /* 63 */; @@ -2484,26 +2501,29 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) case 1: case 2: case 3: - __t4_check_sigbits(wc, x); + t4_check_sigbits(wc, x); break; case 4: case 5: case 6: case 7: - __t4_check_alarms(wc, x - 4); + t4_check_alarms(wc, x - 4); break; } } else if (status & 0x1) { - cis = __t4_framer_in(wc, 0, 0x6f); + cis = t4_framer_in(wc, 0, 0x6f); if (cis & 0x1) - __t4_framer_interrupt(wc, 0); + t4_framer_interrupt(wc, 0); if (cis & 0x2) - __t4_framer_interrupt(wc, 1); + t4_framer_interrupt(wc, 1); if (cis & 0x4) - __t4_framer_interrupt(wc, 2); + t4_framer_interrupt(wc, 2); if (cis & 0x8) - __t4_framer_interrupt(wc, 3); + t4_framer_interrupt(wc, 3); } + + spin_lock_irqsave(&wc->reglock, flags); + #ifdef VPM_SUPPORT if (wc->vpm) { if (!wc->vpm450m && !(wc->intcount % 16) && !(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) { @@ -2530,8 +2550,11 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) printk("Finished digit on span %d, channel %d (energy = %02x < %02x) 'channel' %d, chip %d!\n", span, y + 1, energy, ts->dtmfenergy[y], channel, chip); if (debug & DEBUG_DTMF) printk("Finished digit '%c' on channel %d of span %d\n", ts->dtmfdigit[y], y + 1, span); - if (ts->dtmfmask & (1 << y)) + if (ts->dtmfmask & (1 << y)) { + spin_unlock_irqrestore(&wc->reglock, flags); zt_qevent_lock(&ts->span.chans[y], (ZT_EVENT_DTMFUP | ts->dtmfdigit[y])); + spin_lock_irqsave(&wc->reglock, flags); + } ts->dtmfenergy[y] = 0; ts->dtmfdigit[y] = 0; ts->dtmfactive &= ~(1 << y); @@ -2549,8 +2572,11 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) if (!(wc->intcount & 0xf)) { needcheckvpm450 = 1; } - } else if ((status & 0xff00) != 0xff00) - __t4_check_vpm400(wc, (status & 0xff00) >> 8); + } else if ((status & 0xff00) != 0xff00) { + spin_unlock_irqrestore(&wc->reglock, flags); + t4_check_vpm400(wc, (status & 0xff00) >> 8); + spin_lock_irqsave(&wc->reglock, flags); + } } #endif -- cgit v1.2.3