[zaptel-commits] mattf: trunk r2392 - in /trunk: ./ wct4xxp/base.c
wct4xxp/wct4xxp.h
zaptel-commits at lists.digium.com
zaptel-commits at lists.digium.com
Wed Apr 4 14:48:48 MST 2007
Author: mattf
Date: Wed Apr 4 16:48:48 2007
New Revision: 2392
URL: http://svn.digium.com/view/zaptel?view=rev&rev=2392
Log:
Performance related overhaul of the wct4xxp driver.
Modified:
trunk/ (props changed)
trunk/wct4xxp/base.c
trunk/wct4xxp/wct4xxp.h
Propchange: trunk/
------------------------------------------------------------------------------
svnmerge-integrated = /trunk:1-2389
Modified: trunk/wct4xxp/base.c
URL: http://svn.digium.com/view/zaptel/trunk/wct4xxp/base.c?view=diff&rev=2392&r1=2391&r2=2392
==============================================================================
--- trunk/wct4xxp/base.c (original)
+++ trunk/wct4xxp/base.c Wed Apr 4 16:48:48 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))
/*
@@ -245,8 +233,6 @@
static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT };
-static int inirq = 0;
-
struct t4;
struct t4_span {
@@ -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,9 +2711,9 @@
printk("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);
+
/* Process framer interrupts */
status2 = t4_framer_in(wc, 0, FRMR_CIS);
if (status2 & 0x0f) {
@@ -2751,7 +2733,7 @@
return;
#endif
- t4_pci_out(wc, WC_INTR, 0);
+ __t4_pci_out(wc, WC_INTR, 0);
if (!wc->spansstarted) {
printk("Not prepped yet!\n");
@@ -2814,28 +2796,51 @@
}
#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;
+
+ if (test_and_clear_bit(T4_CHECK_FRAMER, &wc->checkflag)) {
+ spin_lock_irqsave(&wc->reglock, flags);
+ 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 +2852,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 +2865,12 @@
}
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)) {
#ifdef ENABLE_WORKQUEUES
int cpus = num_online_cpus();
atomic_set(&wc->worklist, wc->numspans);
@@ -2893,97 +2897,33 @@
#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
+ set_bit(T4_CHECK_VPM, &wc->checkflag);
+ }
+ } else if ((status & 0xff00) != 0xff00) {
+ wc->vpm400checkstatus = (status & 0xff00) >> 8;
+ set_bit(T4_CHECK_VPM, &wc->checkflag);
+ }
+ }
+
+ spin_lock(&wc->reglock);
+
+ __t4_do_counters(wc);
__handle_leds(wc);
-#endif
-
- if (wc->checktiming > 0)
+
+ if (unlikely(wc->checktiming > 0)) {
__t4_set_timing_source_auto(wc);
- if (wc->stopdma) {
+ }
+
+ if (unlikely(wc->stopdma)) {
/* Stop DMA cleanly if requested */
wc->dmactrl = 0x0;
__t4_pci_out(wc, WC_DMACTRL, 0x00000000);
@@ -2992,15 +2932,14 @@
__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);
+
+ if (unlikely(test_bit(T4_CHECK_VPM, &wc->checkflag) || test_bit(T4_CHECK_FRAMER, &wc->checkflag)))
+ 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);
@@ -3187,8 +3126,8 @@
#endif
if (vpmdtmfsupport == -1) {
- printk("VPM450: hardware DTMF disabled.\n");
- vpmdtmfsupport = 0;
+ printk("VPM450: hardware DTMF enabled.\n");
+ vpmdtmfsupport = 1;
}
wc->vpm = T4_VPM_PRESENT;
@@ -3494,9 +3433,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: trunk/wct4xxp/wct4xxp.h
URL: http://svn.digium.com/view/zaptel/trunk/wct4xxp/wct4xxp.h?view=diff&rev=2392&r1=2391&r2=2392
==============================================================================
--- trunk/wct4xxp/wct4xxp.h (original)
+++ trunk/wct4xxp/wct4xxp.h Wed Apr 4 16:48:48 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