diff options
author | mattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-04-04 21:48:48 +0000 |
---|---|---|
committer | mattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-04-04 21:48:48 +0000 |
commit | 720527551cd60f2ffe061678aa07819cc55031ce (patch) | |
tree | a4277c2366be579fbf1e7069dedbc45258836379 /wct4xxp | |
parent | 8a937ac5a4588ffa815a2b20e94b3a96e13651b5 (diff) |
Performance related overhaul of the wct4xxp driver.
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2392 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'wct4xxp')
-rw-r--r-- | wct4xxp/base.c | 243 | ||||
-rw-r--r-- | wct4xxp/wct4xxp.h | 4 |
2 files changed, 94 insertions, 153 deletions
diff --git a/wct4xxp/base.c b/wct4xxp/base.c index 996f1bd..533641c 100644 --- a/wct4xxp/base.c +++ b/wct4xxp/base.c @@ -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 wct205 = { "Wildcard TE205P ", FLAG_2NDGEN | FLAG_2PORT }; static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT }; -static int inirq = 0; - struct t4; struct t4_span { @@ -305,10 +291,6 @@ struct t4 { 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 @@ struct t4 { 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 */ - int spansstarted; /* number of spans started */ - /* spinlock_t lock; */ /* lock context */ spinlock_t reglock; /* lock register access */ + int spansstarted; /* number of spans started */ 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 @@ static void __t4_check_sigbits(struct t4 *wc, int span); #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 unsigned int t4_framer_in(struct t4 *wc, int unit, const unsigned 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 @@ ZAP_IRQ_HANDLER(t4_interrupt) 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 @@ ZAP_IRQ_HANDLER(t4_interrupt) 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 @@ ZAP_IRQ_HANDLER(t4_interrupt) } #endif - -ZAP_IRQ_HANDLER(t4_interrupt_gen2) +static void t4_isr_bh(unsigned long data) { - struct t4 *wc = dev_id; + struct t4 *wc = (struct t4 *)data; unsigned long flags; unsigned char cis; - int x; - int needcheckvpm450=0; - - unsigned int status; -#if 0 - unsigned int status2; -#endif -#if 0 - if (wc->intcount < 20) - printk("2G: Pre-interrupt\n"); + 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; - 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 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) } #ifdef ENABLE_WORKQUEUES - t4_pci_out(wc, WC_INTR, status & 0x00000008); + __t4_pci_out(wc, WC_INTR, status & 0x00000008); #endif - if (!wc->spansstarted) { + if (unlikely(!wc->spansstarted)) { printk("Not prepped yet!\n"); #ifdef LINUX26 return IRQ_NONE; @@ -2860,13 +2865,12 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) } 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 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) #endif } - spin_lock_irqsave(&wc->reglock, flags); + if (unlikely(status & 0x1)) + set_bit(T4_CHECK_FRAMER, &wc->checkflag); - 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 (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; + set_bit(T4_CHECK_VPM, &wc->checkflag); } - } else if ((status & 0xff00) != 0xff00) - __t4_check_vpm400(wc, (status & 0xff00) >> 8); + } else if ((status & 0xff00) != 0xff00) { + wc->vpm400checkstatus = (status & 0xff00) >> 8; + set_bit(T4_CHECK_VPM, &wc->checkflag); + } } -#endif -#if 1 + 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 @@ ZAP_IRQ_HANDLER(t4_interrupt_gen2) __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 @@ static void t4_vpm450_init(struct t4 *wc) #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 @@ static int __devinit t4_launch(struct t4 *wc) 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; } diff --git a/wct4xxp/wct4xxp.h b/wct4xxp/wct4xxp.h index aa028a4..8b9de68 100644 --- a/wct4xxp/wct4xxp.h +++ b/wct4xxp/wct4xxp.h @@ -105,5 +105,9 @@ struct t4_regs { 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) |