wctc4xxp: Speed up channel setup / tear-down.

1) Enabling multiple csm_encaps channel commands in a single packet.
2) Sending commands to separate channels in parallel.

This reduces the time waiting for the responses to the commands and brings in
the channel setup from 50ms to under 10ms.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
This commit is contained in:
Shaun Ruffell 2014-05-16 14:33:12 -05:00 committed by Russ Meyerriecks
parent c9481d30bb
commit 6e2698f4c1

View File

@ -145,14 +145,7 @@ struct rtp_packet {
__u8 payload[0]; __u8 payload[0];
} __attribute__((packed)); } __attribute__((packed));
/* Ethernet packet type for communication control information to the DTE. */ struct csm_encaps_cmd {
struct csm_encaps_hdr {
struct ethhdr ethhdr;
/* CSM_ENCAPS HEADER */
__be16 op_code;
__u8 seq_num;
__u8 control;
__be16 channel;
/* COMMON PART OF PAYLOAD HEADER */ /* COMMON PART OF PAYLOAD HEADER */
__u8 length; __u8 length;
__u8 index; __u8 index;
@ -163,6 +156,18 @@ struct csm_encaps_hdr {
__le16 params[0]; __le16 params[0];
} __attribute__((packed)); } __attribute__((packed));
/* Ethernet packet type for communication control information to the DTE. */
struct csm_encaps_hdr {
struct ethhdr ethhdr;
/* CSM_ENCAPS HEADER */
__be16 op_code;
__u8 seq_num;
__u8 control;
__be16 channel;
/* There is always at least one command. */
struct csm_encaps_cmd cmd;
} __attribute__((packed));
#define CONTROL_PACKET_OPCODE 0x0001 #define CONTROL_PACKET_OPCODE 0x0001
/* Control bits */ /* Control bits */
#define LITTLE_ENDIAN 0x01 #define LITTLE_ENDIAN 0x01
@ -202,7 +207,8 @@ struct tcb {
#define WAIT_FOR_ACK (1 << 3) #define WAIT_FOR_ACK (1 << 3)
#define WAIT_FOR_RESPONSE (1 << 4) #define WAIT_FOR_RESPONSE (1 << 4)
#define DTE_CMD_TIMEOUT (1 << 5) #define DTE_CMD_TIMEOUT (1 << 5)
unsigned long flags; u16 flags;
u16 next_index;
struct completion *complete; struct completion *complete;
struct tcb *response; struct tcb *response;
struct channel_pvt *cpvt; struct channel_pvt *cpvt;
@ -1028,14 +1034,8 @@ wctc4xxp_transmit_demand_poll(struct wcdte *wc)
#endif #endif
} }
/* Returns the size, in bytes, of a CSM_ENCAPS packet, given the number of #define LENGTH_WITH_N_PARAMETERS(__n) (((__n) * sizeof(u16)) + \
* parameters used. */ sizeof(struct csm_encaps_cmd))
#define SIZE_WITH_N_PARAMETERS(__n) (sizeof(struct csm_encaps_hdr) + \
((__n) * (sizeof(u16))))
/* There are 20 bytes in the ethernet header and the common CSM_ENCAPS header
* that we don't want in the length of the actual CSM_ENCAPS command */
#define LENGTH_WITH_N_PARAMETERS(__n) (SIZE_WITH_N_PARAMETERS(__n) - 20)
static const u8 dst_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; static const u8 dst_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
static const u8 src_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; static const u8 src_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
@ -1061,15 +1061,6 @@ setup_supervisor_header(struct wcdte *wc, struct csm_encaps_hdr *hdr)
hdr->channel = cpu_to_be16(SUPERVISOR_CHANNEL); hdr->channel = cpu_to_be16(SUPERVISOR_CHANNEL);
} }
static void
setup_channel_header(struct channel_pvt *pvt, struct csm_encaps_hdr *hdr)
{
setup_common_header(pvt->wc, hdr);
hdr->op_code = cpu_to_be16(CONTROL_PACKET_OPCODE);
hdr->seq_num = (pvt->cmd_seqno++)&0xf;
hdr->channel = cpu_to_be16(pvt->chan_in_num);
}
static void static void
create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class, create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class,
u16 function, const u16 *parameters, const int num_parameters) u16 function, const u16 *parameters, const int num_parameters)
@ -1084,26 +1075,26 @@ create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class,
setup_supervisor_header(wc, hdr); setup_supervisor_header(wc, hdr);
hdr->length = LENGTH_WITH_N_PARAMETERS(num_parameters); hdr->cmd.length = LENGTH_WITH_N_PARAMETERS(num_parameters);
hdr->index = 0; hdr->cmd.index = 0;
hdr->type = type; hdr->cmd.type = type;
hdr->class = class; hdr->cmd.class = class;
hdr->function = cpu_to_le16(function); hdr->cmd.function = cpu_to_le16(function);
hdr->reserved = 0; hdr->cmd.reserved = 0;
for (i = 0; i < num_parameters; ++i) for (i = 0; i < num_parameters; ++i)
hdr->params[i] = cpu_to_le16(parameters[i]); hdr->cmd.params[i] = cpu_to_le16(parameters[i]);
cmd->flags = WAIT_FOR_RESPONSE; cmd->flags = WAIT_FOR_RESPONSE;
cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters); cmd->data_len = sizeof(struct csm_encaps_hdr) -
sizeof(struct csm_encaps_cmd) +
hdr->cmd.length;
cmd->cpvt = NULL; cmd->cpvt = NULL;
} }
static void static void
create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class, setup_channel_header(struct channel_pvt *pvt, struct tcb *cmd)
u16 function, const u16 *parameters, int num_parameters)
{ {
int i;
struct csm_encaps_hdr *hdr = cmd->data; struct csm_encaps_hdr *hdr = cmd->data;
if (cmd->response) { if (cmd->response) {
@ -1111,21 +1102,50 @@ create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class,
cmd->response = NULL; cmd->response = NULL;
} }
setup_channel_header(pvt, hdr); setup_common_header(pvt->wc, hdr);
hdr->op_code = cpu_to_be16(CONTROL_PACKET_OPCODE);
hdr->length = LENGTH_WITH_N_PARAMETERS(num_parameters); hdr->seq_num = (pvt->cmd_seqno++)&0xf;
hdr->index = 0; hdr->channel = cpu_to_be16(pvt->chan_in_num);
hdr->type = type;
hdr->class = class;
hdr->function = cpu_to_le16(function);
hdr->reserved = 0;
for (i = 0; i < num_parameters; ++i)
hdr->params[i] = cpu_to_le16(parameters[i]);
cmd->flags = WAIT_FOR_RESPONSE; cmd->flags = WAIT_FOR_RESPONSE;
cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters); cmd->data_len = sizeof(struct csm_encaps_hdr) -
sizeof(struct csm_encaps_cmd);
cmd->cpvt = pvt; cmd->cpvt = pvt;
cmd->next_index = 0;
}
static void
append_channel_cmd(struct tcb *cmd, u8 type, u8 class, u16 function,
const u16 *parameters, int num_parameters)
{
int i;
struct csm_encaps_cmd *csm_cmd = cmd->data + cmd->data_len;
csm_cmd->length = LENGTH_WITH_N_PARAMETERS(num_parameters);
csm_cmd->index = cmd->next_index++;
csm_cmd->type = type;
csm_cmd->class = class;
csm_cmd->function = cpu_to_le16(function);
csm_cmd->reserved = 0;
for (i = 0; i < num_parameters; ++i)
csm_cmd->params[i] = cpu_to_le16(parameters[i]);
cmd->data_len += csm_cmd->length;
/* Pad it out to a DW boundary */
if (cmd->data_len % 4)
cmd->data_len += 4 - (cmd->data_len % 4);
WARN_ON(cmd->data_len >= SFRAME_SIZE);
}
static void
create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class,
u16 function, const u16 *parameters, int num_parameters)
{
setup_channel_header(pvt, cmd);
append_channel_cmd(cmd, type, class, function, parameters,
num_parameters);
} }
static int static int
@ -1143,19 +1163,19 @@ send_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot,
if (res) if (res)
return res; return res;
if (0x0000 != response_header(cmd)->params[0]) { if (0x0000 != response_header(cmd)->cmd.params[0]) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
dev_warn(&wc->pdev->dev, dev_warn(&wc->pdev->dev,
"Failed to create channel in timeslot " \ "Failed to create channel in timeslot " \
"%d. Response from DTE was (%04x).\n", "%d. Response from DTE was (%04x).\n",
timeslot, response_header(cmd)->params[0]); timeslot, response_header(cmd)->cmd.params[0]);
} }
free_cmd(cmd->response); free_cmd(cmd->response);
cmd->response = NULL; cmd->response = NULL;
return -EIO; return -EIO;
} }
*channel_number = le16_to_cpu(response_header(cmd)->params[1]); *channel_number = le16_to_cpu(response_header(cmd)->cmd.params[1]);
free_cmd(cmd->response); free_cmd(cmd->response);
cmd->response = NULL; cmd->response = NULL;
return 0; return 0;
@ -1276,6 +1296,16 @@ send_spu_features_control_cmd(struct wcdte *wc, struct tcb *cmd, u16 options)
return wctc4xxp_transmit_cmd_and_wait(wc, cmd); return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
} }
/* Allows sending more than one CSM_ENCAPS packet in a single ethernet frame. */
static int send_csme_multi_cmd(struct wcdte *wc, struct tcb *cmd)
{
const u16 parameters[] = {0x1};
create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
CONFIG_DEVICE_CLASS, 0x010a, parameters,
ARRAY_SIZE(parameters));
return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
}
static int static int
send_tdm_opt_cmd(struct wcdte *wc, struct tcb *cmd) send_tdm_opt_cmd(struct wcdte *wc, struct tcb *cmd)
{ {
@ -1299,7 +1329,7 @@ send_destroy_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 channel)
if (res) if (res)
return res; return res;
/* Let's check the response for any error codes.... */ /* Let's check the response for any error codes.... */
result = le16_to_cpu(response_header(cmd)->params[0]); result = le16_to_cpu(response_header(cmd)->cmd.params[0]);
if (0x0000 != result) { if (0x0000 != result) {
dev_err(&wc->pdev->dev, dev_err(&wc->pdev->dev,
"Failed to destroy channel %04d (%04x)\n", "Failed to destroy channel %04d (%04x)\n",
@ -1309,102 +1339,59 @@ send_destroy_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 channel)
return 0; return 0;
} }
static int static void
send_set_ip_hdr_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd) append_set_ip_hdr_channel_cmd(struct tcb *cmd)
{ {
int res;
u16 result;
struct wcdte *wc = pvt->wc;
const u16 parameters[] = {0, 0x0045, 0, 0, 0x0040, 0x1180, 0, const u16 parameters[] = {0, 0x0045, 0, 0, 0x0040, 0x1180, 0,
0xa8c0, 0x0309, 0xa8c0, 0x0309, 0xa8c0, 0x0309, 0xa8c0, 0x0309,
swab16(pvt->timeslot_out_num + 0x5000), swab16(cmd->cpvt->timeslot_out_num + 0x5000),
swab16(pvt->timeslot_in_num + 0x5000), swab16(cmd->cpvt->timeslot_in_num + 0x5000),
0, 0}; 0, 0};
create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, append_channel_cmd(cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
0x9000, parameters, ARRAY_SIZE(parameters)); 0x9000, parameters, ARRAY_SIZE(parameters));
res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
if (res)
return res;
/* Let's check the response for any error codes.... */
result = le16_to_cpu(response_header(cmd)->params[0]);
if (0x0000 != result) {
dev_err(&wc->pdev->dev, "Failure in %s (%04x)\n",
__func__, result);
return -EIO;
}
return 0;
} }
static int static void
send_voip_vceopt_cmd(struct channel_pvt *pvt, struct tcb *cmd, u16 length) append_voip_vceopt_cmd(struct tcb *cmd, u16 length)
{ {
int res; const u16 parameters[] = {((length << 8)|0x21), 0x1c00,
u16 result; 0x0004, 0, 0};
const u16 parameters[] = {((length << 8)|0x21), 0x1c00, 0x0004, 0, 0}; append_channel_cmd(cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
struct wcdte *wc = pvt->wc;
create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
0x8001, parameters, ARRAY_SIZE(parameters)); 0x8001, parameters, ARRAY_SIZE(parameters));
res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
if (res)
return res;
/* Let's check the response for any error codes.... */
result = le16_to_cpu(response_header(cmd)->params[0]);
if (0x0000 != result) {
dev_err(&wc->pdev->dev, "Failure in %s (%04x)\n",
__func__, result);
return -EIO;
}
return 0;
} }
static int static void
send_voip_tonectl_cmd(struct channel_pvt *pvt, struct tcb *cmd) append_voip_tonectl_cmd(struct tcb *cmd)
{ {
int res;
u16 result;
const u16 parameters[] = {0}; const u16 parameters[] = {0};
struct wcdte *wc = pvt->wc; append_channel_cmd(cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
0x805b, parameters, ARRAY_SIZE(parameters)); 0x805b, parameters, ARRAY_SIZE(parameters));
res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
if (res)
return res;
/* Let's check the response for any error codes.... */
result = le16_to_cpu(response_header(cmd)->params[0]);
if (0x0000 != result) {
dev_err(&wc->pdev->dev, "Failure in %s (%04x)\n",
__func__, result);
return -EIO;
}
return 0;
} }
static int static void
send_voip_dtmfopt_cmd(struct channel_pvt *pvt, struct tcb *cmd) append_voip_dtmfopt_cmd(struct tcb *cmd)
{ {
const u16 parameters[] = {0x0008}; const u16 parameters[] = {0x0008};
create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, append_channel_cmd(cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
0x8002, parameters, ARRAY_SIZE(parameters)); 0x8002, parameters, ARRAY_SIZE(parameters));
return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
} }
static int static void
send_voip_indctrl_cmd(struct channel_pvt *pvt, struct tcb *cmd) append_voip_indctrl_cmd(struct tcb *cmd)
{ {
const u16 parameters[] = {0x0007}; const u16 parameters[] = {0x0007};
create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, append_channel_cmd(cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
0x8084, parameters, ARRAY_SIZE(parameters)); 0x8084, parameters, ARRAY_SIZE(parameters));
return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
} }
static int static void
send_voip_vopena_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 format) send_voip_vopena_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 format)
{ {
const u16 parameters[] = {1, ((format<<8)|0x80), 0, 0, 0, const u16 parameters[] = {1, ((format<<8)|0x80), 0, 0, 0,
0x3412, 0x7856}; 0x3412, 0x7856};
create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS,
0x8000, parameters, ARRAY_SIZE(parameters)); 0x8000, parameters, ARRAY_SIZE(parameters));
return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); wctc4xxp_transmit_cmd(pvt->wc, cmd);
} }
static int static int
@ -1418,7 +1405,7 @@ send_voip_vopena_close_cmd(struct channel_pvt *pvt, struct tcb *cmd)
if (res) if (res)
return res; return res;
/* Let's check the response for any error codes.... */ /* Let's check the response for any error codes.... */
if (0x0000 != response_header(cmd)->params[0]) { if (0x0000 != response_header(cmd)->cmd.params[0]) {
WARN_ON(1); WARN_ON(1);
return -EIO; return -EIO;
} }
@ -1451,7 +1438,7 @@ _send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, u16 enable, u16
return res; return res;
/* Let's check the response for any error codes.... */ /* Let's check the response for any error codes.... */
if (0x0000 != response_header(cmd)->params[0]) { if (0x0000 != response_header(cmd)->cmd.params[0]) {
WARN_ON(1); WARN_ON(1);
return -EIO; return -EIO;
} }
@ -1500,10 +1487,10 @@ send_eth_statistics_cmd(struct wcdte *wc, struct tcb *cmd)
res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
if (res) if (res)
return -EIO; return -EIO;
if (0x0000 != response_header(cmd)->params[0]) { if (0x0000 != response_header(cmd)->cmd.params[0]) {
dev_info(&wc->pdev->dev, dev_info(&wc->pdev->dev,
"Failed to get ethernet stats: 0x%04x\n", "Failed to get ethernet stats: 0x%04x\n",
response_header(cmd)->params[0]); response_header(cmd)->cmd.params[0]);
res = -EIO; res = -EIO;
} }
return res; return res;
@ -1517,7 +1504,7 @@ static void wctc4xxp_match_packet_counts(struct wcdte *wc)
res = send_eth_statistics_cmd(wc, cmd); res = send_eth_statistics_cmd(wc, cmd);
if (0 == res) { if (0 == res) {
parms = (u32 *)(&response_header(cmd)->params[0]); parms = (u32 *)(&response_header(cmd)->cmd.params[0]);
wctc4xxp_set_packet_count(wc->rxd, parms[1]); wctc4xxp_set_packet_count(wc->rxd, parms[1]);
wctc4xxp_set_packet_count(wc->txd, parms[2]); wctc4xxp_set_packet_count(wc->txd, parms[2]);
} }
@ -2319,7 +2306,7 @@ wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel, __le16 function)
hdr->seq_num = seqno; hdr->seq_num = seqno;
hdr->control = 0xe0; hdr->control = 0xe0;
hdr->channel = channel; hdr->channel = channel;
hdr->function = function; hdr->cmd.function = function;
wctc4xxp_transmit_cmd(wc, cmd); wctc4xxp_transmit_cmd(wc, cmd);
} }
@ -2347,7 +2334,7 @@ static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
list_for_each_entry_safe(pos, temp, list_for_each_entry_safe(pos, temp,
&wc->waiting_for_response_list, node) { &wc->waiting_for_response_list, node) {
listhdr = pos->data; listhdr = pos->data;
if ((listhdr->function == rxhdr->function) && if ((listhdr->cmd.function == rxhdr->cmd.function) &&
(listhdr->channel == rxhdr->channel)) { (listhdr->channel == rxhdr->channel)) {
/* If this is a channel command, do not complete it if /* If this is a channel command, do not complete it if
@ -2428,10 +2415,10 @@ do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
static inline int static inline int
is_response(const struct csm_encaps_hdr *hdr) is_response(const struct csm_encaps_hdr *hdr)
{ {
return ((0x02 == hdr->type) || return ((0x02 == hdr->cmd.type) ||
(0x04 == hdr->type) || (0x04 == hdr->cmd.type) ||
(0x0e == hdr->type) || (0x0e == hdr->cmd.type) ||
(0x00 == hdr->type)) ? 1 : 0; (0x00 == hdr->cmd.type)) ? 1 : 0;
} }
static void static void
@ -2441,7 +2428,7 @@ print_command(struct wcdte *wc, const struct tcb *cmd)
const struct csm_encaps_hdr *hdr = cmd->data; const struct csm_encaps_hdr *hdr = cmd->data;
char *buffer; char *buffer;
const int BUFFER_SIZE = 1024; const int BUFFER_SIZE = 1024;
int parameters = ((hdr->length - 8)/sizeof(__le16)); int parameters = ((hdr->cmd.length - 8)/sizeof(__le16));
buffer = kzalloc(BUFFER_SIZE + 1, GFP_ATOMIC); buffer = kzalloc(BUFFER_SIZE + 1, GFP_ATOMIC);
if (!buffer) { if (!buffer) {
@ -2455,12 +2442,12 @@ print_command(struct wcdte *wc, const struct tcb *cmd)
curlength += snprintf(buffer + curlength, BUFFER_SIZE - curlength, curlength += snprintf(buffer + curlength, BUFFER_SIZE - curlength,
"length: %02x index: %02x type: %02x " "length: %02x index: %02x type: %02x "
"class: %02x function: %04x", "class: %02x function: %04x",
hdr->length, hdr->index, hdr->type, hdr->class, hdr->cmd.length, hdr->cmd.index, hdr->cmd.type, hdr->cmd.class,
le16_to_cpu(hdr->function)); le16_to_cpu(hdr->cmd.function));
for (i = 0; i < parameters; ++i) { for (i = 0; i < parameters; ++i) {
curlength += snprintf(buffer + curlength, curlength += snprintf(buffer + curlength,
BUFFER_SIZE - curlength, " %04x", BUFFER_SIZE - curlength, " %04x",
le16_to_cpu(hdr->params[i])); le16_to_cpu(hdr->cmd.params[i]));
} }
dev_info(&wc->pdev->dev, "%s\n", buffer); dev_info(&wc->pdev->dev, "%s\n", buffer);
kfree(buffer); kfree(buffer);
@ -2475,49 +2462,50 @@ static void
receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd) receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
{ {
const struct csm_encaps_hdr *hdr = cmd->data; const struct csm_encaps_hdr *hdr = cmd->data;
const struct csm_encaps_cmd *c = &hdr->cmd;
if (!(hdr->control & MESSAGE_PACKET)) { if (!(hdr->control & MESSAGE_PACKET)) {
const bool suppress_ack = ((hdr->control & SUPPRESS_ACK) > 0); const bool suppress_ack = ((hdr->control & SUPPRESS_ACK) > 0);
if (!suppress_ack) { if (!suppress_ack) {
wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel, wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel,
hdr->function); c->function);
} }
if (is_response(hdr)) { if (is_response(hdr)) {
do_rx_response_packet(wc, cmd); do_rx_response_packet(wc, cmd);
} else if (0xc1 == hdr->type) { } else if (0xc1 == c->type) {
if (0x75 == hdr->class) { if (0x75 == c->class) {
dev_warn(&wc->pdev->dev, dev_warn(&wc->pdev->dev,
"Received alert (0x%04x) from dsp\n", "Received alert (0x%04x) from dsp\n",
le16_to_cpu(hdr->params[0])); le16_to_cpu(c->params[0]));
} }
free_cmd(cmd); free_cmd(cmd);
} else if (0xd4 == hdr->type) { } else if (0xd4 == c->type) {
if (hdr->params[0] != le16_to_cpu(0xffff)) { if (c->params[0] != le16_to_cpu(0xffff)) {
dev_warn(&wc->pdev->dev, dev_warn(&wc->pdev->dev,
"DTE Failed self test (%04x).\n", "DTE Failed self test (%04x).\n",
le16_to_cpu(hdr->params[0])); le16_to_cpu(c->params[0]));
} else if ((hdr->params[1] != le16_to_cpu(0x000c)) && } else if ((c->params[1] != le16_to_cpu(0x000c)) &&
(hdr->params[1] != le16_to_cpu(0x010c))) { (c->params[1] != le16_to_cpu(0x010c))) {
dev_warn(&wc->pdev->dev, dev_warn(&wc->pdev->dev,
"Unexpected ERAM status (%04x).\n", "Unexpected ERAM status (%04x).\n",
le16_to_cpu(hdr->params[1])); le16_to_cpu(c->params[1]));
} else { } else {
wctc4xxp_set_ready(wc); wctc4xxp_set_ready(wc);
wake_up(&wc->waitq); wake_up(&wc->waitq);
} }
free_cmd(cmd); free_cmd(cmd);
} else if (MONITOR_LIVE_INDICATION_TYPE == hdr->type) { } else if (MONITOR_LIVE_INDICATION_TYPE == c->type) {
if (hdr->function == 0x0000) { if (c->function == 0x0000) {
u16 alert_type = le16_to_cpu(hdr->params[0]); u16 alert_type = le16_to_cpu(c->params[0]);
dev_err(&wc->pdev->dev, dev_err(&wc->pdev->dev,
"Received alert (0x%04x) from dsp. Please reload driver.\n", "Received alert (0x%04x) from dsp. Please reload driver.\n",
alert_type); alert_type);
wctc4xxp_reset_processor(wc); wctc4xxp_reset_processor(wc);
set_bit(DTE_SHUTDOWN, &wc->flags); set_bit(DTE_SHUTDOWN, &wc->flags);
@ -2530,7 +2518,8 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
free_cmd(cmd); free_cmd(cmd);
} else { } else {
dev_warn(&wc->pdev->dev, dev_warn(&wc->pdev->dev,
"Unknown command type received. %02x\n", hdr->type); "Unknown command type received. %02x\n",
c->type);
free_cmd(cmd); free_cmd(cmd);
} }
} else { } else {
@ -3096,20 +3085,104 @@ wctc4xxp_boot_processor(struct wcdte *wc, const struct firmware *firmware)
return 0; return 0;
} }
static int static void
setup_half_channel(struct channel_pvt *pvt, struct tcb *cmd, u16 length) setup_half_channel(struct channel_pvt *pvt, struct tcb *cmd, u16 length)
{ {
if (send_set_ip_hdr_channel_cmd(pvt, cmd)) setup_channel_header(pvt, cmd);
return -EIO;
if (send_voip_vceopt_cmd(pvt, cmd, length)) append_set_ip_hdr_channel_cmd(cmd);
return -EIO; append_voip_vceopt_cmd(cmd, length);
if (send_voip_tonectl_cmd(pvt, cmd)) append_voip_tonectl_cmd(cmd);
return -EIO; append_voip_dtmfopt_cmd(cmd);
if (send_voip_dtmfopt_cmd(pvt, cmd)) append_voip_indctrl_cmd(cmd);
return -EIO;
if (send_voip_indctrl_cmd(pvt, cmd)) /* To indicate the end of multiple messages. */
return -EIO; cmd->data_len += 4;
return 0; WARN_ON(cmd->data_len >= SFRAME_SIZE);
wctc4xxp_transmit_cmd(pvt->wc, cmd);
}
static int wctc4xxp_setup_channels(struct wcdte *wc,
struct channel_pvt *encoder_pvt,
struct channel_pvt *decoder_pvt,
u16 length)
{
int res = 0;
struct tcb *encoder_cmd;
struct tcb *decoder_cmd;
DECLARE_COMPLETION_ONSTACK(encoder_done);
DECLARE_COMPLETION_ONSTACK(decoder_done);
encoder_cmd = alloc_cmd(SFRAME_SIZE);
decoder_cmd = alloc_cmd(SFRAME_SIZE);
if (!encoder_cmd || !decoder_cmd) {
res = -ENOMEM;
goto error_exit;
}
encoder_cmd->complete = &encoder_done;
decoder_cmd->complete = &decoder_done;
setup_half_channel(encoder_pvt, encoder_cmd, length);
setup_half_channel(decoder_pvt, decoder_cmd, length);
wait_for_completion(&decoder_done);
wait_for_completion(&encoder_done);
if (encoder_cmd->flags & DTE_CMD_TIMEOUT ||
decoder_cmd->flags & DTE_CMD_TIMEOUT) {
DTE_DEBUG(DTE_DEBUG_GENERAL, "Timeout waiting for command.\n");
res = -EIO;
}
if ((0x0000 != response_header(encoder_cmd)->cmd.params[0]) ||
(0x0000 != response_header(encoder_cmd)->cmd.params[0]))
res = -EIO;
error_exit:
free_cmd(encoder_cmd);
free_cmd(decoder_cmd);
return res;
}
static int wctc4xxp_enable_channels(struct wcdte *wc,
struct channel_pvt *encoder_pvt,
struct channel_pvt *decoder_pvt,
u8 complicated, u8 simple)
{
int res = 0;
struct tcb *encoder_cmd;
struct tcb *decoder_cmd;
DECLARE_COMPLETION_ONSTACK(encoder_done);
DECLARE_COMPLETION_ONSTACK(decoder_done);
encoder_cmd = alloc_cmd(SFRAME_SIZE);
decoder_cmd = alloc_cmd(SFRAME_SIZE);
if (!encoder_cmd || !decoder_cmd) {
res = -ENOMEM;
goto error_exit;
}
encoder_cmd->complete = &encoder_done;
decoder_cmd->complete = &decoder_done;
send_voip_vopena_cmd(encoder_pvt, encoder_cmd, complicated);
send_voip_vopena_cmd(decoder_pvt, decoder_cmd, simple);
wait_for_completion(&decoder_done);
wait_for_completion(&encoder_done);
if ((0x0000 != response_header(encoder_cmd)->cmd.params[0]) ||
(0x0000 != response_header(decoder_cmd)->cmd.params[0]))
res = -EIO;
error_exit:
free_cmd(encoder_cmd);
free_cmd(decoder_cmd);
return res;
} }
static int static int
@ -3119,8 +3192,8 @@ wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
struct channel_pvt *encoder_pvt, *decoder_pvt; struct channel_pvt *encoder_pvt, *decoder_pvt;
u16 encoder_timeslot, decoder_timeslot; u16 encoder_timeslot, decoder_timeslot;
u16 encoder_channel, decoder_channel; u16 encoder_channel, decoder_channel;
u16 length;
struct tcb *cmd; struct tcb *cmd;
u16 length;
cmd = alloc_cmd(SFRAME_SIZE); cmd = alloc_cmd(SFRAME_SIZE);
if (!cmd) if (!cmd)
@ -3139,6 +3212,10 @@ wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
complicated = temp; complicated = temp;
} }
length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH :
(DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0;
BUG_ON(encoder_timeslot/2 >= wc->numchannels); BUG_ON(encoder_timeslot/2 >= wc->numchannels);
BUG_ON(decoder_timeslot/2 >= wc->numchannels); BUG_ON(decoder_timeslot/2 >= wc->numchannels);
encoder_pvt = wc->uencode->channels[encoder_timeslot/2].pvt; encoder_pvt = wc->uencode->channels[encoder_timeslot/2].pvt;
@ -3163,28 +3240,23 @@ wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
"DTE is using the following channels encoder_channel: " \ "DTE is using the following channels encoder_channel: " \
"%d decoder_channel: %d\n", encoder_channel, decoder_channel); "%d decoder_channel: %d\n", encoder_channel, decoder_channel);
length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH :
(DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0;
WARN_ON(encoder_channel == decoder_channel); WARN_ON(encoder_channel == decoder_channel);
/* Now set all the default parameters for the encoder. */ /* Now set all the default parameters for the encoder. */
encoder_pvt->chan_in_num = encoder_channel; encoder_pvt->chan_in_num = encoder_channel;
encoder_pvt->chan_out_num = decoder_channel; encoder_pvt->chan_out_num = decoder_channel;
if (setup_half_channel(encoder_pvt, cmd, length))
goto error_exit;
/* And likewise for the decoder. */
decoder_pvt->chan_in_num = decoder_channel; decoder_pvt->chan_in_num = decoder_channel;
decoder_pvt->chan_out_num = encoder_channel; decoder_pvt->chan_out_num = encoder_channel;
if (setup_half_channel(decoder_pvt, cmd, length))
if (wctc4xxp_setup_channels(wc, encoder_pvt, decoder_pvt, length))
goto error_exit; goto error_exit;
if (send_trans_connect_cmd(wc, cmd, encoder_channel, if (send_trans_connect_cmd(wc, cmd, encoder_channel,
decoder_channel, complicated, simple)) decoder_channel, complicated, simple))
goto error_exit; goto error_exit;
if (send_voip_vopena_cmd(encoder_pvt, cmd, complicated))
goto error_exit; if (wctc4xxp_enable_channels(wc, encoder_pvt, decoder_pvt,
if (send_voip_vopena_cmd(decoder_pvt, cmd, simple)) complicated, simple))
goto error_exit; goto error_exit;
DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
@ -3252,7 +3324,7 @@ static void print_vceinfo_packet(struct wcdte *wc, struct tcb *cmd)
{ "Discarded Packets Due to Insufficient Memory ", true} { "Discarded Packets Due to Insufficient Memory ", true}
}; };
u32 *parms = (u32 *)(&response_header(cmd)->params[0]); u32 *parms = (u32 *)(&response_header(cmd)->cmd.params[0]);
for (i = 0; i < 43; ++i) { for (i = 0; i < 43; ++i) {
if (PARAMETERS[i].show) if (PARAMETERS[i].show)
dev_info(dev, "%s%d\n", PARAMETERS[i].name, parms[i]); dev_info(dev, "%s%d\n", PARAMETERS[i].name, parms[i]);
@ -3279,7 +3351,7 @@ static void print_eth_statistics_packet(struct wcdte *wc, struct tcb *cmd)
{ "Received VLAN frames with E-RIF ", true} { "Received VLAN frames with E-RIF ", true}
}; };
u32 *parms = (u32 *)(&response_header(cmd)->params[0]); u32 *parms = (u32 *)(&response_header(cmd)->cmd.params[0]);
for (i = 0; i < sizeof(PARAMETERS)/sizeof(PARAMETERS[0]); ++i) { for (i = 0; i < sizeof(PARAMETERS)/sizeof(PARAMETERS[0]); ++i) {
if (PARAMETERS[i].show) if (PARAMETERS[i].show)
dev_info(dev, "%s%d\n", PARAMETERS[i].name, parms[i]); dev_info(dev, "%s%d\n", PARAMETERS[i].name, parms[i]);
@ -3370,8 +3442,7 @@ error_exit:
} }
static int static int wctc4xxp_setup_device(struct wcdte *wc)
wctc4xxp_setup_channels(struct wcdte *wc)
{ {
struct tcb *cmd; struct tcb *cmd;
int tdm_bus; int tdm_bus;
@ -3418,6 +3489,9 @@ wctc4xxp_setup_channels(struct wcdte *wc)
if (send_spu_features_control_cmd(wc, cmd, 0x04)) if (send_spu_features_control_cmd(wc, cmd, 0x04))
goto error_exit; goto error_exit;
if (send_csme_multi_cmd(wc, cmd))
goto error_exit;
if (send_tdm_opt_cmd(wc, cmd)) if (send_tdm_opt_cmd(wc, cmd))
goto error_exit; goto error_exit;
@ -3825,7 +3899,7 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#if defined(CONFIG_WCTC4XXP_POLLING) #if defined(CONFIG_WCTC4XXP_POLLING)
wctc4xxp_enable_polling(wc); wctc4xxp_enable_polling(wc);
#endif #endif
res = wctc4xxp_setup_channels(wc); res = wctc4xxp_setup_device(wc);
if (res) if (res)
goto error_exit_hwinit; goto error_exit_hwinit;