diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dahdi/wcte12xp/base.c | 104 |
1 files changed, 84 insertions, 20 deletions
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c index eef229a..f0fa949 100644 --- a/drivers/dahdi/wcte12xp/base.c +++ b/drivers/dahdi/wcte12xp/base.c @@ -643,21 +643,21 @@ static inline int t1_setreg(struct t1 *wc, int addr, int val) return 0; } -static int t1_getreg(struct t1 *wc, int addr) +static void __t1_getreg(struct t1 *wc, int addr, struct command *cmd) { - struct command *cmd = NULL; - unsigned long ret; - unsigned long flags; - - might_sleep(); - - cmd = get_free_cmd(wc); - if (!cmd) - return -ENOMEM; cmd->address = addr; cmd->data = 0x00; cmd->flags = __CMD_RD; submit_cmd(wc, cmd); +} + +static int __t1_getresult(struct t1 *wc, struct command *cmd) +{ + int ret; + unsigned long flags; + + might_sleep(); + ret = wait_for_completion_interruptible_timeout(&cmd->complete, HZ*10); if (unlikely(!ret)) { spin_lock_irqsave(&wc->reglock, flags); @@ -692,6 +692,16 @@ static int t1_getreg(struct t1 *wc, int addr) return ret; } +static int t1_getreg(struct t1 *wc, int addr) +{ + struct command *cmd = NULL; + cmd = get_free_cmd(wc); + if (!cmd) + return -ENOMEM; + __t1_getreg(wc, addr, cmd); + return __t1_getresult(wc, cmd); +} + static void t1_setleds(struct t1 *wc, int leds) { struct command *cmd; @@ -1183,15 +1193,29 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) return 0; } -static inline void t1_check_sigbits(struct t1 *wc) +static void t1_check_sigbits(struct t1 *wc) { + struct command *cmds[15] = {NULL,}; int a,i,rxs; if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; if (dahdi_is_e1_span(&wc->span)) { + /* Send out all the commands first. */ for (i = 0; i < 15; i++) { - a = t1_getreg(wc, 0x71 + i); + if (!(wc->span.chans[i+16]->sig & DAHDI_SIG_CLEAR) || + !(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { + cmds[i] = get_free_cmd(wc); + __t1_getreg(wc, 0x71 + i, cmds[i]); + } + } + + /* Now check the results */ + for (i = 14; i >= 0; --i) { + struct command *cmd = cmds[i]; + if (!cmd) + continue; + a = __t1_getresult(wc, cmd); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0xf); @@ -1209,8 +1233,19 @@ static inline void t1_check_sigbits(struct t1 *wc) } } } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { + /* First we'll send out the commands */ for (i = 0; i < 24; i+=4) { - a = t1_getreg(wc, 0x70 + (i>>2)); + cmds[i] = get_free_cmd(wc); + if (!cmds[i]) { + WARN_ON(1); + return; + } + __t1_getreg(wc, 0x70 + (i>>2), cmds[i]); + } + + /* Now we'll check the results */ + for (i = 20; i >= 0; i -= 4) { + a = __t1_getresult(wc, cmds[i]); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0x3) << 2; @@ -1240,8 +1275,18 @@ static inline void t1_check_sigbits(struct t1 *wc) } } } else { + /* First send out the commands. */ for (i = 0; i < 24; i+=2) { - a = t1_getreg(wc, 0x70 + (i>>1)); + cmds[i] = get_free_cmd(wc); + if (!cmds[i]) { + WARN_ON(1); + return; + } + __t1_getreg(wc, 0x70 + (i>>1), cmds[i]); + } + /* Now check the results. */ + for (i = 22; i >= 0; i -= 2) { + a = __t1_getresult(wc, cmds[i]); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0xf); @@ -2036,19 +2081,38 @@ static int t1_hardware_post_init(struct t1 *wc, enum linemode *type) return 0; } -static inline void t1_check_alarms(struct t1 *wc) +static void t1_check_alarms(struct t1 *wc) { unsigned char c,d; int alarms; int x,j; unsigned char fmr4; /* must read this always */ + struct command *cmds[3]; if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; - c = t1_getreg(wc, 0x4c); - fmr4 = t1_getreg(wc, 0x20); /* must read this even if we don't use it */ - d = t1_getreg(wc, 0x4d); + for (x = 0; x < ARRAY_SIZE(cmds); ++x) { + cmds[x] = get_free_cmd(wc); + if (!cmds[x]) { + WARN_ON(1); + for (x = 0; x < ARRAY_SIZE(cmds); ++x) + free_cmd(wc, cmds[x]); + return; + } + } + + /* Since this is voicebus, if we issue all the reads initially and then + * check the results we can save ourselves some time. Otherwise, each + * read will take a minimum of 3ms to go through the complete pipeline. + */ + __t1_getreg(wc, 0x4c, cmds[0]); + __t1_getreg(wc, 0x20, cmds[1]); /* must read this even if not used */ + __t1_getreg(wc, 0x4d, cmds[2]); + + d = __t1_getresult(wc, cmds[2]); + fmr4 = __t1_getresult(wc, cmds[1]); + c = __t1_getresult(wc, cmds[0]); /* Assume no alarms */ alarms = 0; @@ -2464,11 +2528,11 @@ static void timer_work_func(struct work_struct *work) { struct t1 *wc = container_of(work, struct t1, timer_work); #endif + if (test_bit(INITIALIZED, &wc->bit_flags)) + mod_timer(&wc->timer, jiffies + HZ/30); t1_do_counters(wc); t1_check_alarms(wc); t1_check_sigbits(wc); - if (test_bit(INITIALIZED, &wc->bit_flags)) - mod_timer(&wc->timer, jiffies + HZ/10); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |