summaryrefslogtreecommitdiff
path: root/wct4xxp
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-04-28 21:07:35 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-04-28 21:07:35 +0000
commitfc5e9b162bdb70b77afef47dde086b0edc0d2273 (patch)
treead5672ebe7a70e16c98920b85b36f6d8bbbb7aa5 /wct4xxp
parent73bdbbec7aba3f8a774ea8a3b03690827b644696 (diff)
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
Diffstat (limited to 'wct4xxp')
-rw-r--r--wct4xxp/base.c152
1 files changed, 89 insertions, 63 deletions
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;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);
@@ -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;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) {
@@ -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