summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-04-25 16:49:50 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-04-25 16:49:50 +0000
commit2485ad582edc4bd70f6bc532491fd5da47fb690f (patch)
tree6f71922966392646b0e37c981ed83ff99a010698
parent4f2e90f1a6033eb49b5eaf7a94666acf7f1ab017 (diff)
Fix potential deadlock in driver-zaptel interaction
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2453 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--wct1xxp.c45
1 files changed, 34 insertions, 11 deletions
diff --git a/wct1xxp.c b/wct1xxp.c
index 81e428e..43215fc 100644
--- a/wct1xxp.c
+++ b/wct1xxp.c
@@ -959,10 +959,12 @@ static void t1xxp_receiveprep(struct t1xxp *wc, int ints)
zt_receive(&wc->span);
}
-static void __t1xxp_check_sigbits(struct t1xxp *wc, int x)
+static void t1xxp_check_sigbits(struct t1xxp *wc, int x)
{
int a,b,i,y,rxs;
+ unsigned long flags;
+ spin_lock_irqsave(&wc->lock, flags);
if (wc->ise1) {
/* Read 5 registers at a time, loading 10 channels at a time */
for (i = (x * 5); i < (x * 5) + 5; i++) {
@@ -970,13 +972,19 @@ static void __t1xxp_check_sigbits(struct t1xxp *wc, int x)
/* Get high channel in low bits */
rxs = (a & 0xf);
if (!(wc->chans[i+16].sig & ZT_SIG_CLEAR)) {
- if (wc->chans[i+16].rxsig != rxs)
+ if (wc->chans[i+16].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
zt_rbsbits(&wc->chans[i+16], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
}
rxs = (a >> 4) & 0xf;
if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) {
- if (wc->chans[i].rxsig != rxs)
+ if (wc->chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
zt_rbsbits(&wc->chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
}
}
} else {
@@ -990,18 +998,25 @@ static void __t1xxp_check_sigbits(struct t1xxp *wc, int x)
if (b & (1 << y))
rxs |= ZT_BBIT;
if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) {
- if (wc->chans[i].rxsig != rxs)
+ if (wc->chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
zt_rbsbits(&wc->chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
}
}
}
+ spin_unlock_irqrestore(&wc->lock, flags);
}
-static void __t1xxp_check_alarms(struct t1xxp *wc)
+static void t1xxp_check_alarms(struct t1xxp *wc)
{
unsigned char c,d;
int alarms;
int x,j;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
if (wc->ise1) {
__t1_set_reg(wc, 0x06, 0xff);
@@ -1105,11 +1120,16 @@ static void __t1xxp_check_alarms(struct t1xxp *wc)
wc->span.alarms = alarms;
+ spin_unlock_irqrestore(&wc->lock, flags);
+
zt_alarm_notify(&wc->span);
}
-static void __t1xxp_do_counters(struct t1xxp *wc)
+static void t1xxp_do_counters(struct t1xxp *wc)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
if (wc->alarmtimer) {
if (!--wc->alarmtimer) {
wc->span.alarms &= ~(ZT_ALARM_RECOVER);
@@ -1121,9 +1141,12 @@ static void __t1xxp_do_counters(struct t1xxp *wc)
__t1_set_reg(wc, 0x21, 0x5f);
else
__t1_set_reg(wc, 0x35, 0x10);
+ spin_unlock_irqrestore(&wc->lock, flags);
zt_alarm_notify(&wc->span);
+ spin_lock_irqsave(&wc->lock, flags);
}
}
+ spin_unlock_irqrestore(&wc->lock, flags);
}
ZAP_IRQ_HANDLER(t1xxp_interrupt)
@@ -1161,8 +1184,10 @@ ZAP_IRQ_HANDLER(t1xxp_interrupt)
__handle_leds(wc);
#endif
+ spin_unlock_irqrestore(&wc->lock, flags);
+
/* Count down timers */
- __t1xxp_do_counters(wc);
+ t1xxp_do_counters(wc);
/* Do some things that we don't have to do very often */
x = wc->intcount & 15 /* 63 */;
@@ -1170,17 +1195,15 @@ ZAP_IRQ_HANDLER(t1xxp_interrupt)
case 0:
case 1:
case 2:
- __t1xxp_check_sigbits(wc, x);
+ t1xxp_check_sigbits(wc, x);
break;
case 4:
/* Check alarms 1/4 as frequently */
if (!(wc->intcount & 0x30))
- __t1xxp_check_alarms(wc);
+ t1xxp_check_alarms(wc);
break;
}
- spin_unlock_irqrestore(&wc->lock, flags);
-
if (ints & 0x10)
printk("PCI Master abort\n");