[zaptel-commits] mattf: branch mattf/zaptel-hotwct4xxp r2206 - /team/mattf/zaptel-hotwct4xxp/w...

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Wed Feb 21 09:52:18 MST 2007


Author: mattf
Date: Wed Feb 21 10:52:18 2007
New Revision: 2206

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2206
Log:
Bam, there it is.  Move all non crictial blocking operations (other than data 
transmit and receive) out of the interrupt handler and into a bottom half.  Also 
eliminate locking as much as possible from the handler.

Modified:
    team/mattf/zaptel-hotwct4xxp/wct4xxp/base.c
    team/mattf/zaptel-hotwct4xxp/wct4xxp/wct4xxp.h

Modified: team/mattf/zaptel-hotwct4xxp/wct4xxp/base.c
URL: http://svn.digium.com/view/zaptel/team/mattf/zaptel-hotwct4xxp/wct4xxp/base.c?view=diff&rev=2206&r1=2205&r2=2206
==============================================================================
--- team/mattf/zaptel-hotwct4xxp/wct4xxp/base.c (original)
+++ team/mattf/zaptel-hotwct4xxp/wct4xxp/base.c Wed Feb 21 10:52:18 2007
@@ -48,18 +48,6 @@
 #include "wct4xxp.h"
 #include "vpm450m.h"
 
-/*
- * Tasklets provide better system interactive response at the cost of the
- * possibility of losing a frame of data at very infrequent intervals.  If
- * you are more concerned with the performance of your machine, enable the
- * tasklets.  If you are strict about absolutely no drops, then do not enable
- * tasklets.
- *
- * XXX THIS IS NOT CURRENTLY IMPLEMENTED FOR THIS MODULE.  FOR NOW, DO NOT USE!
- */
-
-/* #define ENABLE_TASKLETS */
-
 /* Work queues are a way to better distribute load on SMP systems */
 #if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
 /*
@@ -188,7 +176,7 @@
 #ifdef VPM_SUPPORT
 static int vpmsupport = 1;
 /* If set to auto, vpmdtmfsupport is enabled for VPM400M and disabled for VPM450M */
-static int vpmdtmfsupport = -1; /* -1=auto, 0=disabled, 1=enabled*/
+static int vpmdtmfsupport = 1; /* -1=auto, 0=disabled, 1=enabled*/
 static int vpmspans = 4;
 #define VPM_DEFAULT_DTMFTHRESHOLD 1000
 static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
@@ -244,8 +232,6 @@
 static struct devtype wct205 = { "Wildcard TE205P ", FLAG_2NDGEN | FLAG_2PORT };
 static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT };
 	
-
-static int inirq = 0;
 
 struct t4;
 
@@ -305,10 +291,6 @@
 	int syncsrc;			/* active sync source */
 	struct t4_span *tspans[4];	/* Individual spans */
 	int numspans;			/* Number of spans on the card */
-#ifdef VPM_SUPPORT
-	int vpm;
-#endif	
-
 	int blinktimer;
 #ifdef FANCY_ALARM
 	int alarmpos;
@@ -321,37 +303,39 @@
 	unsigned int gpio;
 	unsigned int gpioctl;
 	int stopdma;			/* Set to stop DMA */
-	unsigned int dmactrl;
 	int e1recover;			/* E1 recovery timer */
-	dma_addr_t 	readdma;
-	dma_addr_t	writedma;
-	unsigned long memaddr;		/* Base address of card */
-	unsigned long memlen;
-	volatile unsigned int *membase;	/* Base address of card */
+	spinlock_t reglock;		/* lock register access */
 	int spansstarted;		/* number of spans started */
-	/* spinlock_t lock; */		/* lock context */
-	spinlock_t reglock;		/* lock register access */
 	volatile unsigned int *writechunk;					/* Double-word aligned write memory */
 	volatile unsigned int *readchunk;					/* Double-word aligned read memory */
 	unsigned short canary;
 #ifdef ENABLE_WORKQUEUES
 	atomic_t worklist;
 	struct workqueue_struct *workq;
-#else
-#ifdef ENABLE_TASKLETS
-	int taskletrun;
-	int taskletsched;
-	int taskletpending;
-	int taskletexec;
-	int txerrors;
-	struct tasklet_struct t4_tlet;
-#endif
 #endif
 	unsigned int passno;	/* number of interrupt passes */
 	char *variety;
 	int last0;		/* for detecting double-missed IRQ */
 	int checktiming;	/* Set >0 to cause the timing source to be checked */
+
+	/* DMA related fields */
+	unsigned int dmactrl;
+	dma_addr_t 	readdma;
+	dma_addr_t	writedma;
+	unsigned long memaddr;		/* Base address of card */
+	unsigned long memlen;
+	volatile unsigned int *membase;	/* Base address of card */
+
+	/* Flags for our bottom half */
+	unsigned long checkflag;
+	struct tasklet_struct t4_tlet;
+	unsigned int vpm400checkstatus;
+	
+#ifdef VPM_SUPPORT
 	struct vpm450m *vpm450m;
+	int vpm;
+#endif	
+
 };
 
 #define T4_VPM_PRESENT (1 << 28)
@@ -405,9 +389,7 @@
 
 #define MAX_T4_CARDS 64
 
-#ifdef ENABLE_TASKLETS
-static void t4_tasklet(unsigned long data);
-#endif
+static void t4_isr_bh(unsigned long data);
 
 static struct t4 *cards[MAX_T4_CARDS];
 
@@ -541,13 +523,13 @@
 static inline void __t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
 {
 	unit &= 0x3;
-	if (debug & DEBUG_REGS)
+	if (unlikely(debug & DEBUG_REGS))
 		printk("Writing %02x to address %02x of unit %d\n", value, addr, unit);
 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
 	__t4_pci_out(wc, WC_LDATA, value);
 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LWRITE);
 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	
-	if (debug & DEBUG_REGS) printk("Write complete\n");
+	if (unlikely(debug & DEBUG_REGS)) printk("Write complete\n");
 #if 0
 	if ((addr != FRMR_TXFIFO) && (addr != FRMR_CMDR) && (addr != 0xbc))
 	{ unsigned int tmp;
@@ -2729,10 +2711,8 @@
 		printk("Pre-interrupt\n");
 #endif
 	
-	inirq = 1;
 	/* Make sure it's really for us */
-	status = t4_pci_in(wc, WC_INTR);
-	t4_pci_out(wc, WC_INTR, 0);
+	status = __t4_pci_in(wc, WC_INTR);
 
 	/* Process framer interrupts */
 	status2 = t4_framer_in(wc, 0, FRMR_CIS);
@@ -2752,6 +2732,8 @@
 #else
 		return;
 #endif		
+
+	__t4_pci_out(wc, WC_INTR, 0);
 
 	if (!wc->spansstarted) {
 		printk("Not prepped yet!\n");
@@ -2814,28 +2796,56 @@
 }
 #endif
 
-
-ZAP_IRQ_HANDLER(t4_interrupt_gen2)
-{
-	struct t4 *wc = dev_id;
+static void t4_isr_bh(unsigned long data)
+{
+	struct t4 *wc = (struct t4 *)data;
 	unsigned long flags;
 	unsigned char cis;
-	int x;
-	int needcheckvpm450=0;
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	if (test_and_clear_bit(T4_UPDATE_TIMERS, &wc->checkflag)) {
+		__t4_do_counters(wc);
+		__handle_leds(wc);
+	}
+
+	if (test_and_clear_bit(T4_CHECK_FRAMER, &wc->checkflag)) {
+		cis = __t4_framer_in(wc, 0, FRMR_CIS);
+		if (cis & FRMR_CIS_GIS1)
+			__t4_framer_interrupt(wc, 0);
+		if (cis & FRMR_CIS_GIS2)
+			__t4_framer_interrupt(wc, 1);
+		if (cis & FRMR_CIS_GIS3)
+			__t4_framer_interrupt(wc, 2);
+		if (cis & FRMR_CIS_GIS4)
+			__t4_framer_interrupt(wc, 3);
+	}
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+#ifdef VPM_SUPPORT
+	if (wc->vpm) {
+		if (test_and_clear_bit(T4_CHECK_VPM, &wc->checkflag)) {
+			if (wc->vpm450m) {
+				/* How stupid is it that the octasic can't generate an
+				   interrupt when there's a tone, in spite of what their
+				   documentation says? */
+				t4_check_vpm450(wc);
+			} else {
+				spin_lock_irqsave(&wc->reglock, flags);
+				__t4_check_vpm400(wc, wc->vpm400checkstatus);
+				spin_unlock_irqrestore(&wc->reglock, flags);
+			}
+		}
+	}
+#endif
+}
+
+ZAP_IRQ_HANDLER(t4_interrupt_gen2)
+{
+	struct t4 *wc = dev_id;
+	unsigned int status;
 	
-	unsigned int status;
-#if 0
-	unsigned int status2;
-#endif
-
-#if 0
-	if (wc->intcount < 20)
-		printk("2G: Pre-interrupt\n");
-#endif
-	
-	inirq = 1;
 	/* Make sure it's really for us */
-	status = t4_pci_in(wc, WC_INTR);
+	status = __t4_pci_in(wc, WC_INTR);
 
 	/* Ignore if it's not for us */
 	if (!(status & 0x7)) {
@@ -2847,10 +2857,10 @@
 	}
 
 #ifdef ENABLE_WORKQUEUES
-	t4_pci_out(wc, WC_INTR, status & 0x00000008);
-#endif
-
-	if (!wc->spansstarted) {
+	__t4_pci_out(wc, WC_INTR, status & 0x00000008);
+#endif
+
+	if (unlikely(!wc->spansstarted)) {
 		printk("Not prepped yet!\n");
 #ifdef LINUX26
 		return IRQ_NONE;
@@ -2860,13 +2870,13 @@
 	}
 
 	wc->intcount++;
-#if 1
-	if ((wc->intcount < 20) && debug)
+
+	if (unlikely((wc->intcount < 20) && debug))
 
 		printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, __t4_framer_in(wc, 0, FRMR_CIS));
-#endif		
-
-	if (status & 0x2) {
+
+	if (likely(status & 0x2)) {
+		set_bit(T4_UPDATE_TIMERS, &wc->checkflag);
 #ifdef ENABLE_WORKQUEUES
 		int cpus = num_online_cpus();
 		atomic_set(&wc->worklist, wc->numspans);
@@ -2893,97 +2903,31 @@
 #endif
 	}
 
-	spin_lock_irqsave(&wc->reglock, flags);
-
-	if (status & 0x2)
-		__t4_do_counters(wc);
-
-	if (polling && (status & 0x2)) {
-		x = wc->intcount & 15 /* 63 */;
-		switch(x) {
-		case 0:
-		case 1:
-		case 2:
-		case 3:
-			__t4_check_sigbits(wc, x);
-			break;
-		case 4:
-		case 5:
-		case 6:
-		case 7:
-			__t4_check_alarms(wc, x - 4);
-			break;
-		}
-	} else if (status & 0x1) {
-		cis = __t4_framer_in(wc, 0, FRMR_CIS);
-		if (cis & FRMR_CIS_GIS1)
-			__t4_framer_interrupt(wc, 0);
-		if (cis & FRMR_CIS_GIS2)
-			__t4_framer_interrupt(wc, 1);
-		if (cis & FRMR_CIS_GIS3)
-			__t4_framer_interrupt(wc, 2);
-		if (cis & FRMR_CIS_GIS4)
-			__t4_framer_interrupt(wc, 3);
-	}
-#ifdef VPM_SUPPORT
+	if (unlikely(status & 0x1))
+		set_bit(T4_CHECK_FRAMER, &wc->checkflag);
+
 	if (wc->vpm) {
-		if (!wc->vpm450m && !(wc->intcount % 16) && !(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) {
-			/* Check DTMF events */
-			int span = (wc->intcount >> 4) & 0x3;
-			int y;
-			short energy;
-			int offset = 1;
-			int chip;
-			int channel;
-			struct t4_span *ts = wc->tspans[span];
-			if (!wc->t1e1)
-				offset = 5;
-			if (ts->dtmfactive) {
-				for (y = 0; y < ts->span.channels; y++) {
-					if (ts->dtmfactive & (1 << y)) {
-						channel = y + offset;
-						chip = span + ((channel & 0x1) << 2);
-						/* Have an active channel, check its energy! */
-						energy = __t4_vpm_in(wc, chip, 0x58 + channel);
-						energy = ZT_XLAW(energy, ts->span.chans);
-						if (energy < (ts->dtmfenergy[y])) {
-							if (debug & DEBUG_DTMF)
-								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))
-								zt_qevent_lock(&ts->span.chans[y], (ZT_EVENT_DTMFUP | ts->dtmfdigit[y]));
-							ts->dtmfenergy[y] = 0;
-							ts->dtmfdigit[y] = 0;
-							ts->dtmfactive &= ~(1 << y);
-						} else if (energy > (ts->dtmfenergy[y])) {
-							if (debug & DEBUG_DTMF)
-								printk("Increasing digit energy on span %d, channel %d (energy = %02x > %02x)!\n", span, y + 1, energy, ts->dtmfenergy[y]);
-							ts->dtmfenergy[y] = energy;
-						}
-					}
-				}
-			}
-		} 
 		if (wc->vpm450m) {
 			/* How stupid is it that the octasic can't generate an
 			   interrupt when there's a tone, in spite of what their
 			   documentation says? */
 			if (!(wc->intcount & 0xf)) {
-				needcheckvpm450 = 1;
-			}
-		} else if ((status & 0xff00) != 0xff00)
-			__t4_check_vpm400(wc, (status & 0xff00) >> 8);
-	}
-#endif
-
-#if 1 
-	__handle_leds(wc);
-#endif
-
-	if (wc->checktiming > 0)
+				set_bit(T4_CHECK_VPM, &wc->checkflag);
+			}
+		} else if ((status & 0xff00) != 0xff00) {
+			wc->vpm400checkstatus = (status & 0xff00) >> 8;
+			set_bit(T4_CHECK_VPM, &wc->checkflag);
+		}
+	}
+
+	if (unlikely(wc->checktiming > 0)) {
+		spin_lock(&wc->reglock);
 		__t4_set_timing_source_auto(wc);
-	if (wc->stopdma) {
+		spin_unlock(&wc->reglock);
+	}
+
+	if (unlikely(wc->stopdma)) {
+		spin_lock(&wc->reglock);
 		/* Stop DMA cleanly if requested */
 		wc->dmactrl = 0x0;
 		__t4_pci_out(wc, WC_DMACTRL, 0x00000000);
@@ -2991,16 +2935,13 @@
 		__t4_pci_out(wc, WC_INTR, 0x00000000);
 		__t4_set_timing_source(wc, 4, 0, 0);
 		wc->stopdma = 0x0;
-	}
-	spin_unlock_irqrestore(&wc->reglock, flags);
-
-	if (needcheckvpm450 && (vpmdtmfsupport == 1)) {
-		t4_check_vpm450(wc);
-		needcheckvpm450 = 0;
-	}
+		spin_unlock(&wc->reglock);
+	}
+
+	tasklet_schedule(&wc->t4_tlet);
 
 #ifndef ENABLE_WORKQUEUES
-	t4_pci_out(wc, WC_INTR, 0);
+	__t4_pci_out(wc, WC_INTR, 0);
 #endif	
 #ifdef LINUX26
 	return IRQ_RETVAL(1);
@@ -3494,9 +3435,7 @@
 	spin_lock_irqsave(&wc->reglock, flags);
 	__t4_set_timing_source(wc,4, 0, 0);
 	spin_unlock_irqrestore(&wc->reglock, flags);
-#ifdef ENABLE_TASKLETS
-	tasklet_init(&wc->t4_tlet, t4_tasklet, (unsigned long)wc);
-#endif
+	tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
 	return 0;
 }
 

Modified: team/mattf/zaptel-hotwct4xxp/wct4xxp/wct4xxp.h
URL: http://svn.digium.com/view/zaptel/team/mattf/zaptel-hotwct4xxp/wct4xxp/wct4xxp.h?view=diff&rev=2206&r1=2205&r2=2206
==============================================================================
--- team/mattf/zaptel-hotwct4xxp/wct4xxp/wct4xxp.h (original)
+++ team/mattf/zaptel-hotwct4xxp/wct4xxp/wct4xxp.h Wed Feb 21 10:52:18 2007
@@ -105,5 +105,9 @@
 	unsigned char regs[NUM_REGS];
 };
 
+#define T4_CHECK_FRAMER		0
+#define T4_CHECK_VPM		1
+#define T4_UPDATE_TIMERS	2
+
 #define WCT4_GET_REGS	_IOW (ZT_CODE, 60, struct t4_regs)
 



More information about the zaptel-commits mailing list