[svn-commits] mattf: branch 1.4 r2470 - in /branches/1.4: ./ wct4xxp/base.c

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


Author: mattf
Date: Sat Apr 28 16:29:06 2007
New Revision: 2470

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2470
Log:
Merged revisions 2469 via svnmerge from 
https://origsvn.digium.com/svn/zaptel/branches/1.2

........
r2469 | mattf | 2007-04-28 16:07:35 -0500 (Sat, 28 Apr 2007) | 1 line

Fix for potential deadlock in wct4xxp driver
........

Modified:
    branches/1.4/   (props changed)
    branches/1.4/wct4xxp/base.c

Propchange: branches/1.4/
------------------------------------------------------------------------------
Binary property 'branch-1.2-merged' - no diff available.

Modified: branches/1.4/wct4xxp/base.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/wct4xxp/base.c?view=diff&rev=2470&r1=2469&r2=2470
==============================================================================
--- branches/1.4/wct4xxp/base.c (original)
+++ branches/1.4/wct4xxp/base.c Sat Apr 28 16:29:06 2007
@@ -369,8 +369,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, 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_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 @@
 	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 @@
 				}
 				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 @@
 					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 @@
 		}
 
 	}
+	spin_unlock_irqrestore(&wc->reglock, flags);
 }
 #endif
 
@@ -1186,12 +1202,16 @@
 	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 @@
 	}
 	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 @@
 		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 @@
 		__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 @@
 		__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 @@
 		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 @@
 	}
 
 	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 @@
 }
 #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 @@
 
 	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 @@
 		}
 	} 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 @@
 		}
 	} 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,15 +2385,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);
@@ -2488,15 +2507,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) {
@@ -2505,9 +2530,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);
 		}
 	}
@@ -2575,38 +2601,39 @@
 #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 @@
 			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 @@
 #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 @@
 				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,12 +2735,16 @@
 			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);
 
 }
 
@@ -2730,12 +2769,10 @@
 	/* 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);
-		}
-		spin_unlock_irqrestore(&wc->reglock, flags);
+				t4_framer_interrupt(wc, x);
+		}
 	}
 
 	/* Ignore if it's not for us */
@@ -2778,11 +2815,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) {
@@ -2790,25 +2823,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;
 	}
+
+	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);
 #endif		
 }
 #endif
-
 
 ZAP_IRQ_HANDLER(t4_interrupt_gen2)
 {
@@ -2858,7 +2895,7 @@
 #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 @@
 #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 @@
 		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 @@
 								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 @@
 			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