summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2009-04-29 17:48:29 +0000
committerShaun Ruffell <sruffell@digium.com>2009-04-29 17:48:29 +0000
commit6bf3f20913784bd5dedaaded86690d9ed8394e59 (patch)
tree269ea862f87480292a6cd65a253ab69bc9956a3d
parent745ddd1b4ac9bd275907a335ec156a969f8534be (diff)
wcte12xp: Update cmdqueue processing.
The command queue for reading from the registers on the framer is now stored in a linked_list instead of an array. Allows for the locks to protect this structure to be held for shorter periods of time and reduces the need to cycle through all the elements in the array to decide if there is a command in the queue to process. Remove the usecount and dead members from struct t1 since the module reference count will allow us to know when it's safe to free up the memory. This change also moves alarm processing out of the interrupt handler and removes the need for special interrupt handling of commands. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@6525 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wcte12xp/base.c906
-rw-r--r--drivers/dahdi/wcte12xp/vpmadt032.c73
-rw-r--r--drivers/dahdi/wcte12xp/wcte12xp.h70
3 files changed, 416 insertions, 633 deletions
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index 4209842..9294350 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -8,7 +8,7 @@
* Matthew Fredrickson <creslin@digium.com>
* William Meadows <wmeadows@digium.com>
*
- * Copyright (C) 2007-2008, Digium, Inc.
+ * Copyright (C) 2007-2009, Digium, Inc.
*
* All rights reserved.
*
@@ -35,6 +35,9 @@
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
#include <dahdi/kernel.h>
@@ -50,36 +53,6 @@
struct pci_driver te12xp_driver;
-static int chanmap_t1[] =
-{ 2,1,0,
- 6,5,4,
- 10,9,8,
- 14,13,12,
- 18,17,16,
- 22,21,20,
- 26,25,24,
- 30,29,28 };
-
-static int chanmap_e1[] =
-{ 2,1,0,
- 7,6,5,4,
- 11,10,9,8,
- 15,14,13,12,
- 19,18,17,16,
- 23,22,21,20,
- 27,26,25,24,
- 31,30,29,28 };
-
-static int chanmap_e1uc[] =
-{ 3,2,1,0,
- 7,6,5,4,
- 11,10,9,8,
- 15,14,13,12,
- 19,18,17,16,
- 23,22,21,20,
- 27,26,25,24,
- 31,30,29,28 };
-
int debug = 0;
static int j1mode = 0;
static int alarmdebounce = 0;
@@ -108,33 +81,65 @@ static struct t1_desc te120p = { "Wildcard TE120P", 0 };
static struct t1_desc te122 = { "Wildcard TE122", 0 };
static struct t1_desc te121 = { "Wildcard TE121", 0 };
-int schluffen(wait_queue_head_t *q)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static kmem_cache_t *cmd_cache;
+#else
+static struct kmem_cache *cmd_cache;
+#endif
+
+static struct command *get_free_cmd(struct t1 *wc)
{
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(q, &wait);
- current->state = TASK_INTERRUPTIBLE;
- if (!signal_pending(current)) schedule();
- current->state = TASK_RUNNING;
- remove_wait_queue(q, &wait);
- if (signal_pending(current)) return -ERESTARTSYS;
- return(0);
+ struct command *cmd;
+ cmd = kmem_cache_alloc(cmd_cache, GFP_ATOMIC);
+ if (cmd) {
+ memset(cmd, 0, sizeof(*cmd));
+ INIT_LIST_HEAD(&cmd->node);
+ }
+ return cmd;
}
-static inline int empty_slot(struct t1 *wc)
+static void free_cmd(struct t1 *wc, struct command *cmd)
{
- unsigned int x;
+ kmem_cache_free(cmd_cache, cmd);
+}
- for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
- if (!wc->cmdq.cmds[x].flags && !wc->cmdq.cmds[x].address)
- return x;
+static struct command *get_pending_cmd(struct t1 *wc)
+{
+ struct command *cmd = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ if (!list_empty(&wc->pending_cmds)) {
+ cmd = list_entry(wc->pending_cmds.next, struct command, node);
+ list_move_tail(&cmd->node, &wc->active_cmds);
}
- return -1;
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+ return cmd;
+}
+
+static void submit_cmd(struct t1 *wc, struct command *cmd)
+{
+ unsigned long flags;
+ if (cmd->flags & (__CMD_RD | __CMD_PINS))
+ init_completion(&cmd->complete);
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_add_tail(&cmd->node, &wc->pending_cmds);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+}
+
+static void resend_cmds(struct t1 *wc)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_splice_init(&wc->active_cmds, &wc->pending_cmds);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
}
-static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot)
+static void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot)
{
struct command *curcmd=NULL;
- unsigned int x;
+ u16 address;
+ u8 data;
+ u32 flags;
/* Skip audio */
writechunk += 66;
@@ -143,287 +148,145 @@ static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk
/* only 6 useable cs slots per */
/* framer */
- for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
- if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) &&
- !(wc->cmdq.cmds[x].flags & (__CMD_TX | __CMD_FIN))) {
- curcmd = &wc->cmdq.cmds[x];
- wc->cmdq.cmds[x].flags |= __CMD_TX;
- wc->cmdq.cmds[x].ident = wc->txident;
- break;
- }
- }
- if (!curcmd) {
- curcmd = &wc->dummy;
+ curcmd = get_pending_cmd(wc);
+ if (curcmd) {
+ curcmd->cs_slot = slot;
+ curcmd->ident = wc->txident;
+
+ address = curcmd->address;
+ data = curcmd->data;
+ flags = curcmd->flags;
+ } else {
/* If nothing else, use filler */
- curcmd->address = 0x4a;
- curcmd->data = 0x00;
- curcmd->flags = __CMD_RD;
+ address = 0x4a;
+ data = 0;
+ flags = __CMD_RD;
}
- curcmd->cs_slot = slot;
- if (curcmd->flags & __CMD_WR)
- writechunk[CMD_BYTE(slot,0,0)] = 0x0c; /* 0c write command */
- else if (curcmd->flags & __CMD_LEDS)
- writechunk[CMD_BYTE(slot,0,0)] = 0x10 | ((curcmd->address) & 0x0E); /* led set command */
- else if (curcmd->flags & __CMD_PINS)
- writechunk[CMD_BYTE(slot,0,0)] = 0x30; /* CPLD2 pin state */
+
+ if (flags & __CMD_WR)
+ writechunk[CMD_BYTE(slot, 0, 0)] = 0x0c; /* 0c write command */
+ else if (flags & __CMD_LEDS)
+ writechunk[CMD_BYTE(slot, 0, 0)] = 0x10 | ((address) & 0x0E); /* led set command */
+ else if (flags & __CMD_PINS)
+ writechunk[CMD_BYTE(slot, 0, 0)] = 0x30; /* CPLD2 pin state */
else
- writechunk[CMD_BYTE(slot,0,0)] = 0x0a; /* read command */
- writechunk[CMD_BYTE(slot,1,0)] = curcmd->address;
- writechunk[CMD_BYTE(slot,2,0)] = curcmd->data;
- }
+ writechunk[CMD_BYTE(slot, 0, 0)] = 0x0a; /* read command */
+ writechunk[CMD_BYTE(slot, 1, 0)] = address;
+ writechunk[CMD_BYTE(slot, 2, 0)] = data;
+ }
}
static inline void cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk)
{
- unsigned char ident, cs_slot;
- unsigned int x;
- unsigned int is_vpm = 0;
+ struct command *cmd = NULL;
+ unsigned long flags;
+ const int IS_VPM = 0;
/* Skip audio */
readchunk += 66;
- /* Search for any pending results */
- for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
- if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) &&
- (wc->cmdq.cmds[x].flags & (__CMD_TX)) &&
- !(wc->cmdq.cmds[x].flags & (__CMD_FIN))) {
- ident = wc->cmdq.cmds[x].ident;
- cs_slot = wc->cmdq.cmds[x].cs_slot;
-
- if (ident == wc->rxident) {
- /* Store result */
- wc->cmdq.cmds[x].data |= readchunk[CMD_BYTE(cs_slot,2,is_vpm)];
- /*printk(KERN_INFO "answer in rxident=%d cs_slot=%d is %d CMD_BYTE=%d jiffies=%d\n", ident, cs_slot, last_read_command, CMD_BYTE(cs_slot, 2), jiffies); */
- wc->cmdq.cmds[x].flags |= __CMD_FIN;
- if (wc->cmdq.cmds[x].flags & (__CMD_WR | __CMD_LEDS))
- /* clear out writes (and leds) since they need no ack */
- memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x]));
- }
- }
- }
-}
-
-static inline int t1_setreg_full(struct t1 *wc, int addr, int val, const int inisr, int vpm_num)
-{
- unsigned long flags = 0;
- int hit;
- int ret;
-
-
- do {
- if (!inisr)
- spin_lock_irqsave(&wc->reglock, flags);
- hit = empty_slot(wc);
- if (hit > -1) {
- wc->cmdq.cmds[hit].address = addr;
- wc->cmdq.cmds[hit].data = val;
- wc->cmdq.cmds[hit].flags |= __CMD_WR;
- if(vpm_num >= 0) {
- wc->cmdq.cmds[hit].flags |= __CMD_VPM;
- wc->cmdq.cmds[hit].vpm_num = vpm_num;
- }
- }
- if (inisr)
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ while (!list_empty(&wc->active_cmds)) {
+ cmd = list_entry(wc->active_cmds.next, struct command, node);
+ if (cmd->ident != wc->rxident)
break;
- else
- spin_unlock_irqrestore(&wc->reglock, flags);
- if (hit < 0) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
- }
- } while (hit < 0);
-
- return (hit > -1) ? 0 : -1;
-}
-static inline int t1_setreg(struct t1 *wc, int addr, int val)
-{
- return t1_setreg_full(wc, addr, val, 0, NOT_VPM);
-}
-
-/***************************************************************************
- * clean_leftovers()
- *
- * Check for unconsumed isr register reads and clean them up.
- **************************************************************************/
-static inline void clean_leftovers(struct t1 *wc)
-{
- unsigned int x;
- int count = 0;
-
- /* find our requested command */
- for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
- if ((wc->cmdq.cmds[x].flags & __CMD_RD) &&
- (wc->cmdq.cmds[x].flags & __CMD_ISR) &&
- !(wc->cmdq.cmds[x].flags & __CMD_FIN)) {
- debug_printk(1,"leftover isr read! %d", count);
- memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x]));
+ if (cmd->flags & (__CMD_WR | __CMD_LEDS)) {
+ /* Nobody is waiting on writes...so let's just
+ * free them here. */
+ list_del(&cmd->node);
+ free_cmd(wc, cmd);
+ } else {
+ cmd->data |= readchunk[CMD_BYTE(cmd->cs_slot, 2, IS_VPM)];
+ list_del_init(&cmd->node);
+ complete(&cmd->complete);
}
}
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
}
-/********************************************************************
- * t1_getreg_isr()
- *
- * Called in interrupt context to retrieve a value already requested
- * by the normal t1_getreg().
- *******************************************************************/
-static inline int t1_getreg_isr(struct t1 *wc, int addr)
+static inline int t1_setreg_full(struct t1 *wc, int addr, int val, int vpm_num)
{
- int hit=-1;
- int ret;
- unsigned int x;
-
- /* find our requested command */
- for (x = 0;x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
- if ((wc->cmdq.cmds[x].flags & __CMD_RD) &&
- (wc->cmdq.cmds[x].address==addr))
- {
- if (wc->cmdq.cmds[x].flags & __CMD_FIN) {
- hit = x;
- break;
- }
- else {
- /* still in progress. */
- return -1;
- }
- }
+ struct command *cmd;
+ cmd = get_free_cmd(wc);
+ if (!cmd) {
+ WARN_ON(1);
+ return -ENOMEM;
}
-
- if (hit < 0) {
- debug_printk(2, "t1_getreg_isr() no addr=%02x\n", addr);
- return -1; /* oops, couldn't find it */
+ cmd->address = addr;
+ cmd->data = val;
+ cmd->flags |= __CMD_WR;
+ if (vpm_num >= 0) {
+ cmd->flags |= __CMD_VPM;
+ cmd->vpm_num = vpm_num;
}
-
- ret = wc->cmdq.cmds[hit].data;
- memset(&wc->cmdq.cmds[hit], 0, sizeof(struct command));
-
- return ret;
+ submit_cmd(wc, cmd);
+ return 0;
}
-static inline int t1_getreg_full(struct t1 *wc, int addr, const int inisr, int vpm_num)
+static inline int t1_setreg(struct t1 *wc, int addr, int val)
{
- unsigned long flags = 0;
- int hit;
- int ret = 0;
+ return t1_setreg_full(wc, addr, val, NOT_VPM);
+}
- do {
- if (!inisr) {
- spin_lock_irqsave(&wc->reglock, flags);
- }
- hit = empty_slot(wc);
- if (hit > -1) {
- wc->cmdq.cmds[hit].address = addr;
- wc->cmdq.cmds[hit].data = 0x00;
- wc->cmdq.cmds[hit].flags |= __CMD_RD;
- if(vpm_num >= 0) {
- wc->cmdq.cmds[hit].flags |= __CMD_VPM;
- wc->cmdq.cmds[hit].vpm_num = vpm_num;
- }
- if (inisr)
- wc->cmdq.cmds[hit].flags |= __CMD_ISR;
- }
- if (inisr) /* must be requested in t1_getreg_isr() */
- return (hit > -1) ? 0 : -1;
- else {
- spin_unlock_irqrestore(&wc->reglock, flags);
- }
- if (hit < 0) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
- }
- } while (hit < 0);
+static inline int t1_getreg_full(struct t1 *wc, int addr, int vpm_num)
+{
+ struct command *cmd = NULL;
+ int ret;
- do {
- spin_lock_irqsave(&wc->reglock, flags);
- if (wc->cmdq.cmds[hit].flags & __CMD_FIN) {
- ret = wc->cmdq.cmds[hit].data;
- memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit]));
- hit = -1;
- }
- spin_unlock_irqrestore(&wc->reglock, flags);
- if (hit > -1) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
- }
- } while (hit > -1);
+ might_sleep();
+ cmd = get_free_cmd(wc);
+ if (!cmd)
+ return -ENOMEM;
+ cmd->address = addr;
+ cmd->data = 0x00;
+ cmd->flags = __CMD_RD;
+ if (vpm_num > -1) {
+ cmd->flags |= __CMD_VPM;
+ cmd->vpm_num = vpm_num;
+ }
+ submit_cmd(wc, cmd);
+ wait_for_completion(&cmd->complete);
+ ret = cmd->data;
+ free_cmd(wc, cmd);
return ret;
}
-static inline int t1_getreg(struct t1 *wc, int addr, int inisr)
+static int t1_getreg(struct t1 *wc, int addr)
{
- return t1_getreg_full(wc, addr, inisr, NOT_VPM);
+ return t1_getreg_full(wc, addr, NOT_VPM);
}
-static inline int t1_setleds(struct t1 *wc, int leds, const int inisr)
+static void t1_setleds(struct t1 *wc, int leds)
{
- unsigned long flags = 0;
- int hit;
- int ret = 0;
+ struct command *cmd;
- leds = ~leds & 0x0E; /* invert the LED bits (3 downto 1)*/
-
- do {
- if (!inisr) {
- spin_lock_irqsave(&wc->reglock, flags);
- }
- hit = empty_slot(wc);
- if (hit > -1) {
- wc->cmdq.cmds[hit].flags |= __CMD_LEDS;
- wc->cmdq.cmds[hit].address = leds;
- }
- if (inisr) {
- break;
- } else {
- spin_unlock_irqrestore(&wc->reglock, flags);
- }
- if (hit < 0) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
- }
- } while (hit < 0);
+ leds = (~leds) & 0x0E; /* invert the LED bits (3 downto 1)*/
- return (hit > -1) ? 0 : -1;
+ cmd = get_free_cmd(wc);
+ if (!cmd)
+ return;
+ cmd->flags |= __CMD_LEDS;
+ cmd->address = leds;
+ submit_cmd(wc, cmd);
}
static inline int t1_getpins(struct t1 *wc, int inisr)
{
- unsigned long flags;
- int hit;
int ret = 0;
-
- do {
- spin_lock_irqsave(&wc->reglock, flags);
- hit = empty_slot(wc);
- if (hit > -1) {
- wc->cmdq.cmds[hit].address = 0x00;
- wc->cmdq.cmds[hit].data = 0x00;
- wc->cmdq.cmds[hit].flags |= __CMD_PINS;
- }
- spin_unlock_irqrestore(&wc->reglock, flags);
- if (inisr)
- return (hit > -1) ? 0 : -1;
- if (hit < 0) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
- }
- } while (hit < 0);
-
- do {
- spin_lock_irqsave(&wc->reglock, flags);
- if (wc->cmdq.cmds[hit].flags & __CMD_FIN) {
- ret = wc->cmdq.cmds[hit].data;
- memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit]));
- hit = -1;
- }
- spin_unlock_irqrestore(&wc->reglock, flags);
- if (hit > -1) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
- }
- } while (hit > -1);
-
+ struct command *cmd;
+
+ cmd = get_free_cmd(wc);
+ BUG_ON(!cmd);
+
+ cmd->address = 0x00;
+ cmd->data = 0x00;
+ cmd->flags = __CMD_PINS;
+ submit_cmd(wc, cmd);
+ wait_for_completion(&cmd->complete);
+ ret = cmd->data;
+ free_cmd(wc, cmd);
return ret;
}
@@ -440,7 +303,7 @@ static void __t1xxp_set_clear(struct t1 *wc, int channo)
if (((i % 8)==7) && /* write byte every 8 channels */
((channo < 0) || /* channo=-1 means all channels */
(j == (channo-1)/8) )) { /* only the register for this channo */
- ret = t1_setreg_full(wc, 0x2f + j, val, 1, NOT_VPM);
+ ret = t1_setreg_full(wc, 0x2f + j, val, NOT_VPM);
if (ret < 0)
module_printk("set_clear failed for chan %d!\n",i);
val = 0;
@@ -448,16 +311,33 @@ static void __t1xxp_set_clear(struct t1 *wc, int channo)
}
}
-static void t1_release(struct t1 *wc)
+static void free_wc(struct t1 *wc)
{
unsigned int x;
+ unsigned long flags;
+ struct command *cmd;
+ LIST_HEAD(list);
- dahdi_unregister(&wc->span);
- for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) {
+ for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++)
kfree(wc->chans[x]);
+
+ spin_lock_irqsave(&wc->cmd_list_lock, flags);
+ list_splice_init(&wc->active_cmds, &list);
+ list_splice_init(&wc->pending_cmds, &list);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+ while (!list_empty(&list)) {
+ cmd = list_entry(list.next, struct command, node);
+ list_del(&cmd->node);
+ free_cmd(wc, cmd);
}
kfree(wc);
- printk(KERN_INFO "Freed a Wildcard TE12xP\n");
+}
+
+static void t1_release(struct t1 *wc)
+{
+ dahdi_unregister(&wc->span);
+ printk(KERN_INFO "Freed a Wildcard TE12xP.\n");
+ free_wc(wc);
}
static void t4_serial_setup(struct t1 *wc)
@@ -668,9 +548,6 @@ static void t1_configure_e1(struct t1 *wc, int lineconfig)
static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span)
{
- int alreadyrunning = wc->span.flags & DAHDI_FLAG_RUNNING;
- unsigned long flags;
-
if (wc->spantype == TYPE_E1) { /* if this is an E1 card */
t1_configure_e1(wc, span->lineconfig);
} else { /* is a T1 card */
@@ -678,10 +555,7 @@ static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span)
__t1xxp_set_clear(wc, -1);
}
- spin_lock_irqsave(&wc->reglock, flags);
- if (!alreadyrunning)
- wc->span.flags |= DAHDI_FLAG_RUNNING;
- spin_unlock_irqrestore(&wc->reglock, flags);
+ set_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags);
}
static int t1xxp_startup(struct dahdi_span *span)
@@ -705,23 +579,18 @@ static int t1xxp_startup(struct dahdi_span *span)
static int t1xxp_shutdown(struct dahdi_span *span)
{
struct t1 *wc = span->pvt;
- unsigned long flags;
-
t1_setreg(wc, 0x46, 0x41); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
- spin_lock_irqsave(&wc->reglock, flags);
- span->flags &= ~DAHDI_FLAG_RUNNING;
- spin_unlock_irqrestore(&wc->reglock, flags);
+ clear_bit(DAHDI_FLAGBIT_RUNNING, &span->flags);
return 0;
}
static int t1xxp_chanconfig(struct dahdi_chan *chan, int sigtype)
{
struct t1 *wc = chan->pvt;
- int alreadyrunning = chan->span->flags & DAHDI_FLAG_RUNNING;
-
- if (alreadyrunning && (wc->spantype != TYPE_E1))
+ if (test_bit(DAHDI_FLAGBIT_RUNNING, &chan->span->flags) &&
+ (wc->spantype != TYPE_E1)) {
__t1xxp_set_clear(wc, chan->channo);
-
+ }
return 0;
}
@@ -730,14 +599,13 @@ static int t1xxp_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc
struct t1 *wc = span->pvt;
/* Do we want to SYNC on receive or not */
- wc->sync = lc->sync;
- if (wc->sync)
- wc->ctlreg |= 0x80;
+ if (lc->sync)
+ set_bit(7, &wc->ctlreg);
else
- wc->ctlreg &= ~0x80;
+ clear_bit(7, &wc->ctlreg);
/* If already running, apply changes immediately */
- if (span->flags & DAHDI_FLAG_RUNNING)
+ if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags))
return t1xxp_startup(span);
return 0;
@@ -766,7 +634,7 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits)
wc->txsigs[b] = c;
spin_unlock_irqrestore(&wc->reglock, flags);
/* output them to the chip */
- t1_setreg_full(wc,0x71 + b,c,1,NOT_VPM);
+ t1_setreg_full(wc, 0x71 + b, c, NOT_VPM);
} else if (wc->span.lineconfig & DAHDI_CONFIG_D4) {
n = chan->chanpos - 1;
b = (n / 4);
@@ -778,8 +646,8 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits)
wc->txsigs[b] = c;
spin_unlock_irqrestore(&wc->reglock, flags);
/* output them to the chip */
- t1_setreg_full(wc,0x70 + b,c,1,NOT_VPM);
- t1_setreg_full(wc,0x70 + b + 6,c,1,NOT_VPM);
+ t1_setreg_full(wc, 0x70 + b, c, NOT_VPM);
+ t1_setreg_full(wc, 0x70 + b + 6, c, NOT_VPM);
} else if (wc->span.lineconfig & DAHDI_CONFIG_ESF) {
n = chan->chanpos - 1;
b = (n / 2);
@@ -791,124 +659,84 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits)
wc->txsigs[b] = c;
spin_unlock_irqrestore(&wc->reglock, flags);
/* output them to the chip */
- t1_setreg_full(wc,0x70 + b,c,1,NOT_VPM);
+ t1_setreg_full(wc, 0x70 + b, c, NOT_VPM);
}
debug_printk(2,"Finished setting RBS bits\n");
return 0;
}
-static inline void __t1_check_sigbits_reads(struct t1 *wc)
-{
- int i;
-
- if (!(wc->span.flags & DAHDI_FLAG_RUNNING))
- return;
- if (wc->spantype == TYPE_E1) {
- for (i = 0; i < 15; i++) {
- if (t1_getreg(wc, 0x71 + i, 1))
- wc->isrreaderrors++;
- }
- } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) {
- for (i = 0; i < 24; i+=4) {
- if (t1_getreg(wc, 0x70 + (i >> 2), 1))
- wc->isrreaderrors++;
- }
- } else {
- for (i = 0; i < 24; i+=2) {
- if (t1_getreg(wc, 0x70 + (i >> 1), 1))
- wc->isrreaderrors++;
- }
- }
-}
-
-static inline void __t1_check_sigbits(struct t1 *wc)
+static inline void t1_check_sigbits(struct t1 *wc)
{
int a,i,rxs;
- if (!(wc->span.flags & DAHDI_FLAG_RUNNING))
+ if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)))
return;
if (wc->spantype == TYPE_E1) {
for (i = 0; i < 15; i++) {
- a = t1_getreg_isr(wc, 0x71 + i);
+ a = t1_getreg(wc, 0x71 + i);
if (a > -1) {
/* Get high channel in low bits */
rxs = (a & 0xf);
if (!(wc->span.chans[i+16]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i+16]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i+16], rxs);
- spin_lock(&wc->reglock);
}
}
rxs = (a >> 4) & 0xf;
if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i], rxs);
- spin_lock(&wc->reglock);
}
}
}
}
} else if (wc->span.lineconfig & DAHDI_CONFIG_D4) {
for (i = 0; i < 24; i+=4) {
- a = t1_getreg_isr(wc, 0x70 + (i>>2));
+ a = t1_getreg(wc, 0x70 + (i>>2));
if (a > -1) {
/* Get high channel in low bits */
rxs = (a & 0x3) << 2;
if (!(wc->span.chans[i+3]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i+3]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i+3], rxs);
- spin_lock(&wc->reglock);
}
}
rxs = (a & 0xc);
if (!(wc->span.chans[i+2]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i+2]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i+2], rxs);
- spin_lock(&wc->reglock);
}
}
rxs = (a >> 2) & 0xc;
if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i+1]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i+1], rxs);
- spin_lock(&wc->reglock);
}
}
rxs = (a >> 4) & 0xc;
if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i], rxs);
- spin_lock(&wc->reglock);
}
}
}
}
} else {
for (i = 0; i < 24; i+=2) {
- a = t1_getreg_isr(wc, 0x70 + (i>>1));
+ a = t1_getreg(wc, 0x70 + (i>>1));
if (a > -1) {
/* Get high channel in low bits */
rxs = (a & 0xf);
if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i+1]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i+1], rxs);
- spin_lock(&wc->reglock);
}
}
rxs = (a >> 4) & 0xf;
if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
if (wc->span.chans[i]->rxsig != rxs) {
- spin_unlock(&wc->reglock);
dahdi_rbsbits(wc->span.chans[i], rxs);
- spin_lock(&wc->reglock);
}
}
}
@@ -975,29 +803,15 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd)
static int t1xxp_open(struct dahdi_chan *chan)
{
- struct t1 *wc = chan->pvt;
-
- if (wc->dead)
- return -ENODEV;
- wc->usecount++;
-
- try_module_get(THIS_MODULE);
-
- return 0;
+ if (!try_module_get(THIS_MODULE))
+ return -ENXIO;
+ else
+ return 0;
}
static int t1xxp_close(struct dahdi_chan *chan)
{
- struct t1 *wc = chan->pvt;
-
- wc->usecount--;
-
module_put(THIS_MODULE);
-
- /* If we're dead, release us now */
- if (!wc->usecount && wc->dead)
- t1_release(wc);
-
return 0;
}
@@ -1091,6 +905,7 @@ static int t1xxp_echocan_with_params(struct dahdi_chan *chan, struct dahdi_echoc
static int t1_software_init(struct t1 *wc)
{
int x;
+ int num;
struct pci_dev* dev;
dev = voicebus_get_pci_dev(wc->vb);
@@ -1108,9 +923,9 @@ static int t1_software_init(struct t1 *wc)
t4_serial_setup(wc);
- wc->num = x;
- sprintf(wc->span.name, "WCT1/%d", wc->num);
- snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num);
+ num = x;
+ sprintf(wc->span.name, "WCT1/%d", num);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, num);
wc->span.manufacturer = "Digium";
strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
@@ -1151,11 +966,11 @@ static int t1_software_init(struct t1 *wc)
wc->span.deflaw = DAHDI_LAW_MULAW;
}
wc->span.chans = wc->chans;
- wc->span.flags = DAHDI_FLAG_RBS;
+ set_bit(DAHDI_FLAGBIT_RBS, &wc->span.flags);
wc->span.pvt = wc;
init_waitqueue_head(&wc->span.maintq);
for (x = 0; x < wc->span.channels; x++) {
- sprintf(wc->chans[x]->name, "WCT1/%d/%d", wc->num, x + 1);
+ sprintf(wc->chans[x]->name, "WCT1/%d/%d", num, x + 1);
wc->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 |
DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_MTP2 |
DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS |
@@ -1167,7 +982,8 @@ static int t1_software_init(struct t1 *wc)
module_printk("Unable to register span with DAHDI\n");
return -1;
}
- wc->initialized = 1;
+
+ set_bit(INITIALIZED, &wc->bit_flags);
return 0;
}
@@ -1175,12 +991,12 @@ static int t1_software_init(struct t1 *wc)
#ifdef VPM_SUPPORT
static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr)
{
- return t1_getreg_full(wc, addr, 0, unit);
+ return t1_getreg_full(wc, addr, unit);
}
static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val)
{
- return t1_setreg_full(wc, addr, val, 0, unit);
+ return t1_setreg_full(wc, addr, val, unit);
}
#endif
@@ -1204,38 +1020,29 @@ static int t1_hardware_post_init(struct t1 *wc)
}
debug_printk(1, "spantype: %s\n", wc->spantype==1 ? "T1" : "E1");
- if (wc->spantype == TYPE_E1) {
- if (unchannelized)
- wc->chanmap = chanmap_e1uc;
- else
- wc->chanmap = chanmap_e1;
- } else
- wc->chanmap = chanmap_t1;
/* what version of the FALC are we using? */
reg = t1_setreg(wc, 0x4a, 0xaa);
- reg = t1_getreg(wc, 0x4a, 0);
+ reg = t1_getreg(wc, 0x4a);
debug_printk(1, "FALC version: %08x\n", reg);
/* make sure reads and writes work */
for (x = 0; x < 256; x++) {
t1_setreg(wc, 0x14, x);
- if ((reg = t1_getreg(wc, 0x14, 0)) != x)
+ reg = t1_getreg(wc, 0x14);
+ if (reg != x)
module_printk("Wrote '%x' but read '%x'\n", x, reg);
}
- /* all LED's blank */
- wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg);
- wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
- t1_setleds(wc, wc->ledtestreg, 0);
+ t1_setleds(wc, wc->ledstate);
#ifdef VPM_SUPPORT
t1_vpm150m_init(wc);
if (wc->vpm150m) {
module_printk("VPM present and operational (Firmware version %x)\n", wc->vpm150m->version);
- wc->ctlreg |= 0x10; /* turn on vpm (RX audio from vpm module) */
+ set_bit(4, &wc->ctlreg); /* turn on vpm (RX audio from vpm module) */
if (vpmtsisupport) {
debug_printk(1, "enabling VPM TSI pin\n");
- wc->ctlreg |= 0x01; /* turn on vpm timeslot interchange pin */
+ set_bit(0, &wc->ctlreg); /* turn on vpm timeslot interchange pin */
}
}
#endif
@@ -1243,32 +1050,19 @@ static int t1_hardware_post_init(struct t1 *wc)
return 0;
}
-static inline void __t1_check_alarms_reads(struct t1 *wc)
-{
- if (!(wc->span.flags & DAHDI_FLAG_RUNNING))
- return;
-
- if (t1_getreg(wc, 0x4c, 1))
- wc->isrreaderrors++;
- if (t1_getreg(wc, 0x20, 1))
- wc->isrreaderrors++;
- if (t1_getreg(wc, 0x4d, 1))
- wc->isrreaderrors++;
-}
-
-static inline void __t1_check_alarms(struct t1 *wc)
+static inline void t1_check_alarms(struct t1 *wc)
{
unsigned char c,d;
int alarms;
int x,j;
unsigned char fmr4; /* must read this always */
- if (!(wc->span.flags & DAHDI_FLAG_RUNNING))
+ if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)))
return;
- c = t1_getreg_isr(wc, 0x4c);
- fmr4 = t1_getreg_isr(wc, 0x20); /* must read this even if we don't use it */
- d = t1_getreg_isr(wc, 0x4d);
+ 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);
/* Assume no alarms */
alarms = 0;
@@ -1282,16 +1076,16 @@ static inline void __t1_check_alarms(struct t1 *wc)
we haven't found a multiframe since last loss
of frame */
if (!wc->flags.nmf) {
- t1_setreg_full(wc, 0x20, 0x9f | 0x20, 1, NOT_VPM); /* LIM0: Force RAI High */
+ t1_setreg_full(wc, 0x20, 0x9f | 0x20, NOT_VPM); /* LIM0: Force RAI High */
wc->flags.nmf = 1;
module_printk("NMF workaround on!\n");
}
- t1_setreg_full(wc, 0x1e, 0xc3, 1, NOT_VPM); /* Reset to CRC4 mode */
- t1_setreg_full(wc, 0x1c, 0xf2, 1, NOT_VPM); /* Force Resync */
- t1_setreg_full(wc, 0x1c, 0xf0, 1, NOT_VPM); /* Force Resync */
+ t1_setreg_full(wc, 0x1e, 0xc3, NOT_VPM); /* Reset to CRC4 mode */
+ t1_setreg_full(wc, 0x1c, 0xf2, NOT_VPM); /* Force Resync */
+ t1_setreg_full(wc, 0x1c, 0xf0, NOT_VPM); /* Force Resync */
} else if (!(c & 0x02)) {
if (wc->flags.nmf) {
- t1_setreg_full(wc, 0x20, 0x9f, 1, NOT_VPM); /* LIM0: Clear forced RAI */
+ t1_setreg_full(wc, 0x20, 0x9f, NOT_VPM); /* LIM0: Clear forced RAI */
wc->flags.nmf = 0;
module_printk("NMF workaround off!\n");
}
@@ -1301,8 +1095,8 @@ static inline void __t1_check_alarms(struct t1 *wc)
if ((!wc->span.mainttimer) && (d & 0x08)) {
/* Loop-up code detected */
if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) {
- t1_setreg_full(wc, 0x36, 0x08, 1, NOT_VPM); /* LIM0: Disable any local loop */
- t1_setreg_full(wc, 0x37, 0xf6, 1, NOT_VPM); /* LIM1: Enable remote loop */
+ t1_setreg_full(wc, 0x36, 0x08, NOT_VPM); /* LIM0: Disable any local loop */
+ t1_setreg_full(wc, 0x37, 0xf6, NOT_VPM); /* LIM1: Enable remote loop */
wc->span.maintstat = DAHDI_MAINT_REMOTELOOP;
}
} else
@@ -1311,8 +1105,8 @@ static inline void __t1_check_alarms(struct t1 *wc)
if ((!wc->span.mainttimer) && (d & 0x10)) {
/* Loop-down code detected */
if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) {
- t1_setreg_full(wc, 0x36, 0x08, 1, NOT_VPM); /* LIM0: Disable any local loop */
- t1_setreg_full(wc, 0x37, 0xf0, 1, NOT_VPM); /* LIM1: Disable remote loop */
+ t1_setreg_full(wc, 0x36, 0x08, NOT_VPM); /* LIM0: Disable any local loop */
+ t1_setreg_full(wc, 0x37, 0xf0, NOT_VPM); /* LIM1: Disable remote loop */
wc->span.maintstat = DAHDI_MAINT_NONE;
}
} else
@@ -1341,7 +1135,7 @@ static inline void __t1_check_alarms(struct t1 *wc)
/* Keep track of recovering */
if ((!alarms) && wc->span.alarms)
- wc->alarmtimer = DAHDI_ALARMSETTLE_TIME;
+ wc->alarmtimer = jiffies + 5*HZ;
if (wc->alarmtimer)
alarms |= DAHDI_ALARM_RECOVER;
@@ -1350,12 +1144,12 @@ static inline void __t1_check_alarms(struct t1 *wc)
module_printk("Setting yellow alarm\n");
/* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
- t1_setreg_full(wc, 0x20, fmr4 | 0x20, 1, NOT_VPM);
+ t1_setreg_full(wc, 0x20, fmr4 | 0x20, NOT_VPM);
wc->flags.sendingyellow = 1;
} else if (!alarms && wc->flags.sendingyellow) {
module_printk("Clearing yellow alarm\n");
/* We manually do yellow alarm to handle RECOVER */
- t1_setreg_full(wc, 0x20, fmr4 & ~0x20, 1, NOT_VPM);
+ t1_setreg_full(wc, 0x20, fmr4 & ~0x20, NOT_VPM);
wc->flags.sendingyellow = 0;
}
@@ -1364,86 +1158,57 @@ static inline void __t1_check_alarms(struct t1 *wc)
if (wc->span.mainttimer || wc->span.maintstat)
alarms |= DAHDI_ALARM_LOOPBACK;
wc->span.alarms = alarms;
- spin_unlock(&wc->reglock);
dahdi_alarm_notify(&wc->span);
- spin_lock(&wc->reglock);
}
-static inline void __handle_leds(struct t1 *wc)
+static void handle_leds(struct t1 *wc)
{
+ unsigned char led;
+ unsigned long flags;
+
+ led = wc->ledstate;
+
if (wc->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) {
- wc->blinktimer++;
- if (wc->blinktimer == 160)
- wc->ledtestreg = SET_LED_RED(wc->ledtestreg);
- if (wc->blinktimer == 480) {
- wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
- wc->blinktimer = 0;
+ /* When we're in red alarm, blink the led once a second. */
+ if (time_after(jiffies, wc->blinktimer)) {
+ led = (led & __LED_GREEN) ? SET_LED_RED(led) : UNSET_LED_REDGREEN(led);
}
} else if (wc->span.alarms & DAHDI_ALARM_YELLOW) {
- wc->yellowtimer++;
- if (!(wc->yellowtimer % 2))
- wc->ledtestreg = SET_LED_RED(wc->ledtestreg);
- else
- wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg);
+ led = (led & __LED_RED) ? SET_LED_GREEN(led) : SET_LED_RED(led);
} else {
if (wc->span.maintstat != DAHDI_MAINT_NONE)
- wc->ledtestreg = SET_LED_ORANGE(wc->ledtestreg);
+ led = SET_LED_ORANGE(led);
else
- wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg);
- if (wc->span.flags & DAHDI_FLAG_RUNNING)
- wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg);
- else
- wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
- }
+ led = UNSET_LED_ORANGE(led);
- if (wc->ledtestreg != wc->ledlastvalue) {
- t1_setleds(wc, wc->ledtestreg, 1);
- wc->ledlastvalue = wc->ledtestreg;
+ if (test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))
+ led = SET_LED_GREEN(led);
+ else
+ led = UNSET_LED_REDGREEN(led);
}
-}
-
-static void __t1_do_counters(struct t1 *wc)
-{
- if (wc->alarmtimer) {
- if (!--wc->alarmtimer) {
- wc->span.alarms &= ~(DAHDI_ALARM_RECOVER);
- dahdi_alarm_notify(&wc->span);
+ if (led != wc->ledstate) {
+ struct command *cmd;
+ cmd = get_free_cmd(wc);
+ if (cmd) {
+ wc->blinktimer = jiffies + HZ/2;
+ cmd->flags |= __CMD_LEDS;
+ cmd->address = ~led & 0x0E;
+ submit_cmd(wc, cmd);
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->ledstate = led;
+ spin_unlock_irqrestore(&wc->reglock, flags);
}
}
}
-static inline void t1_isr_misc(struct t1 *wc)
-{
- const unsigned int x = wc->intcount & 0x3f;
- int buffer_count = voicebus_current_latency(wc->vb);
-
- if (unlikely(!wc->initialized)) return;
-
- __handle_leds(wc);
-
- __t1_do_counters(wc);
- if ( 0 == x ) {
- __t1_check_sigbits_reads(wc);
- }
- else if ( 1 == x ) {
- if (!(wc->intcount & 0x30)) {
- __t1_check_alarms_reads(wc);
- wc->alarms_read=1;
- }
- }
- else if ( x == buffer_count*2) {
- __t1_check_sigbits(wc);
- }
- else if ( x == (buffer_count*2)+1 ) {
- if (wc->alarms_read) {
- __t1_check_alarms(wc);
- wc->alarms_read=0;
- }
- }
- else if ( x == (buffer_count*2)+2) {
- clean_leftovers(wc);
+static void t1_do_counters(struct t1 *wc)
+{
+ if (wc->alarmtimer && time_after(jiffies, wc->alarmtimer)) {
+ wc->span.alarms &= ~(DAHDI_ALARM_RECOVER);
+ wc->alarmtimer = 0;
+ dahdi_alarm_notify(&wc->span);
}
}
@@ -1454,14 +1219,12 @@ static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk)
int chan;
/* Calculate Transmission */
- if (likely(wc->initialized)) {
- spin_unlock(&wc->reglock);
+ if (likely(test_bit(INITIALIZED, &wc->bit_flags))) {
dahdi_transmit(&wc->span);
- spin_lock(&wc->reglock);
}
for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
- if (likely(wc->initialized)) {
+ if (likely(test_bit(INITIALIZED, &wc->bit_flags))) {
for (chan = 0; chan < wc->span.channels; chan++)
writechunk[(chan+1)*2] = wc->chans[chan]->writechunk[x];
}
@@ -1472,7 +1235,9 @@ static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk)
}
#ifdef VPM_SUPPORT
if(likely(wc->vpm150m)) {
+ spin_lock(&wc->reglock);
vpm150m_cmd_dequeue(wc, writechunk, x);
+ spin_unlock(&wc->reglock);
}
#endif
@@ -1484,25 +1249,13 @@ static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk)
}
}
-static inline void cmd_retransmit(struct t1 *wc)
-{
- unsigned int x;
-
- for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
- if (!(wc->cmdq.cmds[x].flags & __CMD_FIN)) {
- wc->cmdq.cmds[x].flags &= ~(__CMD_TX) ; /* clear __CMD_TX */
- wc->cmdq.cmds[x].ident = 0;
- }
- }
-}
-
static inline void t1_receiveprep(struct t1 *wc, unsigned char* readchunk)
{
int x,chan;
unsigned char expected;
for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
- if (likely(wc->initialized)) {
+ if (likely(test_bit(INITIALIZED, &wc->bit_flags))) {
for (chan = 0; chan < wc->span.channels; chan++) {
wc->chans[chan]->readchunk[x]= readchunk[(chan+1)*2];
}
@@ -1513,65 +1266,75 @@ static inline void t1_receiveprep(struct t1 *wc, unsigned char* readchunk)
wc->statreg = readchunk[EFRAME_SIZE + 2];
if (wc->rxident != expected) {
wc->span.irqmisses++;
- cmd_retransmit(wc);
- if (unlikely(debug && wc->initialized))
+ resend_cmds(wc);
+ if (unlikely(debug && test_bit(INITIALIZED, &wc->bit_flags)))
module_printk("oops: rxident=%d expected=%d x=%d\n", wc->rxident, expected, x);
}
}
cmd_decipher(wc, readchunk);
#ifdef VPM_SUPPORT
- if(wc->vpm150m)
+ if (wc->vpm150m) {
+ spin_lock(&wc->reglock);
vpm150m_cmd_decipher(wc, readchunk);
+ spin_unlock(&wc->reglock);
+ }
#endif
readchunk += (EFRAME_SIZE + EFRAME_GAP);
}
/* echo cancel */
- if (likely(wc->initialized)) {
- spin_unlock(&wc->reglock);
+ if (likely(test_bit(INITIALIZED, &wc->bit_flags))) {
for (x = 0; x < wc->span.channels; x++) {
dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->ec_chunk2[x]);
memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],DAHDI_CHUNKSIZE);
memcpy(wc->ec_chunk1[x],wc->chans[x]->writechunk,DAHDI_CHUNKSIZE);
}
dahdi_receive(&wc->span);
- spin_lock(&wc->reglock);
}
-
- /* Wake up anyone sleeping to read/write a new register */
- wake_up_interruptible(&wc->regq);
}
static void
t1_handle_transmit(void* vbb, void* context)
{
struct t1* wc = context;
- /* Either this function is called from within interrupt context, or
- * the reglock will never be acquired from interrupt context, so it's
- * safe to grab it without locking interrupt.
- */
memset(vbb, 0, SFRAME_SIZE);
- spin_lock(&wc->reglock);
- wc->txints++;
+ atomic_inc(&wc->txints);
t1_transmitprep(wc, vbb);
- wc->intcount++;
- t1_isr_misc(wc);
- spin_unlock(&wc->reglock);
voicebus_transmit(wc->vb, vbb);
+ handle_leds(wc);
}
static void
t1_handle_receive(void* vbb, void* context)
{
struct t1* wc = context;
- wc->rxints++;
- /* Either this function is called from within interrupt context, or
- * the reglock will never be acquired from interrupt context, so it's
- * safe to grab it without locking interrupt.
- */
- spin_lock(&wc->reglock);
t1_receiveprep(wc, vbb);
- spin_unlock(&wc->reglock);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void timer_work_func(void *param)
+{
+ struct t1 *wc = param;
+#else
+static void timer_work_func(struct work_struct *work)
+{
+ struct t1 *wc = container_of(work, struct t1, timer_work);
+#endif
+ /* Called once every 100ms */
+ if (unlikely(!test_bit(INITIALIZED, &wc->bit_flags)))
+ return;
+ t1_do_counters(wc);
+ t1_check_alarms(wc);
+ t1_check_sigbits(wc);
+ mod_timer(&wc->timer, jiffies + HZ/5);
+}
+
+static void
+te12xp_timer(unsigned long data)
+{
+ struct t1 *wc = (struct t1 *)data;
+ schedule_work(&wc->timer_work);
+ return;
}
static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -1602,17 +1365,35 @@ retry:
ifaces[index] = wc;
memset(wc, 0, sizeof(*wc));
+ wc->ledstate = -1;
spin_lock_init(&wc->reglock);
+ spin_lock_init(&wc->cmd_list_lock);
+ INIT_LIST_HEAD(&wc->active_cmds);
+ INIT_LIST_HEAD(&wc->pending_cmds);
+
wc->variety = d->name;
wc->txident = 1;
- init_waitqueue_head(&wc->regq);
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
+ wc->timer.function = te12xp_timer;
+ wc->timer.data = (unsigned long)wc;
+ init_timer(&wc->timer);
+# else
+ setup_timer(&wc->timer, te12xp_timer, (unsigned long)wc);
+# endif
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&wc->timer_work, timer_work_func, wc);
+# else
+ INIT_WORK(&wc->timer_work, timer_work_func);
+# endif
+
snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", index);
if ((res = voicebus_init(pdev, SFRAME_SIZE, wc->name,
t1_handle_receive, t1_handle_transmit, wc,
debug, &wc->vb))) {
WARN_ON(1);
- kfree(wc);
+ free_wc(wc);
ifaces[index] = NULL;
return res;
}
@@ -1628,17 +1409,14 @@ retry:
for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) {
if (!(wc->chans[x] = kmalloc(sizeof(*wc->chans[x]), GFP_KERNEL))) {
- while (x) {
- kfree(wc->chans[--x]);
- }
-
- kfree(wc);
+ free_wc(wc);
ifaces[index] = NULL;
return -ENOMEM;
}
memset(wc->chans[x], 0, sizeof(*wc->chans[x]));
}
+ mod_timer(&wc->timer, jiffies + HZ/5);
t1_software_init(wc);
if (voicebus_current_latency(wc->vb) > startinglatency) {
/* The voicebus library increased the latency during
@@ -1652,7 +1430,7 @@ retry:
dahdi_unregister(&wc->span);
voicebus_release(wc->vb);
wc->vb = NULL;
- kfree(wc);
+ free_wc(wc);
wc = NULL;
goto retry;
}
@@ -1680,14 +1458,15 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev)
destroy_workqueue(vpm150m->wq);
}
#endif
+ clear_bit(INITIALIZED, &wc->bit_flags);
+ del_timer_sync(&wc->timer);
+ flush_scheduled_work();
+ del_timer_sync(&wc->timer);
BUG_ON(!wc->vb);
voicebus_release(wc->vb);
wc->vb = NULL;
- if (debug && wc->isrreaderrors)
- debug_printk(1, "isrreaderrors=%d\n", wc->isrreaderrors);
-
#ifdef VPM_SUPPORT
if(vpm150m) {
spin_lock_irqsave(&wc->reglock, flags);
@@ -1697,11 +1476,7 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev)
kfree(wc->vpm150m);
}
#endif
- /* Release span, possibly delayed */
- if (!wc->usecount)
- t1_release(wc);
- else
- wc->dead = 1;
+ t1_release(wc);
}
static struct pci_device_id te12xp_pci_tbl[] = {
@@ -1724,15 +1499,34 @@ static int __init te12xp_init(void)
{
int res;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
+ cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct command), 0,
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)
+ SLAB_HWCACHE_ALIGN | SLAB_STORE_USER, NULL, NULL);
+#else
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+#endif
+#else
+ cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct command), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+#endif
+ if (!cmd_cache)
+ return -ENOMEM;
+
res = dahdi_pci_module(&te12xp_driver);
+ if (res) {
+ kmem_cache_destroy(cmd_cache);
+ return -ENODEV;
+ }
- return res ? -ENODEV : 0;
+ return 0;
}
static void __exit te12xp_cleanup(void)
{
pci_unregister_driver(&te12xp_driver);
+ kmem_cache_destroy(cmd_cache);
}
module_param(debug, int, S_IRUGO | S_IWUSR);
diff --git a/drivers/dahdi/wcte12xp/vpmadt032.c b/drivers/dahdi/wcte12xp/vpmadt032.c
index c9df41c..2424f67 100644
--- a/drivers/dahdi/wcte12xp/vpmadt032.c
+++ b/drivers/dahdi/wcte12xp/vpmadt032.c
@@ -53,7 +53,7 @@ inline void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechun
struct vpm150m_cmd *curcmd = NULL;
struct vpm150m *vpm150m = wc->vpm150m;
int x;
- unsigned char leds = ~((wc->intcount / 1000) % 8) & 0x7;
+ unsigned char leds = ~((atomic_read(&wc->txints) / 1000) % 8) & 0x7;
/* Skip audio */
writechunk += 66;
@@ -225,7 +225,7 @@ inline void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechun
/* Now let's figure out if we need to check for DTMF */
/* polling */
- if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 100))
+ if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(atomic_read(&wc->txints) % 100))
queue_work(vpm150m->wq, &vpm150m->work_dtmf);
#if 0
@@ -296,11 +296,10 @@ static struct vpm150m_cmd * vpm150m_empty_slot(struct t1 *wc)
static inline int vpm150m_io_wait(struct t1 *wc)
{
int x;
- int ret=0;
for (x=0; x < VPM150M_MAX_COMMANDS;) {
if (wc->vpm150m->cmdq[x].flags) {
- if ((ret=schluffen(&wc->regq))) {
- return ret;
+ if (msleep_interruptible(1)) {
+ return -EINTR;
}
x=0;
}
@@ -308,7 +307,7 @@ static inline int vpm150m_io_wait(struct t1 *wc)
++x;
}
}
- return ret;
+ return 0;
}
static int t1_vpm150m_getreg_full_async(struct t1 *wc, int pagechange, unsigned int len,
@@ -351,8 +350,8 @@ static int t1_vpm150m_getreg_full_return(struct t1 *wc, int pagechange, unsigned
}
else {
spin_unlock_irqrestore(&wc->reglock, flags);
- if ((ret=schluffen(&wc->regq))) {
- return ret;
+ if (msleep_interruptible(1)) {
+ return -EINTR;
}
spin_lock_irqsave(&wc->reglock, flags);
ret = -EBUSY;
@@ -370,8 +369,8 @@ static int t1_vpm150m_getreg_full(struct t1 *wc, int pagechange, unsigned int le
ret = t1_vpm150m_getreg_full_async(wc, pagechange, len, addr, outbuf, &hit);
if (!hit) {
if ( -EBUSY == ret ) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
+ if (msleep_interruptible(1))
+ return -EINTR;
}
BUG_ON( 0 != ret);
}
@@ -385,7 +384,7 @@ static int t1_vpm150m_setreg_full(struct t1 *wc, int pagechange, unsigned int le
{
unsigned long flags;
struct vpm150m_cmd *hit;
- int ret, i;
+ int i;
do {
spin_lock_irqsave(&wc->reglock, flags);
hit = vpm150m_empty_slot(wc);
@@ -400,8 +399,8 @@ static int t1_vpm150m_setreg_full(struct t1 *wc, int pagechange, unsigned int le
}
spin_unlock_irqrestore(&wc->reglock, flags);
if (!hit) {
- if ((ret = schluffen(&wc->regq)))
- return ret;
+ if (msleep_interruptible(1))
+ return -EINTR;
}
} while (!hit);
return (hit) ? 0 : -1;
@@ -499,20 +498,25 @@ static void vpm150m_echocan_bh(struct work_struct *data)
struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_echocan);
#endif
struct t1 *wc = vpm150m->wc;
- struct list_head *task;
- struct list_head *next_task;
unsigned long flags;
+ struct vpm150m_workentry *we;
+ struct dahdi_chan *chan;
+ int deflaw;
+ int res;
+ GPAK_AlgControlStat_t pstatus;
- list_for_each_safe(task, next_task, &vpm150m->worklist) {
- struct vpm150m_workentry *we = list_entry(task, struct vpm150m_workentry, list);
- struct dahdi_chan *chan = we->chan;
- int deflaw;
- int res;
- GPAK_AlgControlStat_t pstatus;
+ while (!list_empty(&vpm150m->worklist)) {
+ we = list_entry(vpm150m->worklist.next, struct vpm150m_workentry, list);
+
+ spin_lock_irqsave(&vpm150m->lock, flags);
+ list_del(&we->list);
+ spin_unlock_irqrestore(&vpm150m->lock, flags);
+
+ chan = we->chan;
if (we->params.tap_length) {
/* configure channel for the ulaw/alaw */
- unsigned int start = wc->intcount;
+ unsigned int start = atomic_read(&wc->txints);
if (memcmp(&we->params, &vpm150m->chan_params[chan->chanpos - 1], sizeof(we->params))) {
/* set parameters */
@@ -535,9 +539,9 @@ static void vpm150m_echocan_bh(struct work_struct *data)
}
res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableEcanA, &pstatus);
- debug_printk(2, "Echo can enable took %d ms\n", wc->intcount - start);
+ debug_printk(2, "Echo can enable took %d ms\n", atomic_read(&wc->txints) - start);
} else {
- unsigned int start = wc->intcount;
+ unsigned int start = atomic_read(&wc->txints);
debug_printk(1, "Disabling EC on channel %d\n", chan->chanpos);
res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, BypassSwCompanding, &pstatus);
if (res)
@@ -545,15 +549,12 @@ static void vpm150m_echocan_bh(struct work_struct *data)
res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, BypassEcanA, &pstatus);
if (res)
module_printk("Unable to disable echo can on channel %d (reason %d)\n", chan->chanpos, res);
- debug_printk(2, "Echocan disable took %d ms\n", wc->intcount - start);
+ debug_printk(2, "Echocan disable took %d ms\n", atomic_read(&wc->txints) - start);
}
if (res) {
module_printk("Unable to toggle echo cancellation on channel %d (reason %d)\n", chan->chanpos, res);
}
- spin_lock_irqsave(&vpm150m->lock, flags);
- list_del(task);
- spin_unlock_irqrestore(&vpm150m->lock, flags);
kfree(we);
}
}
@@ -606,16 +607,16 @@ static void vpm150m_dtmf_bh(struct work_struct *data)
}
}
if (enable > -1) {
- unsigned int start = wc->intcount;
+ unsigned int start = atomic_read(&wc->txints);
GPAK_AlgControlStat_t pstatus;
int res;
if (enable) {
res = gpakAlgControl(vpm150m->dspid, i, EnableDTMFMuteA, &pstatus);
- debug_printk(2, "DTMF mute enable took %d ms\n", wc->intcount - start);
+ debug_printk(2, "DTMF mute enable took %d ms\n", atomic_read(&wc->txints) - start);
} else {
res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &pstatus);
- debug_printk(2, "DTMF mute disable took %d ms\n", wc->intcount - start);
+ debug_printk(2, "DTMF mute disable took %d ms\n", atomic_read(&wc->txints) - start);
}
if (!res)
change_bit(i, &vpm150m->curdtmfmutestate);
@@ -627,11 +628,11 @@ static void vpm150m_dtmf_bh(struct work_struct *data)
GpakAsyncEventCode_t eventcode;
GpakAsyncEventData_t eventdata;
gpakReadEventFIFOMessageStat_t res;
- unsigned int start = wc->intcount;
+ unsigned int start = atomic_read(&wc->txints);
do {
res = gpakReadEventFIFOMessage(vpm150m->dspid, &channel, &eventcode, &eventdata);
- debug_printk(3, "ReadEventFIFOMessage took %d ms\n", wc->intcount - start);
+ debug_printk(3, "ReadEventFIFOMessage took %d ms\n", atomic_read(&wc->txints) - start);
if (res == RefInvalidEvent || res == RefDspCommFailure) {
module_printk("Uh oh (%d)\n", res);
@@ -735,7 +736,7 @@ void t1_vpm150m_init(struct t1 *wc) {
spin_unlock_irqrestore(&wc->reglock, flags);
for (i = 0; i < 10; i++)
- schluffen(&wc->regq);
+ msleep_interruptible(1);
debug_printk(1, "Looking for VPMADT032 by testing page access: ");
for (i = 0; i < 0xf; i++) {
@@ -854,7 +855,7 @@ void t1_vpm150m_init(struct t1 *wc) {
set_bit(VPM150M_HPIRESET, &vpm150m->control);
while (test_bit(VPM150M_HPIRESET, &vpm150m->control))
- schluffen(&wc->regq);
+ msleep(1);
module_printk("VPMADT032 Loading firmware... ");
downloadstatus = gpakDownloadDsp(vpm150m->dspid, &fw);
@@ -872,7 +873,7 @@ void t1_vpm150m_init(struct t1 *wc) {
set_bit(VPM150M_SWRESET, &vpm150m->control);
while (test_bit(VPM150M_SWRESET, &vpm150m->control))
- schluffen(&wc->regq);
+ msleep(1);
msleep(700);
#if 0
diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h
index 9cecf0d..655ac30 100644
--- a/drivers/dahdi/wcte12xp/wcte12xp.h
+++ b/drivers/dahdi/wcte12xp/wcte12xp.h
@@ -51,29 +51,26 @@
#define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
-#define MAX_COMMANDS 7*7*2*2 /* 42 bytes /3 (cntl,addr,data) /2 (cs) */
+#define MAX_COMMANDS 16
#define NUM_EC 4
#define __CMD_VPM (1 << 16) /* flag for VPM action */
-#define __CMD_ISR (1 << 17) /* flag for ISR reads */
#define __CMD_PINS (1 << 18) /* CPLD pin read */
#define __CMD_LEDS (1 << 19) /* LED Operation */
#define __CMD_RD (1 << 20) /* Read Operation */
#define __CMD_WR (1 << 21) /* Write Operation */
-#define __CMD_FIN (1 << 22) /* Has finished receive */
-#define __CMD_TX (1 << 23) /* Has been transmitted */
#define __LED_ORANGE (1<<3)
#define __LED_GREEN (1<<2)
#define __LED_RED (1<<1)
-#define SET_LED_ORANGE(a) a | __LED_ORANGE
-#define SET_LED_RED(a) (a | __LED_RED) & ~__LED_GREEN
-#define SET_LED_GREEN(a) (a | __LED_GREEN) & ~__LED_RED
+#define SET_LED_ORANGE(a) (a | __LED_ORANGE)
+#define SET_LED_RED(a) ((a | __LED_RED) & ~__LED_GREEN)
+#define SET_LED_GREEN(a) ((a | __LED_GREEN) & ~__LED_RED)
-#define UNSET_LED_ORANGE(a) a & ~__LED_ORANGE
-#define UNSET_LED_REDGREEN(a) a | __LED_RED | __LED_GREEN
+#define UNSET_LED_ORANGE(a) (a & ~__LED_ORANGE)
+#define UNSET_LED_REDGREEN(a) (a | __LED_RED | __LED_GREEN)
#define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR)
#define CMD_RD(a) (((a) << 8) | __CMD_RD)
@@ -92,16 +89,14 @@
extern spinlock_t ifacelock;
struct command {
- unsigned short address;
- unsigned char data;
- unsigned char ident;
- unsigned int flags;
- unsigned char cs_slot;
- unsigned char vpm_num; /* ignored for all but vpm commmands */
-};
-
-struct cmdq {
- struct command cmds[MAX_COMMANDS];
+ u8 data;
+ u8 ident;
+ u8 cs_slot;
+ u8 vpm_num; /* ignored for all but vpm commmands */
+ u16 address;
+ u32 flags;
+ struct list_head node;
+ struct completion complete;
};
struct vpm150m;
@@ -117,38 +112,24 @@ struct t1 {
unsigned int sendingyellow:1;
} flags;
unsigned char txsigs[16]; /* Copy of tx sig registers */
- int num;
int alarmcount; /* How much red alarm we've seen */
- int alarmdebounce;
char *variety;
char name[80];
- unsigned int intcount;
- int sync;
- int dead;
- int blinktimer;
- int alarmtimer;
- int yellowtimer;
- int ledlastvalue;
- int alarms_read;
- int checktiming; /* Set >0 to cause the timing source to be checked */
+ unsigned long blinktimer;
int loopupcnt;
int loopdowncnt;
- int initialized;
- int *chanmap;
- unsigned char ledtestreg;
+#define INITIALIZED 1
+#define SHUTDOWN 2
+ unsigned long bit_flags;
+ unsigned long alarmtimer;
+ unsigned char ledstate;
unsigned char ec_chunk1[32][DAHDI_CHUNKSIZE];
unsigned char ec_chunk2[32][DAHDI_CHUNKSIZE];
struct dahdi_span span; /* Span */
struct dahdi_chan *chans[32]; /* Channels */
- wait_queue_head_t regq;
- struct cmdq cmdq;
- struct command dummy; /* preallocate for dummy noop command */
- unsigned char ctlreg;
- unsigned int rxints;
- unsigned int txints;
- int usecount;
+ unsigned long ctlreg;
struct voicebus* vb;
- unsigned int isrreaderrors;
+ atomic_t txints;
#ifdef VPM_SUPPORT
int vpm;
struct vpm150m *vpm150m;
@@ -156,8 +137,15 @@ struct t1 {
unsigned long dtmfmask;
unsigned long dtmfmutemask;
#endif
+
+ spinlock_t cmd_list_lock;
+ struct list_head pending_cmds;
+ struct list_head active_cmds;
+ struct timer_list timer;
+ struct work_struct timer_work;
};
+
int schluffen(wait_queue_head_t *q);
#endif