From 4db210945e3a3d4c92f7d791e207b743d77ec05b Mon Sep 17 00:00:00 2001 From: jsloan Date: Mon, 11 Jun 2007 15:47:37 +0000 Subject: Fixed SMP bugs on quad processor machines. Reduced memory usage git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@2621 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- wctc4xxp/base.c | 121 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 35 deletions(-) (limited to 'wctc4xxp') diff --git a/wctc4xxp/base.c b/wctc4xxp/base.c index b7138e3..6ff049f 100644 --- a/wctc4xxp/base.c +++ b/wctc4xxp/base.c @@ -62,6 +62,7 @@ extern void _binary_tc400m_firmware_bin_size; /* #define USE_TEST_HW */ #define USE_TDM_CONFIG +#define QUIET_DSP #define WC_MAX_IFACES 128 @@ -238,6 +239,17 @@ extern void _binary_tc400m_firmware_bin_size; #define CMD_MSG_VOIP_INDCTRL(s,c) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x84,0x80, 0x00,0x00, \ 0x07,0x00, 0x00,0x00 } +#define CMD_MSG_VOIP_DTMFOPT_LEN 32 +#define CMD_MSG_VOIP_DTMFOPT(s,c) { \ + 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ + 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x02,0x80, 0x00,0x00, \ + 0x08,0x00, 0x00,0x00 } + +#define CMD_MSG_VOIP_TONECTL_LEN 32 +#define CMD_MSG_VOIP_TONECTL(s,c) { \ + 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ + 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x5B,0x80, 0x00,0x00, \ + 0x00,0x00, 0x00,0x00 } /* CPU ACK command */ #define CMD_MSG_ACK_LEN 20 @@ -274,6 +286,7 @@ extern void _binary_tc400m_firmware_bin_size; wc->cmdq[wc->cmdq_wndx].cmdlen = length; \ for (i = 0; i < length; i++) \ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \ + wc->last_seqno = fifo[16]; \ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \ } \ __transmit_demand(wc); \ @@ -287,7 +300,7 @@ extern void _binary_tc400m_firmware_bin_size; struct cmdq { unsigned int cmdlen; - unsigned int cmd[MAX_COMMAND_LEN]; + unsigned char cmd[MAX_COMMAND_LEN]; }; struct wcdte { @@ -312,6 +325,8 @@ struct wcdte { unsigned int cmdq_wndx; unsigned int cmdq_rndx; + unsigned int last_seqno; + unsigned int last_rseqno; unsigned int last_command_sent; unsigned int last_rcommand; unsigned int last_rparm2; @@ -367,6 +382,8 @@ struct dte_state { unsigned int timestamp; unsigned int seqno; + unsigned int cmd_seqno; + unsigned int timeslot_in_num; /* DTE chennel on which results we be received from */ unsigned int timeslot_out_num; /* DTE channel to send data to */ @@ -420,6 +437,8 @@ static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned in state_ptr->timestamp = 0; state_ptr->seqno = 0; + state_ptr->cmd_seqno = 0; + state_ptr->packets_sent = 0; state_ptr->packets_received = 0; state_ptr->last_dte_seqno = 0; @@ -648,6 +667,8 @@ static int dte_operation(struct zt_transcoder_channel *ztc, int op) up(&wc->chansem); break; case ZT_TCOP_TRANSCODE: + if (ztc->chan_built == 0) + printk("wcdte error: Sending data to a channel that isn't built yet\n"); if ( (((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) ) || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES)) || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_BYTES)) ) @@ -806,13 +827,19 @@ static inline void wcdte_receiveprep(struct wcdte *wc, int dbl) wc->rcvflags = RCV_CSMENCAPS; - wc->last_rcommand = rcommand; - wc->last_rparm2 = readchunk[30] | (readchunk[31] << 8); - wake_up_interruptible(&wc->regq); + if (rcommand == wc->last_command_sent) { + wc->last_rcommand = rcommand; + wc->last_rparm2 = readchunk[30] | (readchunk[31] << 8); + wake_up_interruptible(&wc->regq); + } else { + if (debug) + printk("wcdte error: unexpected command response received (sent: %04X, received: %04X)\n", wc->last_command_sent, rcommand); + } up(&wc->cmdqsem); } else { + wc->last_rseqno = readchunk[16]; wc->rcvflags = RCV_CSMENCAPS_ACK; wake_up_interruptible(&wc->regq); } @@ -1024,20 +1051,11 @@ static void dte_wque_run(void *work_data) #endif int res; - if (wc->wqueints & 0x00000040) { - /* Loop descriptors is available */ - do { - res = wcdte_check_descriptor(wc); - } while(res); - } + do { + res = wcdte_check_descriptor(wc); + } while(res); - /* Handle TX interrupts */ - if (wc->wqueints & 0x00000001) - { - wc->txints++; - transmit_demand(wc); - wc->intcount++; - } + transmit_demand(wc); } ZAP_IRQ_HANDLER(wcdte_interrupt) @@ -1105,6 +1123,7 @@ static int wcdte_hardware_init(struct wcdte *wc) newjiffies = jiffies + HZ/10; while(((reg = wcdte_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)); + wcdte_setctl(wc, 0x0000, 0xFFFA0000); /* Configure watchdogs, access, etc */ wcdte_setctl(wc, 0x0030, 0x00280048); @@ -1169,18 +1188,20 @@ static void wcdte_disable_interrupts(struct wcdte *wc) wcdte_setctl(wc, 0x0084, 0x00000000); } -static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int use_mask) +static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int wait_mode) { int ret; - if (use_mask) + if (wait_mode == 1) ret = wait_event_interruptible_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout); + else if (wait_mode == 2) + ret = wait_event_interruptible_timeout(wc->regq, ((wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)), wc->timeout); else - ret = wait_event_interruptible_timeout(wc->regq, (wc->last_rcommand == wc->last_command_sent), wc->timeout); + ret = wait_event_interruptible_timeout(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)), wc->timeout); wc->rcvflags = 0; wc->last_rcommand = 0; - wc->last_command_sent = 0; + wc->last_seqno = 0; if (ret < 0) { @@ -1191,9 +1212,12 @@ static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int use_ if (ret == 0) { if (debug) - printk("wcdte error: Waitfor CSMENCAPS response timed out (ret = %d)\n", ret); + printk("wcdte error: Waitfor CSMENCAPS response timed out (ret = %d) (cmd_snt = %04X)\n", ret, wc->last_command_sent); return(2); } + if (wait_mode == 0) + wc->last_command_sent = 999; + wc->last_rseqno = 999; return(0); } @@ -1345,6 +1369,7 @@ static int wcdte_boot_processor(struct wcdte *wc, const struct firmware *firmwar } while (byteloc < firmware->size-20); wc->timeout = 10 * HZ; + wc->last_command_sent = 0; if (wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 1)) return(1); @@ -1360,6 +1385,8 @@ static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, i { int length = 0; unsigned char chan1, chan2; + struct zt_transcoder_channel *ztc1, *ztc2; + struct dte_state *st1, *st2; if(complicated == DTE_FORMAT_G729A) length = G729_LENGTH; else if (complicated == DTE_FORMAT_G723_1) @@ -1373,19 +1400,31 @@ static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, i zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); chan2 = wc->last_rparm2; + ztc1 = &(wc->uencode->channels[part1_id/2]); + ztc2 = &(wc->udecode->channels[part2_id/2]); + st1 = ztc1->pvt; + st2 = ztc2->pvt; + /* Configure complex channel */ - zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(wc->seq_num++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); - zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(wc->seq_num++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); + zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st1->cmd_seqno++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); + zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st1->cmd_seqno++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); /* Configure simple channel */ - zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(wc->seq_num++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); - zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(wc->seq_num++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); + zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st2->cmd_seqno++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); + zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st2->cmd_seqno++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); + +#ifdef QUIET_DSP + zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_TONECTL_LEN, 0x805B); + zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002); + zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_TONECTL_LEN, 0x805B); + zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002); + zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); + zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); +#endif zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); - zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(wc->seq_num++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); - zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(wc->seq_num++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(wc->seq_num++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(wc->seq_num++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); + zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st1->cmd_seqno++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); + zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st2->cmd_seqno++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); *dte_chan1 = chan1; *dte_chan2 = chan2; @@ -1395,16 +1434,23 @@ static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, i static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2) { + struct zt_transcoder_channel *ztc1, *ztc2; + struct dte_state *st1, *st2; + + ztc1 = &(wc->uencode->channels[chan1/2]); + ztc2 = &(wc->udecode->channels[chan2/2]); + st1 = ztc1->pvt; + st2 = ztc2->pvt; /* Turn off both channels */ - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(wc->seq_num++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); - zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(wc->seq_num++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); + zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); + zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); /* Disconnect the channels */ zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); /* Remove the channels */ - zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); + zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); return 1; @@ -1412,6 +1458,8 @@ static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned static int wcdte_setup_channels(struct wcdte *wc) { + down(&wc->chansem); + #ifndef USE_TEST_HW zt_send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411); zt_send_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++), CMD_MSG_SET_SPU_CLK_LEN, 0x0412); @@ -1443,7 +1491,9 @@ static int wcdte_setup_channels(struct wcdte *wc) zt_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++), CMD_MSG_TDM_OPT_LEN, 0x0435); #endif - wc->timeout = HZ/100 + 1; /* 10msec */ + wc->timeout = HZ/10 + 1; /* 100msec */ + + up(&wc->chansem); return(0); } @@ -1502,6 +1552,7 @@ static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_devic wc->tdbl = 0; wc->rdbl = 0; wc->rcvflags = 0; + wc->last_seqno = 999; wc->last_command_sent = 0; wc->last_rcommand = 0; wc->last_rparm2 = 0; @@ -1538,7 +1589,7 @@ static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_devic init_waitqueue_head(&wc->regq); /* Initialize the work queue */ - wc->dte_wq = create_workqueue("tc400b"); + wc->dte_wq = create_singlethread_workqueue("tc400b"); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) INIT_WORK(&wc->dte_work, dte_wque_run); #else -- cgit v1.2.3