[svn-commits] mattf: branch 1.2 r2469 - /branches/1.2/wct4xxp/base.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Sat Apr 28 14:07:35 MST 2007


Author: mattf
Date: Sat Apr 28 16:07:35 2007
New Revision: 2469

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2469
Log:
Fix for potential deadlock in wct4xxp driver

Modified:
    branches/1.2/wct4xxp/base.c

Modified: branches/1.2/wct4xxp/base.c
URL: http://svn.digium.com/view/zaptel/branches/1.2/wct4xxp/base.c?view=diff&rev=2469&r1=2468&r2=2469
==============================================================================
--- branches/1.2/wct4xxp/base.c (original)
+++ branches/1.2/wct4xxp/base.c Sat Apr 28 16:07:35 2007
@@ -360,8 +360,8 @@
 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_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 @@
 	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 @@
 				}
 				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 @@
 					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 @@
 		}
 
 	}
+	spin_unlock_irqrestore(&wc->reglock, flags);
 }
 #endif
 
@@ -1545,11 +1561,6 @@
 		__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 @@
 		__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 @@
 		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 @@
 }
 #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 @@
 
 	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 @@
 		}
 	} 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 @@
 		}
 	} 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,15 +2043,18 @@
 	}
 }
 
-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 @@
 	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 @@
 				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 @@
 		}
 	}
 #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 @@
 	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 @@
 }
 #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 @@
 		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 @@
 		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 @@
 #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 @@
 		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 @@
 								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 @@
 			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
 



More information about the svn-commits mailing list