diff options
Diffstat (limited to 'wct4xxp/base.c')
-rw-r--r-- | wct4xxp/base.c | 186 |
1 files changed, 115 insertions, 71 deletions
diff --git a/wct4xxp/base.c b/wct4xxp/base.c index 9b86342..51b0c64 100644 --- a/wct4xxp/base.c +++ b/wct4xxp/base.c @@ -369,8 +369,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, int master, int slave); -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 @@ -765,7 +765,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; @@ -773,12 +773,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; @@ -807,23 +809,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;y<chan->numbufs;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); @@ -851,8 +863,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; @@ -864,6 +879,7 @@ static void __t4_check_vpm400(struct t4 *wc, unsigned int newio) } } + spin_unlock_irqrestore(&wc->reglock, flags); } #endif @@ -1186,12 +1202,16 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) return 0; } -static void inline __t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct t4_span *ts) +static void inline t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct t4_span *ts) { int res, i, size = 32; unsigned char buf[32]; + unsigned long flags; res = zt_hdlc_getbuf(ts->sigchan, buf, &size); + + spin_lock_irqsave(&wc->reglock, flags); + if (debug & DEBUG_FRAMER) printk("Got buffer sized %d and res %d for %d\n", size, res, span); if (size > 0) { ts->sigactive = 1; @@ -1222,6 +1242,8 @@ static void inline __t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct } else if (res < 0) ts->sigactive = 0; + + spin_unlock_irqrestore(&wc->reglock, flags); } static void t4_hdlc_hard_xmit(struct zt_chan *chan) @@ -1238,9 +1260,11 @@ static void t4_hdlc_hard_xmit(struct zt_chan *chan) return; } if (debug & DEBUG_FRAMER) printk("t4_hdlc_hard_xmit on channel %s (sigchan %s), sigactive=%d\n", chan->name, ts->sigchan->name, ts->sigactive); - if ((ts->sigchan == chan) && !ts->sigactive) - __t4_hdlc_xmit_fifo(wc, span, ts); - spin_unlock_irqrestore(&wc->reglock, flags); + if ((ts->sigchan == chan) && !ts->sigactive) { + spin_unlock_irqrestore(&wc->reglock, flags); + t4_hdlc_xmit_fifo(wc, span, ts); + } else + spin_unlock_irqrestore(&wc->reglock, flags); } static int t4_maint(struct zt_span *span, int cmd) @@ -1868,11 +1892,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); } @@ -1956,10 +1975,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); } @@ -2024,10 +2039,6 @@ 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); - } /* Startup HDLC controller too */ if (ts->sigchan) { if (__hdlc_start(wc, span->offset, ts->sigchan, ts->sigmode)) { @@ -2040,6 +2051,10 @@ static int t4_startup(struct zt_span *span) } 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) { @@ -2297,7 +2312,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]; @@ -2307,9 +2322,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)) { @@ -2324,7 +2340,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)) { @@ -2349,7 +2365,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)) { @@ -2369,16 +2385,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); @@ -2488,15 +2507,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;span<wc->numspans;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) { @@ -2505,9 +2530,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); } } @@ -2575,38 +2601,39 @@ static inline void __handle_leds(struct t4 *wc) #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, isr1, isr2, isr3, isr4; int readsize = -1; struct t4_span *ts = wc->tspans[span]; + unsigned long flags; if (debug & DEBUG_FRAMER) printk("framer interrupt span %d:%d!\n", wc->num, span + 1); /* 1st gen cards isn't used interrupts */ - gis = __t4_framer_in(wc, span, FRMR_GIS); - isr0 = (gis & FRMR_GIS_ISR0) ? __t4_framer_in(wc, span, FRMR_ISR0) : 0; - isr1 = (gis & FRMR_GIS_ISR1) ? __t4_framer_in(wc, span, FRMR_ISR1) : 0; - isr2 = (gis & FRMR_GIS_ISR2) ? __t4_framer_in(wc, span, FRMR_ISR2) : 0; - isr3 = (gis & FRMR_GIS_ISR3) ? __t4_framer_in(wc, span, FRMR_ISR3) : 0; - isr4 = (gis & FRMR_GIS_ISR4) ? __t4_framer_in(wc, span, FRMR_ISR4) : 0; + gis = t4_framer_in(wc, span, FRMR_GIS); + isr0 = (gis & FRMR_GIS_ISR0) ? t4_framer_in(wc, span, FRMR_ISR0) : 0; + isr1 = (gis & FRMR_GIS_ISR1) ? t4_framer_in(wc, span, FRMR_ISR1) : 0; + isr2 = (gis & FRMR_GIS_ISR2) ? t4_framer_in(wc, span, FRMR_ISR2) : 0; + isr3 = (gis & FRMR_GIS_ISR3) ? t4_framer_in(wc, span, FRMR_ISR3) : 0; + isr4 = (gis & FRMR_GIS_ISR4) ? t4_framer_in(wc, span, FRMR_ISR4) : 0; if (debug & DEBUG_FRAMER) printk("gis: %02x, isr0: %02x, isr1: %02x, isr2: %02x, isr3: %02x, isr4: %02x\n", gis, isr0, isr1, isr2, isr3, isr4); if (isr0) - __t4_check_sigbits(wc, span); + t4_check_sigbits(wc, span); if (ts->spantype == TYPE_E1) { /* E1 checks */ if ((isr3 & 0x38) || isr2 || isr1) - __t4_check_alarms(wc, span); + t4_check_alarms(wc, span); } else { /* T1 checks */ if (isr2 || (isr3 & 0x08)) - __t4_check_alarms(wc, span); + t4_check_alarms(wc, span); } if (debugslips && !ts->span.alarms) { if (isr3 & 0x02) @@ -2619,9 +2646,12 @@ static inline void __t4_framer_interrupt(struct t4 *wc, int span) printk("TE%d10P: TRANSMIT slip NEGATIVE on span %d\n", wc->numspans, span + 1); } + spin_lock_irqsave(&wc->reglock, flags); /* HDLC controller checks - receive side */ - if (!ts->sigchan) + if (!ts->sigchan) { + spin_unlock_irqrestore(&wc->reglock, flags); return; + } if (isr0 & FRMR_ISR0_RME) { readsize = (__t4_framer_in(wc, span, FRMR_RBCH) << 8) | __t4_framer_in(wc, span, FRMR_RBCL); @@ -2664,6 +2694,7 @@ static inline void __t4_framer_interrupt(struct t4 *wc, int span) #endif ++ts->frames_in; + spin_unlock_irqrestore(&wc->reglock, flags); if ((debug & DEBUG_FRAMER) && !(ts->frames_in & 0x0f)) printk("Received %d frames on span %d\n", ts->frames_in, span); if (debug & DEBUG_FRAMER) printk("Received HDLC frame %d. RSIS = 0x%x (%x)\n", ts->frames_in, rsis, rsis_reg); @@ -2684,9 +2715,13 @@ static inline void __t4_framer_interrupt(struct t4 *wc, int span) zt_hdlc_finish(sigchan); if (debug & DEBUG_FRAMER) printk("Received valid HDLC frame on span %d\n", span); } + spin_lock_irqsave(&wc->reglock, flags); debug = olddebug; - } else if (isr0 & FRMR_ISR0_RPF) + } else if (isr0 & FRMR_ISR0_RPF) { + spin_unlock_irqrestore(&wc->reglock, flags); zt_hdlc_putbuf(sigchan, readbuf, readsize); + spin_lock_irqsave(&wc->reglock, flags); + } } /* Transmit side */ @@ -2700,13 +2735,17 @@ static inline void __t4_framer_interrupt(struct t4 *wc, int span) printk("Sigchan %d is %p\n", sigchan->chanpos, sigchan); if (debug & DEBUG_FRAMER) printk("Framer %d: Got XPR!\n", sigchan->span->offset); - __t4_hdlc_xmit_fifo(wc, span, ts); + spin_unlock_irqrestore(&wc->reglock, flags); + t4_hdlc_xmit_fifo(wc, span, ts); + spin_lock_irqsave(&wc->reglock, flags); } if (isr1 & FRMR_ISR1_ALLS) { if (debug & DEBUG_FRAMER) printk("ALLS received\n"); } + spin_unlock_irqrestore(&wc->reglock, flags); + } #ifdef SUPPORT_GEN1 @@ -2730,12 +2769,10 @@ ZAP_IRQ_HANDLER(t4_interrupt) /* Process framer interrupts */ status2 = t4_framer_in(wc, 0, FRMR_CIS); if (status2 & 0x0f) { - spin_lock_irqsave(&wc->reglock, flags); for (x = 0; x < wc->numspans; ++x) { if (status2 & (1 << x)) - __t4_framer_interrupt(wc, x); + t4_framer_interrupt(wc, x); } - spin_unlock_irqrestore(&wc->reglock, flags); } /* Ignore if it's not for us */ @@ -2778,11 +2815,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) { @@ -2790,18 +2823,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); @@ -2809,7 +2847,6 @@ ZAP_IRQ_HANDLER(t4_interrupt) } #endif - ZAP_IRQ_HANDLER(t4_interrupt_gen2) { struct t4 *wc = dev_id; @@ -2858,7 +2895,7 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) #if 1 if ((wc->intcount < 20) && debug) - printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, __t4_framer_in(wc, 0, FRMR_CIS)); + printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, t4_framer_in(wc, 0, FRMR_CIS)); #endif if (status & 0x2) { @@ -2888,10 +2925,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 */; @@ -2900,26 +2935,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, FRMR_CIS); + cis = t4_framer_in(wc, 0, FRMR_CIS); if (cis & FRMR_CIS_GIS1) - __t4_framer_interrupt(wc, 0); + t4_framer_interrupt(wc, 0); if (cis & FRMR_CIS_GIS2) - __t4_framer_interrupt(wc, 1); + t4_framer_interrupt(wc, 1); if (cis & FRMR_CIS_GIS3) - __t4_framer_interrupt(wc, 2); + t4_framer_interrupt(wc, 2); if (cis & FRMR_CIS_GIS4) - __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)) { @@ -2946,8 +2984,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); @@ -2967,8 +3008,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 |