From 275a39b01ad9f8ccf9d31cf5bd78dc4bc82c5659 Mon Sep 17 00:00:00 2001 From: sruffell Date: Tue, 24 Mar 2009 19:59:43 +0000 Subject: Backporting changes to the transcoder from dahdi. - Fix bug where asterisk could not find a loaded transcoder. - Do not allow bad packets to corrupt memory. - Eliminate race condition that could cause asterisk to hang. - General cleanup and whitespace changes. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4633 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/wctc4xxp/base.c | 2861 +++++++++++++++++++++++++++--------------------- kernel/zaptel.h | 3 +- kernel/zttranscode.c | 37 +- 3 files changed, 1647 insertions(+), 1254 deletions(-) diff --git a/kernel/wctc4xxp/base.c b/kernel/wctc4xxp/base.c index 55be5b7..ba810ff 100644 --- a/kernel/wctc4xxp/base.c +++ b/kernel/wctc4xxp/base.c @@ -1,7 +1,7 @@ /* * Wildcard TC400B Driver * - * Copyright (C) 2006-2008, Digium, Inc. + * Copyright (C) 2006-2009, Digium, Inc. * * All rights reserved. * @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,7 +48,7 @@ #define WORKQUEUE 1 #define TASKLET 2 -#ifndef DEFERRED_PROCESSING +#ifndef DEFERRED_PROCESSING # define DEFERRED_PROCESSING WORKQUEUE #endif @@ -63,16 +63,16 @@ #define WARN_ALWAYS() WARN_ON(1) #define DTE_PRINTK(_lvl, _fmt, _args...) \ - printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \ - (wc)->board_name, ## _args) + printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \ + (wc)->board_name, ## _args) -#define DTE_DEBUG(_dbgmask, _fmt, _args...) \ - if ((debug & _dbgmask) == (_dbgmask)) { \ - printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name, \ - (wc)->board_name, ## _args); \ - } \ +#define DTE_DEBUG(_dbgmask, _fmt, _args...) \ + if ((debug & _dbgmask) == (_dbgmask)) { \ + printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name, \ + (wc)->board_name, ## _args); \ + } \ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) #ifndef WARN_ON_ONCE #define WARN_ON_ONCE(__condition) do { \ static int __once = 1; \ @@ -82,12 +82,16 @@ WARN_ON(0); \ } \ } \ -} while(0) +} while (0) #endif #endif +/* The total number of active channels over which the driver will start polling + * the card every 10 ms. */ +#define POLLING_CALL_THRESHOLD 40 + #define INVALID 999 /* Used to mark invalid channels, commands, etc.. */ -#define MAX_CHANNEL_PACKETS 5 /* Never let more than 5 outstanding packets exist for any channel. */ +#define MAX_CHANNEL_PACKETS 5 #define G729_LENGTH 20 #define G723_LENGTH 30 @@ -103,16 +107,16 @@ #define MAX_CAPTURED_PACKETS 5000 /* The following bit fields are used to set the various debug levels. */ -#define DTE_DEBUG_GENERAL (1 << 0) /* 1 */ -#define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */ -#define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */ -#define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */ -#define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */ -#define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */ -#define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */ +#define DTE_DEBUG_GENERAL (1 << 0) /* 1 */ +#define DTE_DEBUG_CHANNEL_SETUP (1 << 1) /* 2 */ +#define DTE_DEBUG_RTP_TX (1 << 2) /* 4 */ +#define DTE_DEBUG_RTP_RX (1 << 3) /* 8 */ +#define DTE_DEBUG_RX_TIMEOUT (1 << 4) /* 16 */ +#define DTE_DEBUG_NETWORK_IF (1 << 5) /* 32 */ +#define DTE_DEBUG_NETWORK_EARLY (1 << 6) /* 64 */ -int debug; -char *mode; +static int debug; +static char *mode; static spinlock_t wctc4xxp_list_lock; static struct list_head wctc4xxp_list; @@ -148,7 +152,7 @@ struct rtp_packet { struct udphdr udphdr; struct rtphdr rtphdr; __u8 payload[0]; -}__attribute__((packed)); +} __attribute__((packed)); /* Ethernet packet type for communication control information to the DTE. */ struct csm_encaps_hdr { @@ -168,165 +172,35 @@ struct csm_encaps_hdr { __le16 params[0]; } __attribute__((packed)); -struct csm_create_channel_cmd { - struct csm_encaps_hdr hdr; - __le16 channel_type; - __le16 timeslot; -} __attribute__((packed)); - -#define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30 -#define CMD_MSG_TDM_SELECT_BUS_MODE(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x01, 0x00,0x06,0x17,0x04, 0xFF,0xFF, \ - 0x04,0x00 } -#define CMD_MSG_TDM_ENABLE_BUS_LEN 30 -#define CMD_MSG_TDM_ENABLE_BUS(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x02, 0x00,0x06,0x05,0x04, 0xFF,0xFF, \ - 0x04,0x00 } -#define CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN 34 -#define CMD_MSG_SUPVSR_SETUP_TDM_PARMS(s,p1,p2,p3) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x10, p1, 0x00,0x06,0x07,0x04, 0xFF,0xFF, \ - p2,0x83, 0x00,0x0C, 0x00,0x00, p3,0x00 } -#define CMD_MSG_TDM_OPT_LEN 30 -#define CMD_MSG_TDM_OPT(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x35,0x04, 0xFF,0xFF, \ - 0x00,0x00 } -#define CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN 30 -#define CMD_MSG_DEVICE_SET_COUNTRY_CODE(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x1B,0x04, 0xFF,0xFF, \ - 0x00,0x00 } - -/* CPU Commands */ -#define CMD_MSG_SET_ARM_CLK_LEN 32 -#define CMD_MSG_SET_ARM_CLK(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x11,0x04, 0x00,0x00, \ - 0x2C,0x01, 0x00,0x00 } -#define CMD_MSG_SET_SPU_CLK_LEN 32 -#define CMD_MSG_SET_SPU_CLK(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x12,0x04, 0x00,0x00, \ - 0x2C,0x01, 0x00,0x00 } -#define CMD_MSG_SPU_FEATURES_CONTROL_LEN 30 -#define CMD_MSG_SPU_FEATURES_CONTROL(s,p1) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x13,0x00, 0xFF,0xFF, \ - p1,0x00 } -#define CMD_MSG_DEVICE_STATUS_CONFIG_LEN 30 -#define CMD_MSG_DEVICE_STATUS_CONFIG(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x0F,0x04, 0xFF,0xFF, \ - 0x05,0x00 } - -/* General IP/RTP Commands */ -#define CMD_MSG_SET_ETH_HEADER_LEN 44 -#define CMD_MSG_SET_ETH_HEADER(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x18, 0x00, 0x00,0x06,0x00,0x01, 0xFF,0xFF, \ - 0x01,0x00, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x00,0x11,0x22,0x33,0x44,0x55, 0x08,0x00 } -#define CMD_MSG_IP_SERVICE_CONFIG_LEN 30 -#define CMD_MSG_IP_SERVICE_CONFIG(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x02,0x03, 0xFF,0xFF, \ - 0x00,0x02 } -#define CMD_MSG_ARP_SERVICE_CONFIG_LEN 30 -#define CMD_MSG_ARP_SERVICE_CONFIG(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x05,0x01, 0xFF,0xFF, \ - 0x01,0x00 } -#define CMD_MSG_ICMP_SERVICE_CONFIG_LEN 30 -#define CMD_MSG_ICMP_SERVICE_CONFIG(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x04,0x03, 0xFF,0xFF, \ - 0x01,0xFF } -#define CMD_MSG_IP_OPTIONS_LEN 30 -#define CMD_MSG_IP_OPTIONS(s) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \ - 0x02,0x00 } - #define CONTROL_PACKET_OPCODE 0x0001 /* Control bits */ -#define LITTLE_ENDIAN 0x01 -#define SUPPRESS_ACK 0x40 -#define MESSAGE_PACKET 0x80 +#define LITTLE_ENDIAN 0x01 +#define SUPPRESS_ACK 0x40 +#define MESSAGE_PACKET 0x80 #define SUPERVISOR_CHANNEL 0xffff /* Supervisor function codes */ -#define SUPVSR_CREATE_CHANNEL 0x0010 +#define SUPVSR_CREATE_CHANNEL 0x0010 #define MONITOR_LIVE_INDICATION_TYPE 0x75 -#define CONFIG_CHANGE_TYPE 0x00 -#define CONFIG_DEVICE_CLASS 0x06 - -#define CMD_MSG_QUERY_CHANNEL_LEN 30 -#define CMD_MSG_QUERY_CHANNEL(s,t) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x01,0x06,0x10,0x00, 0x00,0x00, \ - (t&0x00FF), ((t&0xFF00) >> 8) } - -#define CMD_MSG_TRANS_CONNECT_LEN 38 -#define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x12, 0x00, 0x00,0x06,0x22,0x93, 0x00,0x00, \ - e,0x00, (c1&0x00FF),((c1&0xFF00)>>8), f1,0x00, (c2&0x00FF),((c2&0xFF00)>>8), f2,0x00 } -#define CMD_MSG_DESTROY_CHANNEL_LEN 32 -#define CMD_MSG_DESTROY_CHANNEL(s,t) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x11,0x00, 0x00,0x00, \ - (t&0x00FF),((t&0xFF00)>>8), 0x00, 0x00 } +#define CONFIG_CHANGE_TYPE 0x00 +#define CONFIG_CHANNEL_CLASS 0x02 +#define CONFIG_DEVICE_CLASS 0x06 /* Individual channel config commands */ -#define CMD_MSG_SET_IP_HDR_CHANNEL_LEN 58 -#define CMD_MSG_SET_IP_HDR_CHANNEL(s,c,t2,t1) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00) >> 8),(c&0x00FF), 0x26, 0x00, 0x00,0x02,0x00,0x90, 0x00,0x00, \ - 0x00,0x00, 0x45,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x80,0x11, 0x00,0x00, \ - 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, \ - ((t2&0xFF00)>>8)+0x50,(t2&0x00FF), ((t1&0xFF00)>>8)+0x50,(t1&0x00FF), 0x00,0x00, 0x00,0x00 } -#define CMD_MSG_VOIP_VCEOPT_LEN 40 -#define CMD_MSG_VOIP_VCEOPT(s,c,l,w) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x12, 0x00, 0x00,0x02,0x01,0x80, 0x00,0x00, \ - 0x21,l, 0x00,0x1C, 0x04,0x00, 0x00,0x00, w,0x00, 0x80,0x11 } -#define CMD_MSG_VOIP_VOPENA_LEN 44 -#define CMD_MSG_VOIP_VOPENA(s,c,f) { \ - 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ - 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x16, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, \ - 0x01,0x00, 0x80,f, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x12,0x34, 0x56,0x78, 0x00,0x00 } -#define CMD_MSG_VOIP_VOPENA_CLOSE_LEN 32 -#define CMD_MSG_VOIP_VOPENA_CLOSE(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,0x00,0x80, 0x00,0x00, \ - 0x00,0x00, 0x00,0x00 } -#define CMD_MSG_VOIP_INDCTRL_LEN 32 -#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 } - #define MAX_FRAME_SIZE 1518 -#define SFRAME_SIZE MAX_FRAME_SIZE +#define SFRAME_SIZE MAX_FRAME_SIZE + +#define DRING_SIZE (1 << 7) /* Must be a power of two */ +#define DRING_MASK (DRING_SIZE-1) +#define MIN_PACKET_LEN 64 + +#undef USE_CUSTOM_MEMCACHE /* Transcoder buffer (tcb) */ struct tcb { - /* First field so that is aligned by default. */ - u8 cmd[SFRAME_SIZE]; + void *data; struct list_head node; unsigned long timeout; unsigned long retries; @@ -336,7 +210,7 @@ struct tcb { #define TX_COMPLETE (1 << 1) #define DO_NOT_CAPTURE (1 << 2) #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 WAIT_FOR_ACK (__WAIT_FOR_ACK | DO_NOT_AUTO_FREE) #define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE) @@ -344,123 +218,210 @@ struct tcb { struct tcb *response; struct completion complete; struct timer_list timer; - void *data; /* The number of bytes available in data. */ - int data_len; + int data_len; + spinlock_t lock; +#ifdef USE_CUSTOM_MEMCACHE + u32 sentinel; +#endif }; -static inline void *hdr_from_cmd(struct tcb *cmd) { - return cmd->data; +static inline const struct csm_encaps_hdr * +response_header(struct tcb *cmd) +{ + BUG_ON(!cmd->response); + return (const struct csm_encaps_hdr *)(cmd)->response->data; } -static inline void -initialize_cmd(struct tcb *cmd, unsigned long cmd_flags) +static inline void +initialize_cmd(struct tcb *cmd, unsigned long cmd_flags) { - memset(cmd, 0, sizeof(*cmd)); INIT_LIST_HEAD(&cmd->node); init_completion(&cmd->complete); cmd->flags = cmd_flags; - cmd->data = &cmd->cmd[0]; - cmd->data_len = SFRAME_SIZE; + spin_lock_init(&cmd->lock); +#ifdef USE_CUSTOM_MEMCACHE + cmd->sentinel = 0xdeadbeef; +#endif +} + +#ifdef USE_CUSTOM_MEMCACHE + +struct my_cache { + atomic_t outstanding_count; + spinlock_t lock; + struct list_head free; +}; + +static struct tcb *my_cache_alloc(struct my_cache *c, gfp_t alloc_flags) +{ + unsigned long flags; + struct tcb *cmd; + spin_lock_irqsave(&c->lock, flags); + if (!list_empty(&c->free)) { + cmd = list_entry(c->free.next, struct tcb, node); + list_del_init(&cmd->node); + spin_unlock_irqrestore(&c->lock, flags); + } else { + spin_unlock_irqrestore(&c->lock, flags); + cmd = kmalloc(sizeof(*cmd), alloc_flags); + } + atomic_inc(&c->outstanding_count); + return cmd; +} + +static void my_cache_free(struct my_cache *c, struct tcb *cmd) +{ + unsigned long flags; + spin_lock_irqsave(&c->lock, flags); + list_add_tail(&cmd->node, &c->free); + spin_unlock_irqrestore(&c->lock, flags); + atomic_dec(&c->outstanding_count); +} + +static struct my_cache *my_cache_create(void) +{ + struct my_cache *c; + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return NULL; + spin_lock_init(&c->lock); + INIT_LIST_HEAD(&c->free); + return c; +} + +static int my_cache_destroy(struct my_cache *c) +{ + struct tcb *cmd; + if (atomic_read(&c->outstanding_count)) { + DTE_DEBUG(DTE_DEBUG_GENERAL, "Leaked %d commands.\n", + atomic_read(&c->outstanding_count)); + } + while (!list_empty(&c->free)) { + cmd = list_entry(c->free.next, struct tcb, node); + list_del_init(&cmd->node); + kfree(cmd); + } + kfree(c); + return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static struct my_cache *cmd_cache; + +#else + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) /*! Used to allocate commands to submit to the dte. */ kmem_cache_t *cmd_cache; #else /*! Used to allocate commands to submit to the dte. */ -struct kmem_cache *cmd_cache; +static struct kmem_cache *cmd_cache; #endif +#endif /* USE_CUSTOM_MEMCACHE */ + static inline struct tcb * -__alloc_cmd(unsigned alloc_flags, unsigned long cmd_flags) +__alloc_cmd(size_t size, gfp_t alloc_flags, unsigned long cmd_flags) { struct tcb *cmd; + if (unlikely(size > SFRAME_SIZE)) + return NULL; + if (size < MIN_PACKET_LEN) + size = MIN_PACKET_LEN; +#ifdef USE_CUSTOM_MEMCACHE + cmd = my_cache_alloc(cmd_cache, alloc_flags); +#else cmd = kmem_cache_alloc(cmd_cache, alloc_flags); +#endif if (likely(cmd)) { + memset(cmd, 0, sizeof(*cmd)); + cmd->data = kzalloc(size, alloc_flags); + if (unlikely(!cmd->data)) { + kmem_cache_free(cmd_cache, cmd); + return NULL; + } + cmd->data_len = size; initialize_cmd(cmd, cmd_flags); } return cmd; } static struct tcb * -alloc_cmd(void) +alloc_cmd(size_t size) { - return __alloc_cmd(GFP_KERNEL, 0); + return __alloc_cmd(size, GFP_KERNEL, 0); } -static void +static void __free_cmd(struct tcb *cmd) { - if (cmd->data != &cmd->cmd[0]) { + if (cmd) kfree(cmd->data); - } +#ifdef USE_CUSTOM_MEMCACHE + my_cache_free(cmd_cache, cmd); +#else kmem_cache_free(cmd_cache, cmd); +#endif return; } -static void +static void free_cmd(struct tcb *cmd) { - if (cmd->response) { + if (cmd->response) __free_cmd(cmd->response); - } __free_cmd(cmd); } -typedef enum { DECODER=0, ENCODER, } encode_t; - struct channel_stats { atomic_t packets_sent; atomic_t packets_received; }; struct channel_pvt { - spinlock_t lock; /* Lock for this structure */ - encode_t encoder; /* If we're an encoder */ + spinlock_t lock; /* Lock for this structure */ struct wcdte *wc; - - unsigned int timestamp; - unsigned int seqno; - - unsigned int cmd_seqno; - - unsigned int timeslot_in_num; /* DTE channel on which results will be received from */ - unsigned int timeslot_out_num; /* DTE channel to send data to */ - - unsigned int chan_in_num; /* DTE channel on which results will be received from */ - unsigned int chan_out_num; /* DTE channel to send data to */ - + u16 seqno; + u8 cmd_seqno; + u8 ssrc; + u16 timeslot_in_num; /* DTE timeslot to receive from */ + u16 timeslot_out_num; /* DTE timeslot to send data to */ + u16 chan_in_num; /* DTE channel to receive from */ + u16 chan_out_num; /* DTE channel to send data to */ + u32 timestamp; + struct { + u8 encoder:1; /* If we're an encoder */ + }; struct channel_stats stats; - - u16 last_dte_seqno; - unsigned char ssrc; - struct list_head rx_queue; /* Transcoded packets for this channel. */ + struct list_head rx_queue; /* Transcoded packets for this channel. */ }; struct wcdte { char board_name[40]; const char *variety; int pos; - int cards; struct list_head node; spinlock_t reglock; wait_queue_head_t waitq; struct semaphore chansem; #define DTE_READY 1 -#define DTE_SHUTDOWN 2 +#define DTE_SHUTDOWN 2 +#define DTE_POLLING 3 unsigned long flags; - spinlock_t cmd_list_lock; - spinlock_t rx_list_lock; /* This is a device-global list of commands that are waiting to be * transmited (and did not fit on the transmit descriptor ring) */ + spinlock_t cmd_list_lock; struct list_head cmd_list; struct list_head waiting_for_response_list; + + spinlock_t rx_list_lock; struct list_head rx_list; + spinlock_t rx_lock; unsigned int seq_num; + int last_rx_seq_num; unsigned char numchannels; unsigned char complexname[40]; @@ -471,7 +432,7 @@ struct wcdte { unsigned long iobase; struct wctc4xxp_descriptor_ring *txd; struct wctc4xxp_descriptor_ring *rxd; - + struct zt_transcoder *uencode; struct zt_transcoder *udecode; struct channel_pvt *encoders; @@ -490,80 +451,78 @@ struct wcdte { struct sk_buff_head captured_packets; struct net_device *netdev; struct net_device_stats net_stats; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) struct napi_struct napi; #endif struct timer_list watchdog; + atomic_t open_channels; + struct timer_list polling; +#if HZ > 100 + unsigned long jiffies_at_last_poll; +#endif +}; +#ifdef HAVE_NETDEV_PRIV +struct wcdte_netdev_priv { + struct wcdte *wc; }; +#endif + +static inline struct wcdte * +wcdte_from_netdev(struct net_device *netdev) +{ +#ifdef HAVE_NETDEV_PRIV + struct wcdte_netdev_priv *priv; + priv = netdev_priv(netdev); + return priv->wc; +#else + return netdev->priv; +#endif +} + -static inline void wctc4xxp_set_ready(struct wcdte *wc) { +static inline void wctc4xxp_set_ready(struct wcdte *wc) +{ set_bit(DTE_READY, &wc->flags); } -static inline int wctc4xxp_is_ready(struct wcdte *wc) { + +static inline int wctc4xxp_is_ready(struct wcdte *wc) +{ return test_bit(DTE_READY, &wc->flags); } -#if 1 - /* \todo This macro is a candidate for removal. It's still here because of - * how the commands are passed to this zt_send_cmd */ -#define wctc4xxp_send_cmd(wc, command) ({ \ - int __res; \ - u8 _cmd[] = command; \ - struct tcb *cmd; \ - if (!(cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE))) \ - return -ENOMEM; \ - BUG_ON(sizeof(_cmd) > SFRAME_SIZE); \ - memcpy(cmd->data, _cmd, sizeof(_cmd)); \ - cmd->data_len = sizeof(_cmd); \ - __res = __wctc4xxp_send_cmd(wc, cmd); \ - __res; \ -}) -#define wctc4xxp_create_cmd(wc, command) ({ \ - u8 _command[] = command; \ - struct tcb *_cmd; \ - if (!(_cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE))) \ - return -ENOMEM; \ - BUG_ON(sizeof(_command) > SFRAME_SIZE); \ - memcpy(_cmd->data, _command, sizeof(_command)); \ - _cmd->data_len = sizeof(_command); \ - _cmd; \ -}) -#endif - #define DTE_FORMAT_ULAW 0x00 #define DTE_FORMAT_G723_1 0x04 #define DTE_FORMAT_ALAW 0x08 #define DTE_FORMAT_G729A 0x12 #define DTE_FORMAT_UNDEF 0xFF -static inline u8 wctc4xxp_zapfmt_to_dtefmt(unsigned int fmt) +static inline u8 wctc4xxp_dahdifmt_to_dtefmt(unsigned int fmt) { u8 pt; - - switch(fmt) { - case ZT_FORMAT_G723_1: - pt = DTE_FORMAT_G723_1; - break; - case ZT_FORMAT_ULAW: - pt = DTE_FORMAT_ULAW; - break; - case ZT_FORMAT_ALAW: - pt = DTE_FORMAT_ALAW; - break; - case ZT_FORMAT_G729A: - pt = DTE_FORMAT_G729A; - break; - default: - pt = DTE_FORMAT_UNDEF; - break; + + switch (fmt) { + case ZT_FORMAT_G723_1: + pt = DTE_FORMAT_G723_1; + break; + case ZT_FORMAT_ULAW: + pt = DTE_FORMAT_ULAW; + break; + case ZT_FORMAT_ALAW: + pt = DTE_FORMAT_ALAW; + break; + case ZT_FORMAT_G729A: + pt = DTE_FORMAT_G729A; + break; + default: + pt = DTE_FORMAT_UNDEF; + break; } return pt; } - -static struct sk_buff * +static struct sk_buff * tcb_to_skb(struct net_device *netdev, const struct tcb *cmd) { struct sk_buff *skb; @@ -572,12 +531,12 @@ tcb_to_skb(struct net_device *netdev, const struct tcb *cmd) skb->dev = netdev; skb_put(skb, cmd->data_len); memcpy(skb->data, cmd->data, cmd->data_len); - skb->protocol = eth_type_trans(skb,netdev); + skb->protocol = eth_type_trans(skb, netdev); } return skb; } -/** +/** * wctc4xxp_skb_to_cmd - Convert a socket buffer (skb) to a tcb * @wc: The transcoder that we're going to send this command to. * @skb: socket buffer to convert. @@ -586,81 +545,72 @@ tcb_to_skb(struct net_device *netdev, const struct tcb *cmd) static struct tcb * wctc4xxp_skb_to_cmd(struct wcdte *wc, const struct sk_buff *skb) { - const unsigned long alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + const gfp_t alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct tcb *cmd; - /* const static char dev_mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; */ - if ((cmd = __alloc_cmd(alloc_flags, 0))) { + cmd = __alloc_cmd(skb->len, alloc_flags, 0); + if (cmd) { int res; cmd->data_len = skb->len; - if ((res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len))) { - DTE_PRINTK(WARNING, + res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len); + if (res) { + DTE_PRINTK(WARNING, "Failed call to skb_copy_bits.\n"); free_cmd(cmd); cmd = NULL; } - /* When we set up our interface we indicated that we do not - * support ARP. Therefore, the destination MAC on packets - * arriving from the kernel networking components are not - * going to be correct. Let's fix that here. - */ - /* \todo let us just use whatever was in the packet already... */ - /* memcpy(&cmd->cmd[6], dev_mac, sizeof(dev_mac)); */ } return cmd; } -static void +static void wctc4xxp_net_set_multi(struct net_device *netdev) { - struct wcdte *wc = netdev->priv; - DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n", - __FUNCTION__, netdev->promiscuity); + struct wcdte *wc = wcdte_from_netdev(netdev); + DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n", + __func__, netdev->promiscuity); } -static int +static int wctc4xxp_net_up(struct net_device *netdev) { - struct wcdte *wc = netdev->priv; - DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__); -#if 1 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + struct wcdte *wc = wcdte_from_netdev(netdev); + DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __func__); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_poll_enable(netdev); #else napi_enable(&wc->napi); -#endif #endif return 0; } -static int +static int wctc4xxp_net_down(struct net_device *netdev) { - struct wcdte *wc = netdev->priv; - DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__); -#if 1 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + struct wcdte *wc = wcdte_from_netdev(netdev); + DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __func__); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_poll_disable(netdev); #else napi_disable(&wc->napi); -#endif #endif return 0; } static void wctc4xxp_transmit_cmd(struct wcdte *, struct tcb *); -static int +static int wctc4xxp_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct wcdte *wc = netdev->priv; + struct wcdte *wc = wcdte_from_netdev(netdev); struct tcb *cmd; /* We set DO_NOT_CAPTURE because this packet was already captured by * in code higher up in the networking stack. We don't want to - * capture it twice. + * capture it twice. */ - if ((cmd = wctc4xxp_skb_to_cmd(wc, skb))) { - cmd->flags |= DO_NOT_CAPTURE; + cmd = wctc4xxp_skb_to_cmd(wc, skb); + if (cmd) { + cmd->flags |= DO_NOT_CAPTURE; wctc4xxp_transmit_cmd(wc, cmd); } @@ -668,7 +618,7 @@ wctc4xxp_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } -static int +static int wctc4xxp_net_receive(struct wcdte *wc, int max) { int count = 0; @@ -676,18 +626,17 @@ wctc4xxp_net_receive(struct wcdte *wc, int max) WARN_ON(0 == max); while ((skb = skb_dequeue(&wc->captured_packets))) { netif_receive_skb(skb); - if (++count >= max) { + if (++count >= max) break; - } } return count; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -static int +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +static int wctc4xxp_poll(struct net_device *netdev, int *budget) { - struct wcdte *wc = netdev->priv; + struct wcdte *wc = wcdte_from_netdev(netdev); int count = 0; int quota = min(netdev->quota, *budget); @@ -704,7 +653,7 @@ wctc4xxp_poll(struct net_device *netdev, int *budget) } } #else -static int +static int wctc4xxp_poll(struct napi_struct *napi, int budget) { struct wcdte *wc = container_of(napi, struct wcdte, napi); @@ -713,7 +662,11 @@ wctc4xxp_poll(struct napi_struct *napi, int budget) count = wctc4xxp_net_receive(wc, budget); if (!skb_queue_len(&wc->captured_packets)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) netif_rx_complete(wc->netdev, &wc->napi); +#else + netif_rx_complete(&wc->napi); +#endif } return count; } @@ -722,25 +675,25 @@ wctc4xxp_poll(struct napi_struct *napi, int budget) static struct net_device_stats * wctc4xxp_net_get_stats(struct net_device *netdev) { - struct wcdte *wc = netdev->priv; + struct wcdte *wc = wcdte_from_netdev(netdev); return &wc->net_stats; } /* Wait until this device is put into promiscuous mode, or we timeout. */ -static void +static void wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc) { unsigned int seconds = 15; unsigned long start = jiffies; struct net_device *netdev = wc->netdev; - DTE_PRINTK(INFO, + DTE_PRINTK(INFO, "Waiting %d seconds for adapter to be placed in " \ "promiscuous mode for early trace.\n", seconds); while (!netdev->promiscuity) { if (signal_pending(current)) { - DTE_PRINTK(INFO, + DTE_PRINTK(INFO, "Aborting wait due to signal.\n"); break; } @@ -756,11 +709,11 @@ wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc) static int wctc4xxp_turn_off_booted_led(struct wcdte *wc); static void wctc4xxp_turn_on_booted_led(struct wcdte *wc); -static int +static int wctc4xxp_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { - struct wcdte *wc = netdev->priv; - switch(cmd) { + struct wcdte *wc = wcdte_from_netdev(netdev); + switch (cmd) { case 0x89f0: down(&wc->chansem); wctc4xxp_turn_off_booted_led(wc); @@ -775,27 +728,37 @@ wctc4xxp_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return 0; } -/** +/** * wctc4xxp_net_register - Register a new network interface. * @wc: transcoder card to register the interface for. * * The network interface is primarily used for debugging in order to watch the * traffic between the transcoder and the host. - * + * */ -static int +static int wctc4xxp_net_register(struct wcdte *wc) { int res; struct net_device *netdev; +# ifdef HAVE_NETDEV_PRIV + struct wcdte_netdev_priv *priv; +# endif const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; - if (!(netdev = alloc_netdev(0, wc->board_name, ether_setup))) { +# ifdef HAVE_NETDEV_PRIV + netdev = alloc_netdev(sizeof(*priv), wc->board_name, ether_setup); + if (!netdev) + return -ENOMEM; + priv = netdev_priv(netdev); + priv->wc = wc; +# else + netdev = alloc_netdev(0, wc->board_name, ether_setup); + if (!netdev) return -ENOMEM; - } - - memcpy(netdev->dev_addr, our_mac, sizeof(our_mac)); netdev->priv = wc; +# endif + memcpy(netdev->dev_addr, our_mac, sizeof(our_mac)); netdev->set_multicast_list = &wctc4xxp_net_set_multi; netdev->open = &wctc4xxp_net_up; netdev->stop = &wctc4xxp_net_down; @@ -804,15 +767,16 @@ wctc4xxp_net_register(struct wcdte *wc) netdev->do_ioctl = &wctc4xxp_net_ioctl; netdev->promiscuity = 0; netdev->flags |= IFF_NOARP; -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netdev->poll = &wctc4xxp_poll; netdev->weight = 64; # else netif_napi_add(netdev, &wc->napi, &wctc4xxp_poll, 64); # endif - if ((res = register_netdev(netdev))) { - DTE_PRINTK(WARNING, + res = register_netdev(netdev); + if (res) { + DTE_PRINTK(WARNING, "Failed to register network device %s.\n", wc->board_name); goto error_sw; @@ -821,33 +785,29 @@ wctc4xxp_net_register(struct wcdte *wc) wc->netdev = netdev; skb_queue_head_init(&wc->captured_packets); - if (debug & DTE_DEBUG_NETWORK_EARLY) { + if (debug & DTE_DEBUG_NETWORK_EARLY) wctc4xxp_net_waitfor_promiscuous(wc); - } - DTE_PRINTK(DEBUG, + DTE_PRINTK(DEBUG, "Created network device %s for debug.\n", wc->board_name); return 0; error_sw: - if (netdev) free_netdev(netdev); + if (netdev) + free_netdev(netdev); return res; } -static void +static void wctc4xxp_net_unregister(struct wcdte *wc) { struct sk_buff *skb; - if (!wc->netdev) { - return; - } + if (!wc->netdev) + return; unregister_netdev(wc->netdev); - - while ((skb = skb_dequeue(&wc->captured_packets))) { + while ((skb = skb_dequeue(&wc->captured_packets))) kfree_skb(skb); - } - free_netdev(wc->netdev); wc->netdev = NULL; } @@ -859,35 +819,35 @@ wctc4xxp_net_unregister(struct wcdte *wc) * @cmd: command to send to network stack. * */ -static void +static void wctc4xxp_net_capture_cmd(struct wcdte *wc, const struct tcb *cmd) { struct sk_buff *skb; struct net_device *netdev = wc->netdev; - if (!netdev) { + if (!netdev) return; - } /* No need to capture if there isn't anyone listening. */ - if (!(netdev->flags & IFF_UP)) { + if (!(netdev->flags & IFF_UP)) return; - } - + if (skb_queue_len(&wc->captured_packets) > MAX_CAPTURED_PACKETS) { WARN_ON_ONCE(1); return; } - if (!(skb = tcb_to_skb(netdev, cmd))) { + skb = tcb_to_skb(netdev, cmd); + if (!skb) return; - } skb_queue_tail(&wc->captured_packets, skb); -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) netif_rx_schedule(netdev); -# else +# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) netif_rx_schedule(netdev, &wc->napi); +# else + netif_rx_schedule(&wc->napi); # endif return; } @@ -901,13 +861,9 @@ struct wctc4xxp_descriptor { __le32 container; /* Unused */ } __attribute__((packed)); -#define DRING_SIZE (1 << 5) /* Must be a power of two */ -#define DRING_MASK (DRING_SIZE-1) -#define MIN_PACKET_LEN 64 - struct wctc4xxp_descriptor_ring { /* Pointer to an array of descriptors to give to hardware. */ - struct wctc4xxp_descriptor* desc; + struct wctc4xxp_descriptor *desc; /* Read completed buffers from the head. */ unsigned int head; /* Write ready buffers to the tail. */ @@ -932,54 +888,52 @@ struct wctc4xxp_descriptor_ring { * wctc4xxp_descriptor - Returns the desriptor at index. * @dr: The descriptor ring we're using. * @index: index of the descriptor we want. - * + * * We need this function because we do not know what the padding on the * descriptors will be. Otherwise, we would just use an array. */ static inline struct wctc4xxp_descriptor * wctc4xxp_descriptor(struct wctc4xxp_descriptor_ring *dr, int index) { - return (struct wctc4xxp_descriptor *)((u8*)dr->desc + + return (struct wctc4xxp_descriptor *)((u8 *)dr->desc + ((sizeof(*dr->desc) + dr->padding) * index)); } static int -wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, struct wctc4xxp_descriptor_ring *dr, - u32 des1, unsigned int direction) +wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, + struct wctc4xxp_descriptor_ring *dr, u32 des1, unsigned int direction) { - int i; + int i; const u32 END_OF_RING = 0x02000000; u8 cache_line_size = 0; struct wctc4xxp_descriptor *d; + int add_padding; BUG_ON(!pdev); BUG_ON(!dr); - if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) { - /* \todo Print an error message... */ + if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) return -EIO; - } memset(dr, 0, sizeof(*dr)); /* * Add some padding to each descriptor to ensure that they are - * aligned on host system cache-line boundaries, but only for the + * aligned on host system cache-line boundaries, but only for the * cache-line sizes that we support. * */ - if ((0x08 == cache_line_size) || (0x10 == cache_line_size) || - (0x20 == cache_line_size)) - { + add_padding = (0x08 == cache_line_size) || + (0x10 == cache_line_size) || + (0x20 == cache_line_size); + if (add_padding) dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d); - } - dr->desc = pci_alloc_consistent(pdev, + dr->desc = pci_alloc_consistent(pdev, (sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma); - if (!dr->desc) { + if (!dr->desc) return -ENOMEM; - } memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE); for (i = 0; i < DRING_SIZE; ++i) { @@ -996,12 +950,12 @@ wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, struct wctc4xxp_descri #define OWN_BIT cpu_to_le32(0x80000000) #define OWNED(_d_) (((_d_)->des0)&OWN_BIT) -#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb();} while (0) +#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb(); } while (0) -const unsigned int BUFFER1_SIZE_MASK = 0x7ff; +static const unsigned int BUFFER1_SIZE_MASK = 0x7ff; -static int -wctc4xxp_submit(struct wctc4xxp_descriptor_ring* dr, struct tcb *c) +static int +wctc4xxp_submit(struct wctc4xxp_descriptor_ring *dr, struct tcb *c) { volatile struct wctc4xxp_descriptor *d; unsigned int len; @@ -1015,7 +969,7 @@ wctc4xxp_submit(struct wctc4xxp_descriptor_ring* dr, struct tcb *c) } spin_lock_irqsave(&dr->lock, flags); - d = wctc4xxp_descriptor(dr, dr->tail); + d = wctc4xxp_descriptor(dr, dr->tail); WARN_ON(!d); if (d->buffer1) { spin_unlock_irqrestore(&dr->lock, flags); @@ -1024,10 +978,10 @@ wctc4xxp_submit(struct wctc4xxp_descriptor_ring* dr, struct tcb *c) } d->des1 &= cpu_to_le32(~(BUFFER1_SIZE_MASK)); d->des1 |= cpu_to_le32(len & BUFFER1_SIZE_MASK); - d->buffer1 = pci_map_single(dr->pdev, c->data, - SFRAME_SIZE, dr->direction); + d->buffer1 = pci_map_single(dr->pdev, c->data, + SFRAME_SIZE, dr->direction); - SET_OWNED(d); /* That's it until the hardware is done with it. */ + SET_OWNED(d); /* That's it until the hardware is done with it. */ dr->pending[dr->tail] = c; dr->tail = ++dr->tail & DRING_MASK; ++dr->count; @@ -1035,7 +989,7 @@ wctc4xxp_submit(struct wctc4xxp_descriptor_ring* dr, struct tcb *c) return 0; } -static inline struct tcb* +static inline struct tcb* wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr) { volatile struct wctc4xxp_descriptor *d; @@ -1045,16 +999,16 @@ wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr) spin_lock_irqsave(&dr->lock, flags); d = wctc4xxp_descriptor(dr, head); if (d->buffer1 && !OWNED(d)) { - pci_unmap_single(dr->pdev, d->buffer1, - SFRAME_SIZE, dr->direction); + pci_unmap_single(dr->pdev, d->buffer1, + SFRAME_SIZE, dr->direction); c = dr->pending[head]; WARN_ON(!c); - dr->head = (++head) & DRING_MASK; + dr->head = (++head) & DRING_MASK; d->buffer1 = 0; --dr->count; WARN_ON(!c); c->data_len = (d->des0 >> 16) & BUFFER1_SIZE_MASK; - c->flags |= TX_COMPLETE; + WARN_ON(c->data_len > SFRAME_SIZE); } else { c = NULL; } @@ -1062,7 +1016,7 @@ wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr) return c; } -static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr) +static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr) { int count; unsigned long flags; @@ -1072,35 +1026,38 @@ static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr) return count; } -static inline void +static inline void __wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { outl(val, wc->iobase + addr); } -static inline unsigned int +static inline unsigned int __wctc4xxp_getctl(struct wcdte *wc, unsigned int addr) { return inl(wc->iobase + addr); } -static inline void +static inline void wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { - spin_lock_bh(&wc->reglock); + unsigned long flags; + spin_lock_irqsave(&wc->reglock, flags); __wctc4xxp_setctl(wc, addr, val); - spin_unlock_bh(&wc->reglock); + spin_unlock_irqrestore(&wc->reglock, flags); } -static inline void -wctc4xxp_receive_demand_poll(struct wcdte *wc) +static inline void +wctc4xxp_receive_demand_poll(struct wcdte *wc) { __wctc4xxp_setctl(wc, 0x0010, 0x00000000); } -static inline void +static inline void wctc4xxp_transmit_demand_poll(struct wcdte *wc) { + return; +# if 0 __wctc4xxp_setctl(wc, 0x0008, 0x00000000); /* \todo Investigate why this register needs to be written twice in @@ -1110,11 +1067,13 @@ wctc4xxp_transmit_demand_poll(struct wcdte *wc) * problem with the dte firmware. */ __wctc4xxp_setctl(wc, 0x0008, 0x00000000); +#endif } /* Returns the size, in bytes, of a CSM_ENCAPS packet, given the number of * parameters used. */ -#define SIZE_WITH_N_PARAMETERS(__n) (sizeof(struct csm_encaps_hdr) + ((__n) * (sizeof(u16)))) +#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 */ @@ -1123,7 +1082,9 @@ wctc4xxp_transmit_demand_poll(struct wcdte *wc) 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 void +static int wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd); + +static void setup_common_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) { memcpy(hdr->ethhdr.h_dest, dst_mac, sizeof(dst_mac)); @@ -1131,7 +1092,7 @@ setup_common_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) hdr->ethhdr.h_proto = cpu_to_be16(ETH_P_CSM_ENCAPS); } -static void +static void setup_supervisor_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) { setup_common_header(wc, hdr); @@ -1142,205 +1103,566 @@ setup_supervisor_header(struct wcdte *wc, struct csm_encaps_hdr *hdr) hdr->channel = cpu_to_be16(SUPERVISOR_CHANNEL); } -static void -__wctc4xxp_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot) +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 +create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class, + u16 function, const u16 *parameters, const int num_parameters) { - struct csm_create_channel_cmd *c; - c = hdr_from_cmd(cmd); + struct csm_encaps_hdr *hdr = cmd->data; + int i; - BUG_ON(timeslot > 0x01ff); + if (cmd->response) { + free_cmd(cmd->response); + cmd->response = NULL; + } - setup_supervisor_header(wc, &c->hdr); + setup_supervisor_header(wc, hdr); - c->hdr.length = LENGTH_WITH_N_PARAMETERS(2); - c->hdr.index = 0x0; - c->hdr.type = CONFIG_CHANGE_TYPE; - c->hdr.class = CONFIG_DEVICE_CLASS; - c->hdr.function = cpu_to_le16(SUPVSR_CREATE_CHANNEL); - c->hdr.reserved = 0x0000; + hdr->length = LENGTH_WITH_N_PARAMETERS(num_parameters); + hdr->index = 0; + hdr->type = type; + hdr->class = class; + hdr->function = cpu_to_le16(function); + hdr->reserved = 0; - c->channel_type = cpu_to_le16(0x0002); /* Channel type is VoIP */ - c->timeslot = cpu_to_le16(timeslot); + for (i = 0; i < num_parameters; ++i) + hdr->params[i] = cpu_to_le16(parameters[i]); - cmd->flags |= WAIT_FOR_RESPONSE; - cmd->data_len = sizeof(*c); + cmd->flags = WAIT_FOR_RESPONSE; + cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters); } -struct tcb * -wctc4xxp_create_channel_cmd(struct wcdte *wc, u16 timeslot) +static void +create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class, + u16 function, const u16 *parameters, int num_parameters) { - struct tcb *cmd; - if (!(cmd = alloc_cmd())) { - return NULL; + int i; + struct csm_encaps_hdr *hdr = cmd->data; + + if (cmd->response) { + free_cmd(cmd->response); + cmd->response = NULL; } - __wctc4xxp_create_channel_cmd(wc, cmd, timeslot); - return cmd; -} -void -__wctc4xxp_create_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd) -{ - struct csm_encaps_hdr *hdr = cmd->data; - BUG_ON(SIZE_WITH_N_PARAMETERS(2) > cmd->data_len); + setup_channel_header(pvt, hdr); - setup_supervisor_header(wc, hdr); + hdr->length = LENGTH_WITH_N_PARAMETERS(num_parameters); + hdr->index = 0; + hdr->type = type; + hdr->class = class; + hdr->function = cpu_to_le16(function); + hdr->reserved = 0; - hdr->length = LENGTH_WITH_N_PARAMETERS(2); - hdr->index = 0x0; - hdr->type = CONFIG_CHANGE_TYPE; - hdr->class = CONFIG_DEVICE_CLASS; - hdr->function = cpu_to_le16(0x0411); - hdr->reserved = 0x0000; - hdr->params[0] = cpu_to_le16(0x012c); - hdr->params[1] = cpu_to_le16(0x0000); - - cmd->flags |= WAIT_FOR_RESPONSE; - cmd->data_len = SIZE_WITH_N_PARAMETERS(2); - return; + for (i = 0; i < num_parameters; ++i) + hdr->params[i] = cpu_to_le16(parameters[i]); + + cmd->flags = WAIT_FOR_RESPONSE; + cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters); } -struct tcb * -wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct zt_transcoder_channel *dtc, size_t inbytes) +static int +send_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot, + u16 *channel_number) { - const struct channel_pvt *cpvt = dtc->pvt; - struct rtp_packet *packet; - struct tcb *cmd; + int res; + const u16 parameters[] = {0x0002, timeslot}; - if (!(cmd = alloc_cmd())) { - return NULL; - } + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, SUPVSR_CREATE_CHANNEL, + parameters, ARRAY_SIZE(parameters)); - packet = cmd->data; + res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); + if (res) + return res; - BUG_ON(cmd->data_len < sizeof(*packet)); - - /* setup the ethernet header */ - memcpy(packet->ethhdr.h_dest, dst_mac, sizeof(dst_mac)); - memcpy(packet->ethhdr.h_source, src_mac, sizeof(src_mac)); - packet->ethhdr.h_proto = cpu_to_be16(ETH_P_IP); - - /* setup the IP header */ - packet->iphdr.ihl = 5; - packet->iphdr.version = 4; - packet->iphdr.tos = 0; - packet->iphdr.tot_len = cpu_to_be16(inbytes+40); - packet->iphdr.id = cpu_to_be16(cpvt->seqno); - packet->iphdr.frag_off= cpu_to_be16(0x4000); - packet->iphdr.ttl = 64; - packet->iphdr.protocol= 0x11; /* UDP */ - packet->iphdr.check = 0; - packet->iphdr.saddr = cpu_to_be32(0xc0a80903); - packet->iphdr.daddr = cpu_to_be32(0xc0a80903); - packet->iphdr.check = ip_fast_csum((void*)&packet->iphdr, sizeof(struct iphdr)); + if (0x0000 != response_header(cmd)->params[0]) { + /* The DTE failed to create the channel. */ + /* TODO put some debug information here. */ + WARN_ON(1); + free_cmd(cmd->response); + cmd->response = NULL; + return -EIO; + } - /* setup the UDP header */ - packet->udphdr.source = cpu_to_be16(cpvt->timeslot_out_num + 0x5000); - packet->udphdr.dest = cpu_to_be16(cpvt->timeslot_in_num + 0x5000); - packet->udphdr.len = cpu_to_be16(inbytes + sizeof(struct rtphdr) + sizeof(struct udphdr)); - packet->udphdr.check = 0; + *channel_number = le16_to_cpu(response_header(cmd)->params[1]); + free_cmd(cmd->response); + cmd->response = NULL; + return 0; +} - /* Setup the RTP header */ - packet->rtphdr.ver = 2; - packet->rtphdr.padding = 0; - packet->rtphdr.extension = 0; - packet->rtphdr.csrc_count = 0; - packet->rtphdr.marker = 0; - packet->rtphdr.type = wctc4xxp_zapfmt_to_dtefmt(dtc->srcfmt); - packet->rtphdr.seqno = cpu_to_be16(cpvt->seqno); - packet->rtphdr.timestamp = cpu_to_be32(cpvt->timestamp); - packet->rtphdr.ssrc = cpu_to_be32(cpvt->ssrc); - - cmd->data_len = sizeof(*packet) + inbytes; +static int +send_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0x012c, 0x0000}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0411, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} - return cmd; +static int +send_set_spu_clk_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0x012c, 0x0000}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0412, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } -static void -wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr) + +static int +send_tdm_select_bus_mode_cmd(struct wcdte *wc, struct tcb *cmd) { - int i; - struct wctc4xxp_descriptor *d; - unsigned long flags; - - /* NOTE: The DTE must be in the stopped state. */ - spin_lock_irqsave(&dr->lock, flags); - for (i = 0; i < DRING_SIZE; ++i) { - d = wctc4xxp_descriptor(dr, i); - if (d->buffer1) { - pci_unmap_single(dr->pdev, d->buffer1, - SFRAME_SIZE, dr->direction); - d->buffer1 = 0; - /* Commands will also be sitting on the waiting for - * response list, so we want to make sure to delete - * them from that list as well. */ - list_del_init(&(dr->pending[i])->node); - free_cmd(dr->pending[i]); - dr->pending[i] = NULL; - } - } - dr->head = 0; - dr->tail = 0; - dr->count = 0; - spin_unlock_irqrestore(&dr->lock, flags); - pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE, - dr->desc, dr->desc_dma); + const u16 parameters[] = {0x0004}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0417, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } -static void wctc4xxp_cleanup_command_list(struct wcdte *wc) +static int +send_set_eth_header_cmd(struct wcdte *wc, struct tcb *cmd, + const u8 *host_mac, const u8 *assigned_mac) { - struct tcb *cmd; - LIST_HEAD(local_list); + u16 parameters[8]; + u16 *part; - spin_lock_bh(&wc->cmd_list_lock); - list_splice_init(&wc->cmd_list, &local_list); - list_splice_init(&wc->waiting_for_response_list, &local_list); - list_splice_init(&wc->rx_list, &local_list); - spin_unlock_bh(&wc->cmd_list_lock); + parameters[0] = 0x0001; + part = (u16 *)host_mac; + parameters[1] = part[0]; + parameters[2] = part[1]; + parameters[3] = part[2]; + part = (u16 *)assigned_mac; + parameters[4] = part[0]; + parameters[5] = part[1]; + parameters[6] = part[2]; + parameters[7] = 0x0008; - while(!list_empty(&local_list)) { - cmd = list_entry(local_list.next, struct tcb, node); - list_del_init(&cmd->node); - free_cmd(cmd); - } + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0100, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } -/** - * The command list is used to store commands that couldn't fit in the tx - * descriptor list when they were requested. - */ -static void -wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd) +static int +send_supvsr_setup_tdm_parms(struct wcdte *wc, struct tcb *cmd, + u8 bus_number) { - spin_lock_bh(&wc->cmd_list_lock); - list_add_tail(&cmd->node, &wc->cmd_list); - spin_unlock_bh(&wc->cmd_list_lock); + const u16 parameters[] = {0x8380, 0x0c00, 0, (bus_number << 2)&0xc}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0407, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); } -static void -wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd) +static int +send_ip_service_config_cmd(struct wcdte *wc, struct tcb *cmd) { - spin_lock_bh(&wc->cmd_list_lock); - list_add_tail(&cmd->node, &wc->waiting_for_response_list); - spin_unlock_bh(&wc->cmd_list_lock); + const u16 parameters[] = {0x0200}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0302, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +send_arp_service_config_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0x0001}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0105, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +send_icmp_service_config_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0xff01}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0304, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +send_device_set_country_code_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0x0000}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x041b, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +send_spu_features_control_cmd(struct wcdte *wc, struct tcb *cmd, u16 options) +{ + const u16 parameters[] = {options}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0013, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +send_tdm_opt_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0x0000}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0435, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +send_destroy_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 channel) +{ + int res; + u16 result; + const u16 parameters[] = {channel}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0011, 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) { + DTE_PRINTK(ERR, "Failed to destroy channel %04d (%04x)\n", + channel, result); + return -EIO; + } + return 0; +} + +static int +send_set_ip_hdr_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd) +{ + int res; + u16 result; + struct wcdte *wc = pvt->wc; + const u16 parameters[] = {0, 0x0045, 0, 0, 0x0040, 0x1180, 0, + 0xa8c0, 0x0309, 0xa8c0, 0x0309, + cpu_to_be16(pvt->timeslot_out_num + 0x5000), + cpu_to_be16(pvt->timeslot_in_num + 0x5000), + 0, 0}; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 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) { + DTE_PRINTK(ERR, "Failure in %s (%04x)\n", + __func__, result); + return -EIO; + } + return 0; +} + +static int +send_voip_vceopt_cmd(struct channel_pvt *pvt, struct tcb *cmd, u16 length) +{ + int res; + u16 result; + const u16 parameters[] = {((length << 8)|0x21), 0x1c00, 0x0004, 0, 0}; + struct wcdte *wc = pvt->wc; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 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) { + DTE_PRINTK(ERR, "Failure in %s (%04x)\n", + __func__, result); + return -EIO; + } + return 0; +} + +static int +send_voip_tonectl_cmd(struct channel_pvt *pvt, struct tcb *cmd) +{ + int res; + u16 result; + const u16 parameters[] = {0}; + struct wcdte *wc = pvt->wc; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 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) { + DTE_PRINTK(ERR, "Failure in %s (%04x)\n", + __func__, result); + return -EIO; + } + return 0; +} + +static int +send_voip_dtmfopt_cmd(struct channel_pvt *pvt, struct tcb *cmd) +{ + const u16 parameters[] = {0x0008}; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 0x8002, parameters, ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); +} + +static int +send_voip_indctrl_cmd(struct channel_pvt *pvt, struct tcb *cmd) +{ + const u16 parameters[] = {0x0007}; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 0x8084, parameters, ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); +} + +static int +send_voip_vopena_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 format) +{ + const u16 parameters[] = {1, ((format<<8)|0x80), 0, 0, 0, + 0x3412, 0x7856}; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 0x8000, parameters, ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); +} + +static int +send_voip_vopena_close_cmd(struct channel_pvt *pvt, struct tcb *cmd) +{ + int res; + const u16 parameters[] = {0}; + create_channel_cmd(pvt, cmd, CONFIG_CHANGE_TYPE, CONFIG_CHANNEL_CLASS, + 0x8000, parameters, ARRAY_SIZE(parameters)); + res = wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd); + if (res) + return res; + /* Let's check the response for any error codes.... */ + if (0x0000 != response_header(cmd)->params[0]) { + WARN_ON(1); + return -EIO; + } + return 0; +} + +static int +send_ip_options_cmd(struct wcdte *wc, struct tcb *cmd) +{ + const u16 parameters[] = {0x0002}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x0306, parameters, + ARRAY_SIZE(parameters)); + return wctc4xxp_transmit_cmd_and_wait(wc, cmd); +} + +static int +_send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, u16 enable, u16 + encoder_channel, u16 decoder_channel, u16 encoder_format, + u16 decoder_format) +{ + int res; + const u16 parameters[] = {enable, encoder_channel, encoder_format, + decoder_channel, decoder_format}; + create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE, + CONFIG_DEVICE_CLASS, 0x9322, 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.... */ + if (0x0000 != response_header(cmd)->params[0]) { +#ifdef USE_CUSTOM_MEMCACHE + WARN_ON(0xdeadbeef != cmd->response->sentinel); +#endif + WARN_ON(1); + return -EIO; + } + return 0; +} + +static int +send_trans_connect_cmd(struct wcdte *wc, struct tcb *cmd, const u16 + encoder_channel, const u16 decoder_channel, const u16 encoder_format, + const u16 decoder_format) +{ + return _send_trans_connect_cmd(wc, cmd, 1, encoder_channel, + decoder_channel, encoder_format, decoder_format); +} + +static int +send_trans_disconnect_cmd(struct wcdte *wc, struct tcb *cmd, const u16 + encoder_channel, const u16 decoder_channel, const u16 encoder_format, + const u16 decoder_format) +{ + return _send_trans_connect_cmd(wc, cmd, 0, encoder_channel, + decoder_channel, encoder_format, decoder_format); +} + +static struct tcb * +wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct zt_transcoder_channel *dtc, + size_t inbytes) +{ + const struct channel_pvt *cpvt = dtc->pvt; + struct rtp_packet *packet; + struct tcb *cmd; + + cmd = alloc_cmd(sizeof(*packet) + inbytes); + if (!cmd) + return NULL; + + packet = cmd->data; + + BUG_ON(cmd->data_len < sizeof(*packet)); + + /* setup the ethernet header */ + memcpy(packet->ethhdr.h_dest, dst_mac, sizeof(dst_mac)); + memcpy(packet->ethhdr.h_source, src_mac, sizeof(src_mac)); + packet->ethhdr.h_proto = cpu_to_be16(ETH_P_IP); + + /* setup the IP header */ + packet->iphdr.ihl = 5; + packet->iphdr.version = 4; + packet->iphdr.tos = 0; + packet->iphdr.tot_len = cpu_to_be16(inbytes+40); + packet->iphdr.id = 0; + packet->iphdr.frag_off = cpu_to_be16(0x4000); + packet->iphdr.ttl = 64; + packet->iphdr.protocol = 0x11; /* UDP */ + packet->iphdr.check = 0; + packet->iphdr.saddr = cpu_to_be32(0xc0a80903); + packet->iphdr.daddr = cpu_to_be32(0xc0a80903); + + packet->iphdr.check = ip_fast_csum((void *)&packet->iphdr, + packet->iphdr.ihl); + + /* setup the UDP header */ + packet->udphdr.source = cpu_to_be16(cpvt->timeslot_out_num + 0x5000); + packet->udphdr.dest = cpu_to_be16(cpvt->timeslot_in_num + 0x5000); + packet->udphdr.len = cpu_to_be16(inbytes + sizeof(struct rtphdr) + + sizeof(struct udphdr)); + packet->udphdr.check = 0; + + /* Setup the RTP header */ + packet->rtphdr.ver = 2; + packet->rtphdr.padding = 0; + packet->rtphdr.extension = 0; + packet->rtphdr.csrc_count = 0; + packet->rtphdr.marker = 0; + packet->rtphdr.type = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt); + packet->rtphdr.seqno = cpu_to_be16(cpvt->seqno); + packet->rtphdr.timestamp = cpu_to_be32(cpvt->timestamp); + packet->rtphdr.ssrc = cpu_to_be32(cpvt->ssrc); + + WARN_ON(cmd->data_len > SFRAME_SIZE); + return cmd; +} +static void +wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr) +{ + int i; + struct wctc4xxp_descriptor *d; + + if (!dr || !dr->desc) + return; + + for (i = 0; i < DRING_SIZE; ++i) { + d = wctc4xxp_descriptor(dr, i); + if (d->buffer1) { + pci_unmap_single(dr->pdev, d->buffer1, + SFRAME_SIZE, dr->direction); + d->buffer1 = 0; + /* Commands will also be sitting on the waiting for + * response list, so we want to make sure to delete + * them from that list as well. */ + list_del_init(&(dr->pending[i])->node); + free_cmd(dr->pending[i]); + dr->pending[i] = NULL; + } + } + dr->head = 0; + dr->tail = 0; + dr->count = 0; + pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE, + dr->desc, dr->desc_dma); +} + +static void wctc4xxp_cleanup_command_list(struct wcdte *wc) +{ + struct tcb *cmd; + unsigned long flags; + LIST_HEAD(local_list); + + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_splice_init(&wc->cmd_list, &local_list); + list_splice_init(&wc->waiting_for_response_list, &local_list); + list_splice_init(&wc->rx_list, &local_list); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); + + while (!list_empty(&local_list)) { + cmd = list_entry(local_list.next, struct tcb, node); + list_del_init(&cmd->node); + free_cmd(cmd); + } +} + +/** + * The command list is used to store commands that couldn't fit in the tx + * descriptor list when they were requested. + */ +static void +wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd) +{ + unsigned long flags; + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_add_tail(&cmd->node, &wc->cmd_list); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); +} + +static void +wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd) +{ + unsigned long flags; + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_add_tail(&cmd->node, &wc->waiting_for_response_list); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } static void wctc4xxp_remove_from_response_list(struct wcdte *wc, struct tcb *cmd) { - spin_lock_bh(&wc->cmd_list_lock); + unsigned long flags; + spin_lock_irqsave(&wc->cmd_list_lock, flags); list_del_init(&cmd->node); - spin_unlock_bh(&wc->cmd_list_lock); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } -static void +static void wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd) { int res; if (cmd->data_len < MIN_PACKET_LEN) { - memset((u8*)(cmd->data) + cmd->data_len, 0, + memset((u8 *)(cmd->data) + cmd->data_len, 0, MIN_PACKET_LEN-cmd->data_len); cmd->data_len = MIN_PACKET_LEN; - } + } WARN_ON(cmd->response); WARN_ON(cmd->flags & TX_COMPLETE); cmd->timeout = jiffies + HZ/4; @@ -1351,32 +1673,32 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd) * retry if we do not get the response within the * timeout period. */ struct csm_encaps_hdr *hdr = cmd->data; - hdr->control |= SUPPRESS_ACK; + hdr->control |= SUPPRESS_ACK; } WARN_ON(!list_empty(&cmd->node)); wctc4xxp_add_to_response_list(wc, cmd); mod_timer(&wc->watchdog, jiffies + HZ/2); } - if (!(cmd->flags & DO_NOT_CAPTURE)) wctc4xxp_net_capture_cmd(wc, cmd); - if ((res=wctc4xxp_submit(wc->txd, cmd))) { - if (-EBUSY == res) { - /* Looks like we're out of room in the descriptor - * ring. We'll add this command to the pending list - * and the interrupt service routine will pull from - * this list as it clears up room in the descriptor - * ring. */ - wctc4xxp_remove_from_response_list(wc, cmd); - wctc4xxp_add_to_command_list(wc, cmd); - } else { - /* Unknown return value... */ - WARN_ON(1); - } - } else { + if (!(cmd->flags & DO_NOT_CAPTURE)) + wctc4xxp_net_capture_cmd(wc, cmd); + res = wctc4xxp_submit(wc->txd, cmd); + if (-EBUSY == res) { + /* Looks like we're out of room in the descriptor + * ring. We'll add this command to the pending list + * and the interrupt service routine will pull from + * this list as it clears up room in the descriptor + * ring. */ + wctc4xxp_remove_from_response_list(wc, cmd); + wctc4xxp_add_to_command_list(wc, cmd); + } else if (0 == res) { wctc4xxp_transmit_demand_poll(wc); + } else { + /* Unknown return value... */ + WARN_ON(1); } } -static int +static int wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd) { cmd->flags |= DO_NOT_AUTO_FREE; @@ -1385,77 +1707,62 @@ wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd) if (cmd->flags & DTE_CMD_TIMEOUT) { DTE_DEBUG(DTE_DEBUG_GENERAL, "Timeout waiting for command.\n"); return -EIO; - } + } return 0; } -static int wctc4xxp_create_channel_pair(struct wcdte *wc, - struct channel_pvt *cpvt, u8 simple, u8 complicated); -static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt); +static int wctc4xxp_create_channel_pair(struct wcdte *wc, + struct channel_pvt *cpvt, u8 simple, u8 complicated); +static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, + struct channel_pvt *cpvt); static int __wctc4xxp_setup_channels(struct wcdte *wc); -static int -__wctc4xxp_send_cmd(struct wcdte *wc, struct tcb *cmd) -{ - int ret = 0; - wctc4xxp_transmit_cmd(wc, cmd); - wait_for_completion(&cmd->complete); - if (cmd->flags & DTE_CMD_TIMEOUT) { - ret = -EIO; - } - free_cmd(cmd); - return ret; -} - -static void -wctc4xxp_init_state(struct channel_pvt *cpvt, encode_t encoder, - unsigned int channel, struct wcdte *wc) +static void +wctc4xxp_init_state(struct channel_pvt *cpvt, int encoder, + unsigned int channel, struct wcdte *wc) { memset(cpvt, 0, sizeof(*cpvt)); cpvt->encoder = encoder; cpvt->wc = wc; - cpvt->chan_in_num = INVALID; cpvt->chan_out_num = INVALID; - cpvt->ssrc = 0x78; - - cpvt->timeslot_in_num = channel* 2; - cpvt->timeslot_out_num = channel * 2; - - if (ENCODER == encoder) { - cpvt->timeslot_out_num++; - } else { - cpvt->timeslot_in_num++; - } + cpvt->timeslot_in_num = channel*2; + cpvt->timeslot_out_num = channel*2; + if (encoder) + ++cpvt->timeslot_out_num; + else + ++cpvt->timeslot_in_num; spin_lock_init(&cpvt->lock); INIT_LIST_HEAD(&cpvt->rx_queue); } -static unsigned int +static unsigned int wctc4xxp_getctl(struct wcdte *wc, unsigned int addr) { unsigned int val; - spin_lock_bh(&wc->reglock); + unsigned long flags; + spin_lock_irqsave(&wc->reglock, flags); val = __wctc4xxp_getctl(wc, addr); - spin_unlock_bh(&wc->reglock); + spin_unlock_irqrestore(&wc->reglock, flags); return val; } -static void -wctc4xxp_cleanup_channel_private(struct wcdte *wc, +static void +wctc4xxp_cleanup_channel_private(struct wcdte *wc, struct zt_transcoder_channel *dtc) { struct tcb *cmd, *temp; struct channel_pvt *cpvt = dtc->pvt; + unsigned long flags; LIST_HEAD(local_list); - spin_lock_bh(&cpvt->lock); + spin_lock_irqsave(&cpvt->lock, flags); list_splice_init(&cpvt->rx_queue, &local_list); zt_tc_clear_data_waiting(dtc); - cpvt->last_dte_seqno = 0; - spin_unlock_bh(&cpvt->lock); + spin_unlock_irqrestore(&cpvt->lock, flags); + memset(&cpvt->stats, 0, sizeof(cpvt->stats)); list_for_each_entry_safe(cmd, temp, &local_list, node) { list_del(&cmd->node); free_cmd(cmd); @@ -1463,7 +1770,7 @@ wctc4xxp_cleanup_channel_private(struct wcdte *wc, } static int -wctc4xxp_mark_channel_complement_built(struct wcdte *wc, +wctc4xxp_mark_channel_complement_built(struct wcdte *wc, struct zt_transcoder_channel *dtc) { int index; @@ -1474,17 +1781,17 @@ wctc4xxp_mark_channel_complement_built(struct wcdte *wc, BUG_ON(!cpvt); index = cpvt->timeslot_in_num/2; BUG_ON(index >= wc->numchannels); - if (cpvt->encoder == 1) { + if (cpvt->encoder) compl_dtc = &(wc->udecode->channels[index]); - } else { + else compl_dtc = &(wc->uencode->channels[index]); - } /* It shouldn't already have been built... */ WARN_ON(zt_tc_is_built(compl_dtc)); compl_dtc->built_fmts = dtc->dstfmt | dtc->srcfmt; compl_cpvt = compl_dtc->pvt; - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "dtc: %p is the complement to %p\n", compl_dtc, dtc); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "dtc: %p is the complement to %p\n", compl_dtc, dtc); compl_cpvt->chan_in_num = cpvt->chan_out_num; compl_cpvt->chan_out_num = cpvt->chan_in_num; zt_tc_set_built(compl_dtc); @@ -1493,7 +1800,7 @@ wctc4xxp_mark_channel_complement_built(struct wcdte *wc, return 0; } -static int +static int do_channel_allocate(struct zt_transcoder_channel *dtc) { struct channel_pvt *cpvt = dtc->pvt; @@ -1502,27 +1809,33 @@ do_channel_allocate(struct zt_transcoder_channel *dtc) u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */ int res; +#ifndef DEBUG_WCTC4XXP down(&wc->chansem); +#else + if (down_interruptible(&wc->chansem)) + return -EINTR; +#endif /* Check again to see if the channel was built after grabbing the * channel semaphore, in case the previous holder of the semaphore * built this channel as a complement to itself. */ if (zt_tc_is_built(dtc)) { up(&wc->chansem); - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, - "Allocating channel %p which is already built.\n", dtc); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Allocating channel %p which is already built.\n", dtc); return 0; } - - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, - "Entering %s for channel %p.\n", __FUNCTION__, dtc); + + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Entering %s for channel %p.\n", __func__, dtc); /* Anything on the rx queue now is old news... */ wctc4xxp_cleanup_channel_private(wc, dtc); - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Allocating a new channel: %p.\n", dtc); - wctc4xxp_srcfmt = wctc4xxp_zapfmt_to_dtefmt(dtc->srcfmt); - wctc4xxp_dstfmt = wctc4xxp_zapfmt_to_dtefmt(dtc->dstfmt); - res = wctc4xxp_create_channel_pair(wc, cpvt, wctc4xxp_srcfmt, - wctc4xxp_dstfmt); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Allocating a new channel: %p.\n", dtc); + wctc4xxp_srcfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->srcfmt); + wctc4xxp_dstfmt = wctc4xxp_dahdifmt_to_dtefmt(dtc->dstfmt); + res = wctc4xxp_create_channel_pair(wc, cpvt, wctc4xxp_srcfmt, + wctc4xxp_dstfmt); if (res) { /* There was a problem creating the channel.... */ up(&wc->chansem); @@ -1531,17 +1844,50 @@ do_channel_allocate(struct zt_transcoder_channel *dtc) /* Mark this channel as built */ zt_tc_set_built(dtc); dtc->built_fmts = dtc->dstfmt | dtc->srcfmt; - /* Mark the channel complement (other half of encoder/decoder pair) as built */ + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Channel %p has dstfmt=%x and srcfmt=%x\n", dtc, dtc->dstfmt, + dtc->srcfmt); + /* Mark the channel complement (other half of encoder/decoder pair) as + * built */ res = wctc4xxp_mark_channel_complement_built(wc, dtc); up(&wc->chansem); zt_transcoder_alert(dtc); return res; } +static void +wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask) +{ + wc->intmask = intmask; + wctc4xxp_setctl(wc, 0x0038, intmask); +} + +static void +wctc4xxp_enable_interrupts(struct wcdte *wc) +{ + wctc4xxp_setintmask(wc, 0x000180c0); +} + +static void +wctc4xxp_disable_interrupts(struct wcdte *wc) +{ + /* Disable interrupts */ + wctc4xxp_setintmask(wc, 0x00000000); + wctc4xxp_setctl(wc, 0x0084, 0x00000000); +} + +static void +wctc4xxp_enable_polling(struct wcdte *wc) +{ + set_bit(DTE_POLLING, &wc->flags); + mod_timer(&wc->polling, jiffies + 1); + wctc4xxp_disable_interrupts(wc); +} + static int wctc4xxp_operation_allocate(struct zt_transcoder_channel *dtc) { - struct wcdte *wc = ((struct channel_pvt*)(dtc->pvt))->wc; + struct wcdte *wc = ((struct channel_pvt *)(dtc->pvt))->wc; if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { /* The shudown flags can also be set if there is a @@ -1549,14 +1895,27 @@ wctc4xxp_operation_allocate(struct zt_transcoder_channel *dtc) return -EIO; } + atomic_inc(&wc->open_channels); + if (atomic_read(&wc->open_channels) > POLLING_CALL_THRESHOLD) { + if (!test_bit(DTE_POLLING, &wc->flags)) + wctc4xxp_enable_polling(wc); + } + if (zt_tc_is_built(dtc)) { - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, - "Allocating channel %p which is already built.\n", dtc); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "Allocating channel %p which is already built.\n", dtc); return 0; } return do_channel_allocate(dtc); } +static void +wctc4xxp_disable_polling(struct wcdte *wc) +{ + clear_bit(DTE_POLLING, &wc->flags); + wctc4xxp_enable_interrupts(wc); +} + static int wctc4xxp_operation_release(struct zt_transcoder_channel *dtc) { @@ -1568,6 +1927,7 @@ wctc4xxp_operation_release(struct zt_transcoder_channel *dtc) struct channel_pvt *compl_cpvt; struct channel_pvt *cpvt = dtc->pvt; struct wcdte *wc = cpvt->wc; + int packets_received, packets_sent; BUG_ON(!cpvt); BUG_ON(!wc); @@ -1578,34 +1938,54 @@ wctc4xxp_operation_release(struct zt_transcoder_channel *dtc) return -EIO; } +#ifndef DEBUG_WCTC4XXP down(&wc->chansem); +#else + if (down_interruptible(&wc->chansem)) + return -EINTR; +#endif + + atomic_dec(&wc->open_channels); + if (atomic_read(&wc->open_channels) < POLLING_CALL_THRESHOLD) { + if (test_bit(DTE_POLLING, &wc->flags)) + wctc4xxp_disable_polling(wc); + } + + packets_received = atomic_read(&cpvt->stats.packets_received); + packets_sent = atomic_read(&cpvt->stats.packets_sent); + + if ((packets_sent - packets_received) > 5) { + DTE_DEBUG(DTE_DEBUG_GENERAL, "%s channel %d sent %d packets " + "and received %d packets.\n", (cpvt->encoder) ? + "encoder" : "decoder", cpvt->chan_out_num, + packets_sent, packets_received); + } /* Remove any packets that are waiting on the outbound queue. */ wctc4xxp_cleanup_channel_private(wc, dtc); index = cpvt->timeslot_in_num/2; BUG_ON(index >= wc->numchannels); - if (ENCODER == cpvt->encoder) { + if (cpvt->encoder) compl_dtc = &(wc->udecode->channels[index]); - } else { + else compl_dtc = &(wc->uencode->channels[index]); - } BUG_ON(!compl_dtc); if (!zt_tc_is_built(compl_dtc)) { - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing a channel that was never built.\n"); res = 0; goto error_exit; } /* If the channel complement (other half of the encoder/decoder pair) is - * being used.*/ + * being used. */ if (zt_tc_is_busy(compl_dtc)) { res = 0; goto error_exit; } - if ((res = wctc4xxp_destroy_channel_pair(wc, cpvt))) { - WARN_ON(1); + res = wctc4xxp_destroy_channel_pair(wc, cpvt); + if (res) goto error_exit; - } + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, "Releasing channel: %p\n", dtc); /* Mark this channel as not built */ zt_tc_clear_built(dtc); @@ -1623,28 +2003,78 @@ error_exit: return res; } -static inline struct tcb* +static inline struct tcb* get_ready_cmd(struct zt_transcoder_channel *dtc) { struct channel_pvt *cpvt = dtc->pvt; struct tcb *cmd; - spin_lock_bh(&cpvt->lock); + unsigned long flags; + spin_lock_irqsave(&cpvt->lock, flags); if (!list_empty(&cpvt->rx_queue)) { WARN_ON(!zt_tc_is_data_waiting(dtc)); - cmd = list_entry(cpvt->rx_queue.next, struct tcb, node); + cmd = list_entry(cpvt->rx_queue.next, struct tcb, node); list_del_init(&cmd->node); } else { cmd = NULL; } - if (list_empty(&cpvt->rx_queue)) { + if (list_empty(&cpvt->rx_queue)) zt_tc_clear_data_waiting(dtc); - } - spin_unlock_bh(&cpvt->lock); + spin_unlock_irqrestore(&cpvt->lock, flags); return cmd; } +static int +wctc4xxp_handle_receive_ring(struct wcdte *wc) +{ + struct tcb *cmd; + unsigned long flags; + unsigned int count = 0; + + /* If we can't grab this lock, another thread must already be checking + * the receive ring...so we should just finish up, and we'll try again + * later. */ + if (!spin_trylock_irqsave(&wc->rx_lock, flags)) + return 0; + + while ((cmd = wctc4xxp_retrieve(wc->rxd))) { + ++count; + spin_lock(&wc->rx_list_lock); + list_add_tail(&cmd->node, &wc->rx_list); + spin_unlock(&wc->rx_list_lock); + cmd = __alloc_cmd(SFRAME_SIZE, GFP_ATOMIC, 0); + if (!cmd) { + DTE_PRINTK(ERR, "Out of memory in %s.\n", __func__); + } else { + if (wctc4xxp_submit(wc->rxd, cmd)) { + DTE_PRINTK(ERR, "Failed submit in %s\n", + __func__); + free_cmd(cmd); + } + } + } + spin_unlock_irqrestore(&wc->rx_lock, flags); + return count; +} + +static void +__wctc4xxp_polling(struct wcdte *wc) +{ + if (wctc4xxp_handle_receive_ring(wc)) + schedule_work(&wc->deferred_work); +} + +static void +wctc4xxp_polling(unsigned long data) +{ + struct wcdte *wc = (struct wcdte *)data; + __wctc4xxp_polling(wc); + if (test_bit(DTE_POLLING, &wc->flags)) + mod_timer(&wc->polling, jiffies + 1); +} + + /* Called with a buffer in which to copy a transcoded frame. */ -static ssize_t +static ssize_t wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos) { ssize_t ret; @@ -1654,7 +2084,6 @@ wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos) struct tcb *cmd; struct rtp_packet *packet; ssize_t payload_bytes; - u16 rtp_eseq; BUG_ON(!dtc); BUG_ON(!cpvt); @@ -1665,52 +2094,43 @@ wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos) return -EIO; } - if (!(cmd = get_ready_cmd(dtc))) { + cmd = get_ready_cmd(dtc); + if (!cmd) { if (file->f_flags & O_NONBLOCK) { return -EAGAIN; } else { - ret = wait_event_interruptible(dtc->ready, - zt_tc_is_data_waiting(dtc)); + ret = wait_event_interruptible(dtc->ready, + zt_tc_is_data_waiting(dtc)); if (-ERESTARTSYS == ret) { /* Signal interrupted the wait */ return -EINTR; } else { /* List went not empty. */ cmd = get_ready_cmd(dtc); - } + } } } BUG_ON(!cmd); packet = cmd->data; - - payload_bytes = be16_to_cpu(packet->udphdr.len) - sizeof(struct rtphdr) - - sizeof(struct udphdr); + + payload_bytes = be16_to_cpu(packet->udphdr.len) - + sizeof(struct rtphdr) - sizeof(struct udphdr); if (count < payload_bytes) { - DTE_PRINTK(ERR, "Insufficient room to copy read data. Dropping packet.\n"); + if (printk_ratelimit()) { + DTE_PRINTK(ERR, + "Cannot copy %zd bytes into %zd byte user " \ + "buffer.\n", payload_bytes, count); + } free_cmd(cmd); return -EFBIG; } atomic_inc(&cpvt->stats.packets_received); - if (!(cpvt->last_dte_seqno)) { - cpvt->last_dte_seqno = be16_to_cpu(packet->rtphdr.seqno); - } else { - rtp_eseq = ++cpvt->last_dte_seqno; - cpvt->last_dte_seqno = be16_to_cpu(packet->rtphdr.seqno); - if (rtp_eseq != cpvt->last_dte_seqno) - DTE_DEBUG(DTE_DEBUG_GENERAL, - "Bad seqno from DTE! [%04X][%d][%d][%d]\n", - be16_to_cpu(packet->rtphdr.seqno), - (be16_to_cpu(packet->udphdr.dest) - 0x5000), - be16_to_cpu(packet->rtphdr.seqno), - rtp_eseq); - } - if (unlikely(copy_to_user(frame, &packet->payload[0], payload_bytes))) { - DTE_PRINTK(ERR, "Failed to copy data in %s\n", __FUNCTION__); + DTE_PRINTK(ERR, "Failed to copy data in %s\n", __func__); free_cmd(cmd); return -EFAULT; } @@ -1720,9 +2140,10 @@ wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos) return payload_bytes; } -/* Called with a frame in the srcfmt that is to be transcoded into the dstfmt. */ -static ssize_t -wctc4xxp_write(struct file *file, const char __user *frame, size_t count, loff_t *ppos) +/* Called with a frame in the srcfmt to be transcoded into the dstfmt. */ +static ssize_t +wctc4xxp_write(struct file *file, const char __user *frame, + size_t count, loff_t *ppos) { struct zt_transcoder_channel *dtc = file->private_data; struct channel_pvt *cpvt = dtc->pvt; @@ -1732,72 +2153,84 @@ wctc4xxp_write(struct file *file, const char __user *frame, size_t count, loff_t BUG_ON(!cpvt); BUG_ON(!wc); - if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) { - /* The shudown flags can also be set if there is a - * catastrophic failure. */ + if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) return -EIO; - } - if (!test_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags)) { + if (!test_bit(ZT_TC_FLAG_CHAN_BUILT, &dtc->flags)) return -EAGAIN; - } if (count < 2) { - DTE_DEBUG(DTE_DEBUG_GENERAL, - "Cannot request to transcode a packet that is less than 2 bytes.\n"); + DTE_DEBUG(DTE_DEBUG_GENERAL, + "Cannot request to transcode a packet that is less than " \ + "2 bytes.\n"); return -EINVAL; } if (unlikely(count > SFRAME_SIZE - sizeof(struct rtp_packet))) { - DTE_DEBUG(DTE_DEBUG_GENERAL, + DTE_DEBUG(DTE_DEBUG_GENERAL, "Cannot transcode packet of %Zu bytes. This exceeds the " \ - "maximum size of %Zu bytes.\n", count, + "maximum size of %Zu bytes.\n", count, SFRAME_SIZE - sizeof(struct rtp_packet)); return -EINVAL; } if (ZT_FORMAT_G723_1 == dtc->srcfmt) { if ((G723_5K_BYTES != count) && (G723_6K_BYTES != count)) { - DTE_DEBUG(DTE_DEBUG_GENERAL, + DTE_DEBUG(DTE_DEBUG_GENERAL, "Trying to transcode packet into G723 format " \ "that is %Zu bytes instead of the expected " \ - "%d/%d bytes.\n", count, G723_5K_BYTES, G723_6K_BYTES); + "%d/%d bytes.\n", count, G723_5K_BYTES, + G723_6K_BYTES); return -EINVAL; } cpvt->timestamp += G723_SAMPLES; } else if (ZT_FORMAT_G723_1 == dtc->dstfmt) { - cpvt->timestamp += G723_SAMPLES; + cpvt->timestamp = G723_SAMPLES; } else { /* Same for ulaw and alaw */ cpvt->timestamp += G729_SAMPLES; } - if (!(cmd = wctc4xxp_create_rtp_cmd(wc, dtc, count))) { + cmd = wctc4xxp_create_rtp_cmd(wc, dtc, count); + if (!cmd) return -ENOMEM; - } /* Copy the data directly from user space into the command buffer. */ - if (copy_from_user(&((struct rtp_packet*)(cmd->data))->payload[0], frame, count)) { + if (copy_from_user(&((struct rtp_packet *)(cmd->data))->payload[0], + frame, count)) { DTE_PRINTK(ERR, "Failed to copy packet from userspace.\n"); free_cmd(cmd); return -EFAULT; } cpvt->seqno += 1; - DTE_DEBUG(DTE_DEBUG_RTP_TX, + DTE_DEBUG(DTE_DEBUG_RTP_TX, "Sending packet of %Zu byte on channel (%p).\n", count, dtc); - wctc4xxp_transmit_cmd(wc, cmd); atomic_inc(&cpvt->stats.packets_sent); + wctc4xxp_transmit_cmd(wc, cmd); + + if (test_bit(DTE_POLLING, &wc->flags)) { +#if HZ == 100 + __wctc4xxp_polling(wc); +#else + if (jiffies != wc->jiffies_at_last_poll) { + wc->jiffies_at_last_poll = jiffies; + __wctc4xxp_polling(wc); + } +#endif + } + return count; } -static void +static void wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel) { struct tcb *cmd; struct csm_encaps_hdr *hdr; - if (!(cmd = __alloc_cmd(ALLOC_FLAGS, 0))) { + cmd = __alloc_cmd(sizeof(*hdr), ALLOC_FLAGS, 0); + if (!cmd) { WARN_ON(1); return; } @@ -1809,76 +2242,105 @@ wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel) hdr->control = 0xe0; hdr->channel = channel; - cmd->data_len = sizeof(*hdr); wctc4xxp_transmit_cmd(wc, cmd); } -static void +static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd) { - const struct csm_encaps_hdr *listhdr; - const struct csm_encaps_hdr *rxhdr; - struct tcb *pos; - struct tcb *temp; - + const struct csm_encaps_hdr *listhdr, *rxhdr; + struct tcb *pos, *temp; + unsigned long flags; + u32 handled = 0; rxhdr = cmd->data; - spin_lock_bh(&wc->cmd_list_lock); - list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) { + if (0xffff == rxhdr->channel) { + /* We received a duplicate response. */ + if (rxhdr->seq_num == wc->last_rx_seq_num) { + free_cmd(cmd); + return; + } + wc->last_rx_seq_num = rxhdr->seq_num; + } + + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_for_each_entry_safe(pos, temp, + &wc->waiting_for_response_list, node) { listhdr = pos->data; if ((listhdr->function == rxhdr->function) && (listhdr->channel == rxhdr->channel)) { + + spin_lock(&pos->lock); list_del_init(&pos->node); pos->flags &= ~(__WAIT_FOR_RESPONSE); - WARN_ON(pos->response); pos->response = cmd; - complete(&pos->complete); + /* If this isn't TX_COMPLETE yet, then this packet will + * be completed in service_tx_ring. */ + if (pos->flags & TX_COMPLETE) + complete(&pos->complete); + spin_unlock(&pos->lock); + handled = 1; + break; } } - spin_unlock_bh(&wc->cmd_list_lock); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); + + if (!handled) { + DTE_DEBUG(DTE_DEBUG_GENERAL, + "Freeing unhandled response ch:(%04x)\n", + be16_to_cpu(rxhdr->channel)); + free_cmd(cmd); + } } -static void +static void do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd) { - const struct csm_encaps_hdr *listhdr; - const struct csm_encaps_hdr *rxhdr; - struct tcb *pos; - struct tcb *temp; + const struct csm_encaps_hdr *listhdr, *rxhdr; + struct tcb *pos, *temp; + unsigned long flags; rxhdr = cmd->data; - spin_lock_bh(&wc->cmd_list_lock); - list_for_each_entry_safe(pos, temp, &wc->waiting_for_response_list, node) { + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_for_each_entry_safe(pos, temp, + &wc->waiting_for_response_list, node) { listhdr = pos->data; if (cpu_to_be16(0xefed) == listhdr->ethhdr.h_proto) { wc->seq_num = (rxhdr->seq_num + 1) & 0xff; WARN_ON(!(pos->flags & DO_NOT_AUTO_FREE)); + WARN_ON(!(pos->flags & TX_COMPLETE)); list_del_init(&pos->node); + WARN_ON(!(pos->flags & TX_COMPLETE)); complete(&pos->complete); - } else if ((listhdr->seq_num == rxhdr->seq_num) && + } else if ((listhdr->seq_num == rxhdr->seq_num) && (listhdr->channel == rxhdr->channel)) { + spin_lock(&pos->lock); if (pos->flags & __WAIT_FOR_RESPONSE) { pos->flags &= ~(__WAIT_FOR_ACK); + spin_unlock(&pos->lock); } else { list_del_init(&pos->node); if (pos->flags & DO_NOT_AUTO_FREE) { + WARN_ON(!(pos->flags & TX_COMPLETE)); complete(&pos->complete); + spin_unlock(&pos->lock); } else { + spin_unlock(&pos->lock); free_cmd(pos); } } break; - } + } } - spin_unlock_bh(&wc->cmd_list_lock); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); /* There is never a reason to store up the ack packets. */ free_cmd(cmd); } -static inline int +static inline int is_response(const struct csm_encaps_hdr *hdr) { return ((0x02 == hdr->type) || (0x04 == hdr->type)) ? 1 : 0; @@ -1898,7 +2360,7 @@ print_command(struct wcdte *wc, const struct tcb *cmd) DTE_PRINTK(DEBUG, "Failed print_command\n"); return; } - curlength = snprintf(buffer, BUFFER_SIZE, + curlength = snprintf(buffer, BUFFER_SIZE, "opcode: %04x seq: %02x control: %02x " "channel: %04x ", be16_to_cpu(hdr->op_code), hdr->seq_num, hdr->control, be16_to_cpu(hdr->channel)); @@ -1916,36 +2378,33 @@ print_command(struct wcdte *wc, const struct tcb *cmd) kfree(buffer); } -static void +static void receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd) { const struct csm_encaps_hdr *hdr = cmd->data; if (!(hdr->control & MESSAGE_PACKET)) { - - if (!(hdr->control & SUPPRESS_ACK)) { + if (!(hdr->control & SUPPRESS_ACK)) wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel); - } if (is_response(hdr)) { do_rx_response_packet(wc, cmd); } else if (0xc1 == hdr->type) { if (0x75 == hdr->class) { DTE_PRINTK(WARNING, - "Received alert (0x%04x) from dsp\n", + "Received alert (0x%04x) from dsp\n", le16_to_cpu(hdr->params[0])); } free_cmd(cmd); } else if (0xd4 == hdr->type) { if (hdr->params[0] != le16_to_cpu(0xffff)) { - DTE_PRINTK(WARNING, - "DTE Failed self test (%04x).\n", + DTE_PRINTK(WARNING, + "DTE Failed self test (%04x).\n", le16_to_cpu(hdr->params[0])); - } else if ((hdr->params[1] != le16_to_cpu(0x000c))&& - (hdr->params[1] != le16_to_cpu(0x010c))) - { - DTE_PRINTK(WARNING, - "Unexpected ERAM status (%04x).\n", + } else if ((hdr->params[1] != le16_to_cpu(0x000c)) && + (hdr->params[1] != le16_to_cpu(0x010c))) { + DTE_PRINTK(WARNING, + "Unexpected ERAM status (%04x).\n", le16_to_cpu(hdr->params[1])); } else { wctc4xxp_set_ready(wc); @@ -1957,7 +2416,8 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd) print_command(wc, cmd); free_cmd(cmd); } else { - DTE_PRINTK(WARNING, "Unknown command type received. %02x\n", hdr->type); + DTE_PRINTK(WARNING, + "Unknown command type received. %02x\n", hdr->type); free_cmd(cmd); } } else { @@ -1965,23 +2425,35 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd) } } -static void +static void queue_rtp_packet(struct wcdte *wc, struct tcb *cmd) { - int index; + unsigned index; struct zt_transcoder_channel *dtc; struct channel_pvt *cpvt; struct rtp_packet *packet = cmd->data; + unsigned long flags; + + if (unlikely(ip_fast_csum((void *)(&packet->iphdr), + packet->iphdr.ihl))) { + DTE_DEBUG(DTE_DEBUG_GENERAL, + "Invalid checksum in RTP packet %04x\n", + ip_fast_csum((void *)(&packet->iphdr), + packet->iphdr.ihl)); + free_cmd(cmd); + return; + } index = (be16_to_cpu(packet->udphdr.dest) - 0x5000) / 2; - if (unlikely(index >= wc->numchannels)) { - DTE_PRINTK(ERR, "Invalid channel number in response from DTE.\n"); + if (unlikely(!(index < wc->numchannels))) { + DTE_PRINTK(ERR, + "Invalid channel number in response from DTE.\n"); free_cmd(cmd); return; } switch (packet->rtphdr.type) { - case 0x00: + case 0x00: case 0x08: dtc = &(wc->udecode->channels[index]); break; @@ -1991,32 +2463,32 @@ queue_rtp_packet(struct wcdte *wc, struct tcb *cmd) break; default: DTE_PRINTK(ERR, "Unknown codec in packet (0x%02x).\n",\ - packet->rtphdr.type); + packet->rtphdr.type); free_cmd(cmd); return; } cpvt = dtc->pvt; - spin_lock_bh(&cpvt->lock); + spin_lock_irqsave(&cpvt->lock, flags); list_add_tail(&cmd->node, &cpvt->rx_queue); zt_tc_set_data_waiting(dtc); - spin_unlock_bh(&cpvt->lock); + spin_unlock_irqrestore(&cpvt->lock, flags); zt_transcoder_alert(dtc); return; } -static inline void +static inline void wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd) { - const struct ethhdr *ethhdr = (const struct ethhdr*)(cmd->data); + const struct ethhdr *ethhdr = (const struct ethhdr *)(cmd->data); if (cpu_to_be16(ETH_P_IP) == ethhdr->h_proto) { queue_rtp_packet(wc, cmd); } else if (cpu_to_be16(ETH_P_CSM_ENCAPS) == ethhdr->h_proto) { receive_csm_encaps_packet(wc, cmd); } else { - DTE_PRINTK(WARNING, - "Unknown packet protocol recieved: %04x.\n", + DTE_DEBUG(DTE_DEBUG_GENERAL, + "Unknown packet protocol recieved: %04x.\n", be16_to_cpu(ethhdr->h_proto)); free_cmd(cmd); } @@ -2025,36 +2497,41 @@ wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd) static inline void service_tx_ring(struct wcdte *wc) { struct tcb *cmd; - /* - * Process the transmit packets - */ + unsigned long flags; while ((cmd = wctc4xxp_retrieve(wc->txd))) { + spin_lock_irqsave(&cmd->lock, flags); + cmd->flags |= TX_COMPLETE; if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) { /* If we're not waiting for an ACK or Response from * the DTE, this message should not be sitting on any * lists. */ WARN_ON(!list_empty(&cmd->node)); if (DO_NOT_AUTO_FREE & cmd->flags) { + spin_unlock_irqrestore(&cmd->lock, flags); + WARN_ON(!(cmd->flags & TX_COMPLETE)); complete(&cmd->complete); } else { + spin_unlock_irqrestore(&cmd->lock, flags); free_cmd(cmd); } + } else { + spin_unlock_irqrestore(&cmd->lock, flags); } + /* We've freed up a spot in the hardware ring buffer. If * another packet is queued up, let's submit it to the * hardware. */ - spin_lock_bh(&wc->cmd_list_lock); + spin_lock_irqsave(&wc->cmd_list_lock, flags); if (!list_empty(&wc->cmd_list)) { cmd = list_entry(wc->cmd_list.next, struct tcb, node); list_del_init(&cmd->node); } else { cmd = NULL; } - spin_unlock_bh(&wc->cmd_list_lock); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); - if (cmd) { + if (cmd) wctc4xxp_transmit_cmd(wc, cmd); - } } } @@ -2063,12 +2540,11 @@ static inline void service_rx_ring(struct wcdte *wc) struct tcb *cmd; unsigned long flags; LIST_HEAD(local_list); - spin_lock_irqsave(&wc->rx_list_lock, flags); list_splice_init(&wc->rx_list, &local_list); spin_unlock_irqrestore(&wc->rx_list_lock, flags); - /* + /* * Process the received packets */ while (!list_empty(&local_list)) { @@ -2081,14 +2557,14 @@ static inline void service_rx_ring(struct wcdte *wc) wctc4xxp_receive_demand_poll(wc); } -static inline void service_dte(struct wcdte *wc) +static inline void service_dte(struct wcdte *wc) { service_tx_ring(wc); service_rx_ring(wc); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void deferred_work_func(void *param) { struct wcdte *wc = param; @@ -2103,7 +2579,6 @@ static void deferred_work_func(struct work_struct *work) ZAP_IRQ_HANDLER(wctc4xxp_interrupt) { struct wcdte *wc = dev_id; - struct tcb *cmd; u32 ints; u32 reg; #define TX_COMPLETE_INTERRUPT 0x00000001 @@ -2114,40 +2589,29 @@ ZAP_IRQ_HANDLER(wctc4xxp_interrupt) ints = __wctc4xxp_getctl(wc, 0x0028); ints &= wc->intmask; - + if (!ints) return IRQ_NONE; if (likely(ints & NORMAL_INTERRUPTS)) { reg = 0; - if (ints & TX_COMPLETE_INTERRUPT) { + if (ints & TX_COMPLETE_INTERRUPT) reg |= TX_COMPLETE_INTERRUPT; - } + if (ints & RX_COMPLETE_INTERRUPT) { - while ((cmd = wctc4xxp_retrieve(wc->rxd))) { - spin_lock(&wc->rx_list_lock); - list_add_tail(&cmd->node, &wc->rx_list); - spin_unlock(&wc->rx_list_lock); - - cmd = __alloc_cmd(GFP_ATOMIC, 0); - if (!cmd) { - DTE_PRINTK(ERR, "Out of memory in %s.\n", __FUNCTION__); - } else { - if (wctc4xxp_submit(wc->rxd, cmd)) { - DTE_PRINTK(ERR, "Failed submit in %s\n", __FUNCTION__); - free_cmd(cmd); - } - } - } + wctc4xxp_handle_receive_ring(wc); reg |= RX_COMPLETE_INTERRUPT; } + #if DEFERRED_PROCESSING == WORKQUEUE schedule_work(&wc->deferred_work); #elif DEFERRED_PROCESSING == INTERRUPT -#error "You will need to change the locks if you want to run the processing in the interrupt handler." +#error "You will need to change the locks if you want to run the processing " \ + "in the interrupt handler." #else #error "Define a deferred processing function in kernel/wctc4xxp/wctc4xxp.h" #endif + __wctc4xxp_setctl(wc, 0x0028, reg); } else { if ((ints & 0x00008000) && debug) @@ -2170,9 +2634,6 @@ ZAP_IRQ_HANDLER(wctc4xxp_interrupt) if ((ints & 0x00000008) && debug) DTE_PRINTK(INFO, "Jabber Timer Time-out INT\n"); - if ((ints & 0x00000004) && debug) - ; // printk("wcdte: Transmit Descriptor Unavailable INT\n"); - if ((ints & 0x00000002) && debug) DTE_PRINTK(INFO, "Transmit Processor Stopped INT\n"); @@ -2182,7 +2643,7 @@ ZAP_IRQ_HANDLER(wctc4xxp_interrupt) return IRQ_HANDLED; } -static int +static int wctc4xxp_hardware_init(struct wcdte *wc) { /* Hardware stuff */ @@ -2190,16 +2651,15 @@ wctc4xxp_hardware_init(struct wcdte *wc) unsigned long newjiffies; u8 cache_line_size; const u32 DEFAULT_PCI_ACCESS = 0xfff80000; - + /* Enable I/O Access */ pci_read_config_dword(wc->pdev, 0x0004, ®); reg |= 0x00000007; pci_write_config_dword(wc->pdev, 0x0004, reg); - if (pci_read_config_byte(wc->pdev, 0x0c, &cache_line_size)) { - /* \todo Print an error message... */ + if (pci_read_config_byte(wc->pdev, 0x0c, &cache_line_size)) return -EIO; - } + switch (cache_line_size) { case 0x08: reg = DEFAULT_PCI_ACCESS | (0x1 << 14); @@ -2207,66 +2667,52 @@ wctc4xxp_hardware_init(struct wcdte *wc) case 0x10: reg = DEFAULT_PCI_ACCESS | (0x2 << 14); break; - case 0x20: + case 0x20: reg = DEFAULT_PCI_ACCESS | (0x3 << 14); break; default: reg = 0xfe584202; break; } - + reg |= ((wc->txd->padding / sizeof(u32)) << 2) & 0x7c; /* Reset the DTE... */ wctc4xxp_setctl(wc, 0x0000, reg | 1); newjiffies = jiffies + HZ; /* One second timeout */ /* ...and wait for it to come out of reset. */ - while(((wctc4xxp_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)) { + while (((wctc4xxp_getctl(wc, 0x0000)) & 0x00000001) && + (newjiffies > jiffies)) msleep(1); - } - wctc4xxp_setctl(wc, 0x0000, reg); - - /* Configure watchdogs, access, etc */ - wctc4xxp_setctl(wc, 0x0030, 0x00280048); - wctc4xxp_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */); + wctc4xxp_setctl(wc, 0x0000, reg | 0x60000); + /* Configure watchdogs, access, etc */ + wctc4xxp_setctl(wc, 0x0030, 0x00280040); + wctc4xxp_setctl(wc, 0x0078, 0x00000013); reg = wctc4xxp_getctl(wc, 0x00fc); wctc4xxp_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); - reg = wctc4xxp_getctl(wc, 0x00fc); - return 0; } -static void -wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask) -{ - wc->intmask = intmask; - wctc4xxp_setctl(wc, 0x0038, intmask); -} - -static void -wctc4xxp_enable_interrupts(struct wcdte *wc) -{ - wctc4xxp_setintmask(wc, 0x000180c0); -} - -static void +static void wctc4xxp_start_dma(struct wcdte *wc) { int res; int i; u32 reg; struct tcb *cmd; - - for (i = 0; i < DRING_SIZE; ++i) { - if (!(cmd = alloc_cmd())) { + + for (i = 0; i < DRING_SIZE; ++i) { + cmd = alloc_cmd(SFRAME_SIZE); + if (!cmd) { WARN_ALWAYS(); return; } - cmd->data_len = SFRAME_SIZE; - if ((res=wctc4xxp_submit(wc->rxd, cmd))) { + WARN_ON(SFRAME_SIZE != cmd->data_len); + res = wctc4xxp_submit(wc->rxd, cmd); + if (res) { /* When we're starting the DMA, we should always be * able to fill the ring....so something is wrong * here. */ @@ -2281,14 +2727,14 @@ wctc4xxp_start_dma(struct wcdte *wc) /* Start receiver/transmitter */ reg = wctc4xxp_getctl(wc, 0x0030); - wctc4xxp_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */ + wctc4xxp_setctl(wc, 0x0030, reg | 0x00002002); wctc4xxp_receive_demand_poll(wc); reg = wctc4xxp_getctl(wc, 0x0028); wctc4xxp_setctl(wc, 0x0028, reg); } -static void +static void wctc4xxp_stop_dma(struct wcdte *wc) { /* Disable interrupts and reset */ @@ -2305,18 +2751,11 @@ wctc4xxp_stop_dma(struct wcdte *wc) newjiffies = jiffies + HZ; /* One second timeout */ /* We'll wait here for the part to come out of reset */ - while(((wctc4xxp_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)) { - msleep(1); - } + while (((wctc4xxp_getctl(wc, 0x0000)) & 0x00000001) && + (newjiffies > jiffies)) + msleep(1); } -static void -wctc4xxp_disable_interrupts(struct wcdte *wc) -{ - /* Disable interrupts */ - wctc4xxp_setintmask(wc, 0x00000000); - wctc4xxp_setctl(wc, 0x0084, 0x00000000); -} #define MDIO_SHIFT_CLK 0x10000 #define MDIO_DATA_WRITE1 0x20000 @@ -2324,7 +2763,7 @@ wctc4xxp_disable_interrupts(struct wcdte *wc) #define MDIO_ENB_IN 0x40000 #define MDIO_DATA_READ 0x80000 -static int +static int wctc4xxp_read_phy(struct wcdte *wc, int location) { int i; @@ -2333,28 +2772,33 @@ wctc4xxp_read_phy(struct wcdte *wc, int location) int retval = 0; /* Establish sync by sending at least 32 logic ones. */ - for (i = 32; i >= 0; i--) { - wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); + for (i = 32; i >= 0; --i) { + wctc4xxp_setctl(wc, mdio_addr, + MDIO_ENB | MDIO_DATA_WRITE1); wctc4xxp_getctl(wc, mdio_addr); - wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + wctc4xxp_setctl(wc, mdio_addr, + MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Shift the read command bits out. */ - for (i = 17; i >= 0; i--) { + for (i = 17; i >= 0; --i) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval); wctc4xxp_getctl(wc, mdio_addr); - wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); + wctc4xxp_setctl(wc, mdio_addr, + MDIO_ENB | dataval | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { + for (i = 19; i > 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN); wctc4xxp_getctl(wc, mdio_addr); - retval = (retval << 1) | ((wctc4xxp_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + retval = (retval << 1) | + ((wctc4xxp_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? + 1 : 0); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } @@ -2362,7 +2806,7 @@ wctc4xxp_read_phy(struct wcdte *wc, int location) return retval; } -static void +static void wctc4xxp_write_phy(struct wcdte *wc, int location, int value) { int i; @@ -2370,22 +2814,24 @@ wctc4xxp_write_phy(struct wcdte *wc, int location, int value) long mdio_addr = 0x0048; /* Establish sync by sending 32 logic ones. */ - for (i = 32; i >= 0; i--) { + for (i = 32; i >= 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); wctc4xxp_getctl(wc, mdio_addr); - wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + wctc4xxp_setctl(wc, mdio_addr, + MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { + for (i = 31; i >= 0; --i) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval); wctc4xxp_getctl(wc, mdio_addr); - wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); + wctc4xxp_setctl(wc, mdio_addr, + MDIO_ENB | dataval | MDIO_SHIFT_CLK); wctc4xxp_getctl(wc, mdio_addr); } /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { + for (i = 2; i > 0; --i) { wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN); wctc4xxp_getctl(wc, mdio_addr); wctc4xxp_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); @@ -2401,7 +2847,7 @@ wctc4xxp_wait_for_link(struct wcdte *wc) unsigned int delay_count = 0; do { reg = wctc4xxp_getctl(wc, 0x00fc); - mdelay(2); + msleep(2); delay_count++; if (delay_count >= 5000) { @@ -2412,7 +2858,7 @@ wctc4xxp_wait_for_link(struct wcdte *wc) return 0; } -static int +static int wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware) { unsigned int byteloc; @@ -2422,20 +2868,14 @@ wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware) byteloc = 17; - if (!(cmd = alloc_cmd())) { + cmd = alloc_cmd(SFRAME_SIZE); + if (!cmd) return -ENOMEM; - } - if (MAX_FRAME_SIZE > cmd->data_len) { - cmd->data = kmalloc(MAX_FRAME_SIZE, GFP_KERNEL); - if (!(cmd->data)) { - free_cmd(cmd); - return -ENOMEM; - } - cmd->data_len = MAX_FRAME_SIZE; - } + while (byteloc < (firmware->size-20)) { last_byteloc = byteloc; - length = (firmware->data[byteloc] << 8) | firmware->data[byteloc+1]; + length = (firmware->data[byteloc] << 8) | + firmware->data[byteloc+1]; byteloc += 2; cmd->data_len = length; BUG_ON(length > cmd->data_len); @@ -2449,7 +2889,7 @@ wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware) DTE_PRINTK(ERR, "Failed to load firmware.\n"); return -EIO; } - } + } free_cmd(cmd); if (!wait_event_timeout(wc->waitq, wctc4xxp_is_ready(wc), 15*HZ)) { DTE_PRINTK(ERR, "Failed to boot firmware.\n"); @@ -2465,22 +2905,22 @@ wctc4xxp_turn_off_booted_led(struct wcdte *wc) int reg; /* Turn off auto negotiation */ wctc4xxp_write_phy(wc, 0, 0x2100); - DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n", + DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n", wctc4xxp_read_phy(wc, 0)); /* Set reset */ wctc4xxp_setctl(wc, 0x00A0, 0x04000000); /* Wait 4 ms to ensure processor reset */ - mdelay(4); + msleep(4); /* Clear reset */ wctc4xxp_setctl(wc, 0x00A0, 0x04080000); /* Wait for the ethernet link */ - if ((ret = wctc4xxp_wait_for_link(wc))) { + ret = wctc4xxp_wait_for_link(wc); + if (ret) return ret; - } /* Turn off booted LED */ wctc4xxp_setctl(wc, 0x00A0, 0x04084000); @@ -2492,174 +2932,140 @@ wctc4xxp_turn_off_booted_led(struct wcdte *wc) return ret; } -static void +static void wctc4xxp_turn_on_booted_led(struct wcdte *wc) { wctc4xxp_setctl(wc, 0x00A0, 0x04080000); } -static int +static int wctc4xxp_boot_processor(struct wcdte *wc, const struct firmware *firmware) { int ret; wctc4xxp_turn_off_booted_led(wc); - if ((ret = wctc4xxp_load_firmware(wc, firmware))) { + ret = wctc4xxp_load_firmware(wc, firmware); + if (ret) return ret; - } - + wctc4xxp_turn_on_booted_led(wc); - DTE_DEBUG(DTE_DEBUG_GENERAL, "Successfully booted DTE processor.\n"); + DTE_DEBUG(DTE_DEBUG_GENERAL, "Successfully booted DTE processor.\n"); + return 0; +} + +static int +setup_half_channel(struct channel_pvt *pvt, struct tcb *cmd, u16 length) +{ + if (send_set_ip_hdr_channel_cmd(pvt, cmd)) + return -EIO; + if (send_voip_vceopt_cmd(pvt, cmd, length)) + return -EIO; + if (send_voip_tonectl_cmd(pvt, cmd)) + return -EIO; + if (send_voip_dtmfopt_cmd(pvt, cmd)) + return -EIO; + if (send_voip_indctrl_cmd(pvt, cmd)) + return -EIO; return 0; } -static int -wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt, +static int +wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt, u8 simple, u8 complicated) { - int res; - int length; - u8 chan1, chan2; - struct zt_transcoder_channel *dtc1, *dtc2; - struct channel_pvt *cpvt1, *cpvt2; - /* \todo what do these part variable names mean? */ - unsigned int timeslot; - unsigned int part2_id; + struct channel_pvt *encoder_pvt, *decoder_pvt; + u16 encoder_timeslot, decoder_timeslot; + u16 encoder_channel, decoder_channel; + u16 length; struct tcb *cmd; - const struct csm_encaps_hdr *hdr; - + cmd = alloc_cmd(SFRAME_SIZE); + if (!cmd) + return -ENOMEM; + BUG_ON(!wc || !cpvt); if (cpvt->encoder) { - timeslot = cpvt->timeslot_in_num; - part2_id = cpvt->timeslot_out_num; + encoder_timeslot = cpvt->timeslot_in_num; + decoder_timeslot = cpvt->timeslot_out_num; } else { u8 temp; - timeslot = cpvt->timeslot_out_num; - part2_id = cpvt->timeslot_in_num; + encoder_timeslot = cpvt->timeslot_out_num; + decoder_timeslot = cpvt->timeslot_in_num; temp = simple; simple = complicated; complicated = temp; } - length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH : - (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0; - - if (!(cmd = wctc4xxp_create_channel_cmd(wc, timeslot))) { - return -ENOMEM; - } - if ((res=wctc4xxp_transmit_cmd_and_wait(wc, cmd))) { - free_cmd(cmd); - return res; - } - free_cmd(cmd); + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "DTE is using the following channels encoder_channel: " \ + "%d decoder_channel: %d\n", encoder_channel, decoder_channel); - cmd = wctc4xxp_create_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, timeslot)); - if ((res=wctc4xxp_transmit_cmd_and_wait(wc,cmd))) { - free_cmd(cmd); - return res; - } - WARN_ON(!cmd->response); - hdr = (const struct csm_encaps_hdr*)cmd->response->data; - chan1 = le16_to_cpu(hdr->params[0]);; - free_cmd(cmd); + BUG_ON(encoder_timeslot/2 >= wc->numchannels); + BUG_ON(decoder_timeslot/2 >= wc->numchannels); + encoder_pvt = wc->uencode->channels[encoder_timeslot/2].pvt; + decoder_pvt = wc->udecode->channels[decoder_timeslot/2].pvt; + BUG_ON(!encoder_pvt); + BUG_ON(!decoder_pvt); - if (!(cmd = wctc4xxp_create_channel_cmd(wc, part2_id))) { - return -ENOMEM; - } - if ((res = __wctc4xxp_send_cmd(wc, cmd))) { - return res; - } - cmd = wctc4xxp_create_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id)); - cmd->flags |= WAIT_FOR_RESPONSE; - if ((res=wctc4xxp_transmit_cmd_and_wait(wc,cmd))) { - return res; - } - WARN_ON(!cmd->response); - hdr = (const struct csm_encaps_hdr*)cmd->response->data; - chan2 = le16_to_cpu(hdr->params[0]);; - free_cmd(cmd); + WARN_ON(encoder_timeslot == decoder_timeslot); + /* First, let's create two channels, one for the simple -> complex + * encoder and another for the complex->simple decoder. */ + if (send_create_channel_cmd(wc, cmd, encoder_timeslot, + &encoder_channel)) + goto error_exit; - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, - "DTE is using the following channels chan1: %d chan2: %d\n", chan1, chan2); + if (send_create_channel_cmd(wc, cmd, decoder_timeslot, + &decoder_channel)) + goto error_exit; - BUG_ON(timeslot/2 >= wc->numchannels); - BUG_ON(part2_id/2 >= wc->numchannels); - dtc1 = &(wc->uencode->channels[timeslot/2]); - dtc2 = &(wc->udecode->channels[part2_id/2]); - cpvt1 = dtc1->pvt; - cpvt2 = dtc2->pvt; - BUG_ON(!cpvt1); - BUG_ON(!cpvt2); + length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH : + (DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0; - /* Configure complex channel */ - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(cpvt1->cmd_seqno++, chan1, part2_id, timeslot)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(cpvt1->cmd_seqno++, chan1, length, 0)))) { - return res; - } - /* Configure simple channel */ - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(cpvt2->cmd_seqno++, chan2, timeslot, part2_id)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(cpvt2->cmd_seqno++, chan2, length, 0)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_TONECTL(cpvt1->cmd_seqno++, chan1)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(cpvt1->cmd_seqno++, chan1)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_TONECTL(cpvt2->cmd_seqno++, chan2)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(cpvt2->cmd_seqno++, chan2)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(cpvt1->cmd_seqno++, chan1)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(cpvt2->cmd_seqno++, chan2)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA(cpvt1->cmd_seqno++, chan1, complicated)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA(cpvt2->cmd_seqno++, chan2, simple)))) { - return res; - } + WARN_ON(encoder_channel == decoder_channel); + /* Now set all the default parameters for the encoder. */ + encoder_pvt->chan_in_num = encoder_channel; + encoder_pvt->chan_out_num = decoder_channel; + if (setup_half_channel(encoder_pvt, cmd, length)) + goto error_exit; - DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, - "DTE has completed setup and connected the two channels together.\n"); + /* And likewise for the decoder. */ + decoder_pvt->chan_in_num = decoder_channel; + decoder_pvt->chan_out_num = encoder_channel; + if (setup_half_channel(decoder_pvt, cmd, length)) + goto error_exit; + if (send_trans_connect_cmd(wc, cmd, encoder_channel, + decoder_channel, complicated, simple)) + goto error_exit; + if (send_voip_vopena_cmd(encoder_pvt, cmd, complicated)) + goto error_exit; + if (send_voip_vopena_cmd(decoder_pvt, cmd, simple)) + goto error_exit; - /* Save off the channels returned from the DTE so we can use then when - * sending the RTP packets. */ - if (ENCODER == cpvt->encoder) { - cpvt->chan_in_num = chan1; - cpvt->chan_out_num = chan2; - } else { - cpvt->chan_out_num = chan1; - cpvt->chan_in_num = chan2; - } + DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP, + "DTE has completed setup and connected the " \ + "two channels together.\n"); + free_cmd(cmd); return 0; +error_exit: + free_cmd(cmd); + return -EIO; } -static int +static int wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt) { struct zt_transcoder_channel *dtc1, *dtc2; - struct channel_pvt *cpvt1, *cpvt2; + struct channel_pvt *encoder_pvt, *decoder_pvt; int chan1, chan2, timeslot1, timeslot2; - int res; + struct tcb *cmd; + + cmd = alloc_cmd(SFRAME_SIZE); + if (!cmd) + return -ENOMEM; if (cpvt->encoder) { chan1 = cpvt->chan_in_num; @@ -2674,121 +3080,104 @@ wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt) } if (timeslot1/2 >= wc->numchannels || timeslot2/2 >= wc->numchannels) { - DTE_PRINTK(WARNING, - "Invalid channel numbers in %s. chan1:%d chan2: %d\n", - __FUNCTION__, timeslot1/2, timeslot2/2); + DTE_PRINTK(WARNING, + "Invalid channel numbers in %s. chan1:%d chan2: %d\n", + __func__, timeslot1/2, timeslot2/2); return 0; } dtc1 = &(wc->uencode->channels[timeslot1/2]); dtc2 = &(wc->udecode->channels[timeslot2/2]); - cpvt1 = dtc1->pvt; - cpvt2 = dtc2->pvt; - - /* Turn off both channels */ - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(cpvt1->cmd_seqno++, chan1)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(cpvt2->cmd_seqno++, chan2)))) { - return res; - } - - /* Disconnect the channels */ - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0)))) { - return res; - } + encoder_pvt = dtc1->pvt; + decoder_pvt = dtc2->pvt; - /* Remove the channels */ - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2)))) { - return res; - } + if (send_voip_vopena_close_cmd(encoder_pvt, cmd)) + goto error_exit; + if (send_voip_vopena_close_cmd(decoder_pvt, cmd)) + goto error_exit; + if (send_trans_disconnect_cmd(wc, cmd, chan1, chan2, 0, 0)) + goto error_exit; + if (send_destroy_channel_cmd(wc, cmd, chan1)) + goto error_exit; + if (send_destroy_channel_cmd(wc, cmd, chan2)) + goto error_exit; + free_cmd(cmd); return 0; +error_exit: + free_cmd(cmd); + return -1; } -static int +static int __wctc4xxp_setup_channels(struct wcdte *wc) { - int res; struct tcb *cmd; + int tdm_bus; - if (!(cmd = alloc_cmd())) { + cmd = alloc_cmd(SFRAME_SIZE); + if (!cmd) return -ENOMEM; - } - __wctc4xxp_create_set_arm_clk_cmd(wc, cmd); - res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); - free_cmd(cmd); - if (res) { - return res; - } + if (send_set_arm_clk_cmd(wc, cmd)) + goto error_exit; - cmd = wctc4xxp_create_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++)); - res = wctc4xxp_transmit_cmd_and_wait(wc, cmd); - free_cmd(cmd); - if (res) { - return res; - } + if (send_set_spu_clk_cmd(wc, cmd)) + goto error_exit; - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++)))) { - return res; - } + if (send_tdm_select_bus_mode_cmd(wc, cmd)) + goto error_exit; - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04)))) { - return res; - } - if ((res=wctc4xxp_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++)))) { - return res; + for (tdm_bus = 0; tdm_bus < 4; ++tdm_bus) { + if (send_supvsr_setup_tdm_parms(wc, cmd, tdm_bus)) + goto error_exit; } + + if (send_set_eth_header_cmd(wc, cmd, src_mac, dst_mac)) + goto error_exit; + + if (send_ip_service_config_cmd(wc, cmd)) + goto error_exit; + + if (send_arp_service_config_cmd(wc, cmd)) + goto error_exit; + + if (send_icmp_service_config_cmd(wc, cmd)) + goto error_exit; + + if (send_device_set_country_code_cmd(wc, cmd)) + goto error_exit; + + if (send_spu_features_control_cmd(wc, cmd, 0x02)) + goto error_exit; + + if (send_ip_options_cmd(wc, cmd)) + goto error_exit; + + if (send_spu_features_control_cmd(wc, cmd, 0x04)) + goto error_exit; + + if (send_tdm_opt_cmd(wc, cmd)) + goto error_exit; + + free_cmd(cmd); return 0; +error_exit: + free_cmd(cmd); + return -1; } -static int +static int wctc4xxp_setup_channels(struct wcdte *wc) { int ret; - +#ifndef DEBUG_WCTC4XXP down(&wc->chansem); +#else + if (down_interruptible(&wc->chansem)) + return -EINTR; +#endif ret = __wctc4xxp_setup_channels(wc); up(&wc->chansem); @@ -2802,81 +3191,73 @@ static void wctc4xxp_setup_file_operations(struct file_operations *fops) fops->write = wctc4xxp_write; } -static int -initialize_channel_pvt(struct wcdte *wc, encode_t type, - struct channel_pvt **cpvt) +static int +initialize_channel_pvt(struct wcdte *wc, int encoder, + struct channel_pvt **cpvt) { int chan; - *cpvt = kmalloc(sizeof(struct channel_pvt) * wc->numchannels, GFP_KERNEL); - if (!(*cpvt)) { + *cpvt = kmalloc(sizeof(struct channel_pvt) * wc->numchannels, + GFP_KERNEL); + if (!(*cpvt)) return -ENOMEM; - } - for (chan = 0; chan < wc->numchannels; ++chan) { - wctc4xxp_init_state((*cpvt) + chan, type, chan, wc); - } + for (chan = 0; chan < wc->numchannels; ++chan) + wctc4xxp_init_state((*cpvt) + chan, encoder, chan, wc); return 0; } -static int -initialize_transcoder(struct wcdte *wc, unsigned int srcfmts, - unsigned int dstfmts, struct channel_pvt *pvts, - struct zt_transcoder **zt) +static int +initialize_transcoder(struct wcdte *wc, unsigned int srcfmts, + unsigned int dstfmts, struct channel_pvt *pvts, + struct zt_transcoder **zt) { int chan; *zt = zt_transcoder_alloc(wc->numchannels); - if (!(*zt)) { + if (!(*zt)) return -ENOMEM; - } (*zt)->srcfmts = srcfmts; (*zt)->dstfmts = dstfmts; (*zt)->allocate = wctc4xxp_operation_allocate; (*zt)->release = wctc4xxp_operation_release; wctc4xxp_setup_file_operations(&((*zt)->fops)); - for (chan = 0; chan < wc->numchannels; ++chan) { + for (chan = 0; chan < wc->numchannels; ++chan) (*zt)->channels[chan].pvt = &pvts[chan]; - } return 0; } static int initialize_encoders(struct wcdte *wc, unsigned int complexfmts) { int res; - if ((res = initialize_channel_pvt(wc, ENCODER, &wc->encoders))) { + res = initialize_channel_pvt(wc, 1, &wc->encoders); + if (res) return res; - } - if ((res = initialize_transcoder(wc, - ZT_FORMAT_ULAW | ZT_FORMAT_ALAW, - complexfmts, - wc->encoders, - &wc->uencode))) - { + + res = initialize_transcoder(wc, ZT_FORMAT_ULAW | ZT_FORMAT_ALAW, + complexfmts, wc->encoders, &wc->uencode); + if (res) return res; - } sprintf(wc->uencode->name, "DTE Encoder"); return res; } -static int +static int initialize_decoders(struct wcdte *wc, unsigned int complexfmts) { int res; - if ((res = initialize_channel_pvt(wc, DECODER, &wc->decoders))) { + res = initialize_channel_pvt(wc, 0, &wc->decoders); + if (res) return res; - } - if ((res = initialize_transcoder(wc, - complexfmts, + + res = initialize_transcoder(wc, complexfmts, ZT_FORMAT_ULAW | ZT_FORMAT_ALAW, - wc->decoders, - &wc->udecode))) - { + wc->decoders, &wc->udecode); + if (res) return res; - } sprintf(wc->udecode->name, "DTE Decoder"); return res; } -static void +static void wctc4xxp_send_commands(struct wcdte *wc, struct list_head *to_send) { struct tcb *cmd; @@ -2887,38 +3268,43 @@ wctc4xxp_send_commands(struct wcdte *wc, struct list_head *to_send) } } -static void +static void wctc4xxp_watchdog(unsigned long data) { struct wcdte *wc = (struct wcdte *)data; struct tcb *cmd, *temp; LIST_HEAD(cmds_to_retry); const int MAX_RETRIES = 5; + int reschedule_timer = 0; - /* Check for any commands that have completed transmission. */ service_tx_ring(wc); spin_lock(&wc->cmd_list_lock); /* Go through the list of messages that are waiting for responses from * the DTE, and complete or retry any that have timed out. */ - list_for_each_entry_safe(cmd, temp, &wc->waiting_for_response_list, node) { + list_for_each_entry_safe(cmd, temp, + &wc->waiting_for_response_list, node) { if (time_after(jiffies, cmd->timeout)) { if (++cmd->retries > MAX_RETRIES) { if (!(cmd->flags & TX_COMPLETE)) { set_bit(DTE_SHUTDOWN, &wc->flags); spin_unlock(&wc->cmd_list_lock); wctc4xxp_stop_dma(wc); - DTE_PRINTK(ERR, "Board malfunctioning. Halting operation.\n"); + DTE_PRINTK(ERR, + "Board malfunctioning. " \ + "Halting operation.\n"); return; } - /* ERROR: We've retried the command and haven't - * received the ACK or the response. */ + /* ERROR: We've retried the command and + * haven't received the ACK or the response. + */ cmd->flags |= DTE_CMD_TIMEOUT; list_del_init(&cmd->node); complete(&cmd->complete); } else if (cmd->flags & TX_COMPLETE) { /* Move this to the local list because we're - * going to resend it once we free the locks */ + * going to resend it once we free the locks + */ list_move_tail(&cmd->node, &cmds_to_retry); cmd->flags &= ~(TX_COMPLETE); } else { @@ -2927,20 +3313,25 @@ wctc4xxp_watchdog(unsigned long data) * off any lists, lets just reset the timeout * and tell the hardware to look for another * command . */ - DTE_PRINTK(WARNING, "Retrying command that was " \ - "still on descriptor list.\n"); + DTE_PRINTK(WARNING, + "Retrying command that was " \ + "still on descriptor list.\n"); cmd->timeout = jiffies + HZ/4; wctc4xxp_transmit_demand_poll(wc); + reschedule_timer = 1; } - } + } } spin_unlock(&wc->cmd_list_lock); - wctc4xxp_send_commands(wc, &cmds_to_retry); + if (list_empty(&cmds_to_retry) && reschedule_timer) + mod_timer(&wc->watchdog, jiffies + HZ/2); + else if (!list_empty(&cmds_to_retry)) + wctc4xxp_send_commands(wc, &cmds_to_retry); } /** - * Insert an struct wcdte on the global list in sorted order + * Insert an struct wcdte on the global list in sorted order * */ static int __devinit @@ -2955,14 +3346,13 @@ wctc4xxp_add_to_device_list(struct wcdte *wc) /* Add the new entry before the one here */ list_add_tail(&wc->node, &cur->node); break; - } - else { + } else { ++pos; } } - if (list_empty(&wc->node)) { + /* If we didn't already add the new entry to the list, add it now */ + if (list_empty(&wc->node)) list_add_tail(&wc->node, &wctc4xxp_list); - } spin_unlock(&wctc4xxp_list_lock); return pos; } @@ -2973,19 +3363,19 @@ struct wctc4xxp_desc { int flags; }; -static struct wctc4xxp_desc wctc400p = { +static struct wctc4xxp_desc wctc400p = { .short_name = "tc400b", - .long_name = "Wildcard TC400P+TC400M", - .flags = 0, + .long_name = "Wildcard TC400P+TC400M", + .flags = 0, }; -static struct wctc4xxp_desc wctce400 = { +static struct wctc4xxp_desc wctce400 = { .short_name = "tce400", - .long_name = "Wildcard TCE400+TC400M", + .long_name = "Wildcard TCE400+TC400M", .flags = 0, }; -static int __devinit +static int __devinit wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res, reg, position_on_list; @@ -2997,37 +3387,38 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct firmware embedded_firmware; const struct firmware *firmware = &embedded_firmware; #if !defined(HOTPLUG_FIRMWARE) - extern void _binary_zt_fw_tc400m_bin_size; - extern u8 _binary_zt_fw_tc400m_bin_start[]; + extern void _binary_dahdi_fw_tc400m_bin_size; + extern u8 _binary_dahdi_fw_tc400m_bin_start[]; #else - static const char tc400m_firmware[] = "zaptel-fw-tc400m.bin"; + static const char tc400m_firmware[] = "dahdi-fw-tc400m.bin"; #endif /* ------------------------------------------------------------------ * Setup the pure software constructs internal to this driver. * --------------------------------------------------------------- */ - if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { + wc = kzalloc(sizeof(*wc), GFP_KERNEL); + if (!wc) return -ENOMEM; - } - memset(wc, 0, sizeof(*wc)); position_on_list = wctc4xxp_add_to_device_list(wc); - snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d", - d->short_name, position_on_list); + snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d", + d->short_name, position_on_list); wc->iobase = pci_resource_start(pdev, 0); wc->pdev = pdev; wc->pos = position_on_list; wc->variety = d->long_name; + wc->last_rx_seq_num = -1; init_MUTEX(&wc->chansem); spin_lock_init(&wc->reglock); spin_lock_init(&wc->cmd_list_lock); spin_lock_init(&wc->rx_list_lock); + spin_lock_init(&wc->rx_lock); INIT_LIST_HEAD(&wc->cmd_list); INIT_LIST_HEAD(&wc->waiting_for_response_list); INIT_LIST_HEAD(&wc->rx_list); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) INIT_WORK(&wc->deferred_work, deferred_work_func, wc); #else INIT_WORK(&wc->deferred_work, deferred_work_func); @@ -3037,7 +3428,7 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Keep track of whether we need to free the region */ if (!request_region(wc->iobase, 0xff, wc->board_name)) { /* \todo put in error message. */ - DTE_PRINTK(WARNING, + DTE_PRINTK(WARNING, "Failed to reserve the I/O ports for this device.\n"); return -EIO; } @@ -3050,36 +3441,39 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return -EIO; } - if (!(wc->txd = kmalloc(sizeof(*wc->txd), GFP_KERNEL))) { + wc->txd = kmalloc(sizeof(*wc->txd), GFP_KERNEL); + if (!wc->txd) { res = -ENOMEM; goto error_exit_swinit; } - if ((res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd, - 0xe0800000, - DMA_TO_DEVICE))) { + res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd, + 0xe0800000, DMA_TO_DEVICE); + if (res) goto error_exit_swinit; - } - if (!(wc->rxd = kmalloc(sizeof(*wc->rxd), GFP_KERNEL))) { + wc->rxd = kmalloc(sizeof(*wc->rxd), GFP_KERNEL); + if (!wc->rxd) { res = -ENOMEM; goto error_exit_swinit; } - if ((res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0, - DMA_FROM_DEVICE))) { + res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0, + DMA_FROM_DEVICE); + if (res) goto error_exit_swinit; - } #if defined(HOTPLUG_FIRMWARE) - if ((res = request_firmware(&firmware, tc400m_firmware, &wc->pdev->dev)) || - !firmware) { - DTE_PRINTK(ERR, "Firmware %s not available from userspace. (%d)\n", tc400m_firmware, res); + res = request_firmware(&firmware, tc400m_firmware, &wc->pdev->dev); + if (res || !firmware) { + DTE_PRINTK(ERR, + "Firmware %s not available from userspace. (%d)\n", + tc400m_firmware, res); goto error_exit_swinit; } #else - embedded_firmware.data = _binary_zt_fw_tc400m_bin_start; - embedded_firmware.size = (size_t) &_binary_zt_fw_tc400m_bin_size; + embedded_firmware.data = _binary_dahdi_fw_tc400m_bin_start; + embedded_firmware.size = (size_t) &_binary_dahdi_fw_tc400m_bin_size; #endif wctc4xxp_firmware_ver = firmware->data[0]; @@ -3107,75 +3501,82 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) wc->numchannels = min_numchannels; } - if ((res = initialize_encoders(wc, complexfmts))) { + res = initialize_encoders(wc, complexfmts); + if (res) goto error_exit_swinit; - } - if ((res = initialize_decoders(wc, complexfmts))) { + res = initialize_decoders(wc, complexfmts); + if (res) goto error_exit_swinit; - } - + if (DTE_DEBUG_NETWORK_IF & debug) { - if ((res = wctc4xxp_net_register(wc))) { + res = wctc4xxp_net_register(wc); + if (res) goto error_exit_swinit; - } } - -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) wc->watchdog.function = wctc4xxp_watchdog; wc->watchdog.data = (unsigned long)wc; init_timer(&wc->watchdog); # else - setup_timer(&wc->watchdog, wctc4xxp_watchdog, (unsigned long)wc); + setup_timer(&wc->watchdog, wctc4xxp_watchdog, (unsigned long)wc); +# endif + +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) + wc->polling.function = wctc4xxp_polling; + wc->polling.data = (unsigned long)wc; + init_timer(&wc->polling); +# else + setup_timer(&wc->polling, wctc4xxp_polling, (unsigned long)wc); # endif /* ------------------------------------------------------------------ * Load the firmware and start the DTE. * --------------------------------------------------------------- */ - if ((res = pci_enable_device(pdev))) { + res = pci_enable_device(pdev); + if (res) { DTE_PRINTK(ERR, "Failed to enable device.\n"); goto error_exit_swinit;; } pci_set_master(pdev); pci_set_drvdata(pdev, wc); - if ((res = request_irq(pdev->irq, wctc4xxp_interrupt, ZAP_IRQ_SHARED, wc->board_name, wc))) { + res = request_irq(pdev->irq, wctc4xxp_interrupt, + ZAP_IRQ_SHARED, wc->board_name, wc); + if (res) { DTE_PRINTK(ERR, "Unable to request IRQ %d\n", pdev->irq); - if (firmware != &embedded_firmware) { + if (firmware != &embedded_firmware) release_firmware(firmware); - } goto error_exit_hwinit; } - if ((res = wctc4xxp_hardware_init(wc))) { - if (firmware != &embedded_firmware) { + res = wctc4xxp_hardware_init(wc); + if (res) { + if (firmware != &embedded_firmware) release_firmware(firmware); - } goto error_exit_hwinit; } wctc4xxp_enable_interrupts(wc); wctc4xxp_start_dma(wc); res = wctc4xxp_boot_processor(wc, firmware); - if (firmware != &embedded_firmware) { + if (firmware != &embedded_firmware) release_firmware(firmware); - } - if (res) { + if (res) goto error_exit_hwinit; - } - if ((res = wctc4xxp_setup_channels(wc))) { + res = wctc4xxp_setup_channels(wc); + if (res) goto error_exit_hwinit; - } /* \todo Read firmware version directly from tc400b.*/ DTE_PRINTK(INFO, "(%s) Transcoder support LOADED " \ - "(firm ver = %d.%d)\n", wc->complexname, wctc4xxp_firmware_ver, + "(firm ver = %d.%d)\n", wc->complexname, wctc4xxp_firmware_ver, wctc4xxp_firmware_ver_minor); reg = wctc4xxp_getctl(wc, 0x00fc); - DTE_DEBUG(DTE_DEBUG_GENERAL, + DTE_DEBUG(DTE_DEBUG_GENERAL, "debug: (post-boot) Reg fc is %08x\n", reg); - + DTE_PRINTK(INFO, "Installed a Wildcard TC: %s \n", wc->variety); DTE_DEBUG(DTE_DEBUG_GENERAL, "Operating in DEBUG mode.\n"); zt_transcoder_register(wc->uencode); @@ -3190,28 +3591,20 @@ error_exit_hwinit: pci_set_drvdata(pdev, NULL); error_exit_swinit: wctc4xxp_net_unregister(wc); - if (wc->encoders) kfree(wc->encoders); - if (wc->decoders) kfree(wc->decoders); - if (wc->uencode) zt_transcoder_free(wc->uencode); - if (wc->udecode) zt_transcoder_free(wc->udecode); - if (wc->txd) { - if (wc->txd->desc) { - wctc4xxp_cleanup_descriptor_ring(wc->txd); - } - kfree(wc->txd); - } - if (wc->rxd) { - if (wc->rxd && wc->rxd->desc) { - wctc4xxp_cleanup_descriptor_ring(wc->rxd); - } - kfree(wc->rxd); - } + kfree(wc->encoders); + kfree(wc->decoders); + zt_transcoder_free(wc->uencode); + zt_transcoder_free(wc->udecode); + wctc4xxp_cleanup_descriptor_ring(wc->txd); + kfree(wc->txd); + wctc4xxp_cleanup_descriptor_ring(wc->rxd); + kfree(wc->rxd); release_region(wc->iobase, 0xff); spin_lock(&wctc4xxp_list_lock); list_del(&wc->node); spin_unlock(&wctc4xxp_list_lock); kfree(wc); - return res; + return res; } static void wctc4xxp_cleanup_channels(struct wcdte *wc) @@ -3219,10 +3612,10 @@ static void wctc4xxp_cleanup_channels(struct wcdte *wc) int i; struct zt_transcoder_channel *dtc_en, *dtc_de; - for(i = 0; i < wc->numchannels; i++) { + for (i = 0; i < wc->numchannels; ++i) { dtc_en = &(wc->uencode->channels[i]); wctc4xxp_cleanup_channel_private(wc, dtc_en); - + dtc_de = &(wc->udecode->channels[i]); wctc4xxp_cleanup_channel_private(wc, dtc_de); } @@ -3230,56 +3623,32 @@ static void wctc4xxp_cleanup_channels(struct wcdte *wc) static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev) { - int i; struct wcdte *wc = pci_get_drvdata(pdev); - struct zt_transcoder_channel *dtc_en, *dtc_de; - struct channel_pvt *cpvt; - if (!wc) { - /* \todo print warning message here. */ + if (!wc) return; - } spin_lock(&wctc4xxp_list_lock); list_del(&wc->node); spin_unlock(&wctc4xxp_list_lock); set_bit(DTE_SHUTDOWN, &wc->flags); - if (del_timer_sync(&wc->watchdog)) { - /* Just delete the timer twice in case the timer had already - * checked DTE_SHUTDOWN and rescheduled itself the first time. - */ + if (del_timer_sync(&wc->watchdog)) del_timer_sync(&wc->watchdog); - } + + /* This should already be stopped, but it doesn't hurt to make sure. */ + clear_bit(DTE_POLLING, &wc->flags); + if (del_timer_sync(&wc->polling)) + del_timer_sync(&wc->polling); wctc4xxp_net_unregister(wc); - if (debug) { - for(i = 0; i < wc->numchannels; i++) { - dtc_en = &(wc->uencode->channels[i]); - cpvt = dtc_en->pvt; - DTE_DEBUG(DTE_DEBUG_GENERAL, - "encoder[%d] snt = %d, rcv = %d [%d]\n", i, - atomic_read(&cpvt->stats.packets_sent), - atomic_read(&cpvt->stats.packets_received), - atomic_read(&cpvt->stats.packets_sent) - atomic_read(&cpvt->stats.packets_received)); - - dtc_de = &(wc->udecode->channels[i]); - cpvt = dtc_de->pvt; - DTE_DEBUG(DTE_DEBUG_GENERAL, - "decoder[%d] snt = %d, rcv = %d [%d]\n", i, - atomic_read(&cpvt->stats.packets_sent), - atomic_read(&cpvt->stats.packets_received), - atomic_read(&cpvt->stats.packets_sent) - atomic_read(&cpvt->stats.packets_received)); - } - } - /* Stop any DMA */ wctc4xxp_stop_dma(wc); /* In case hardware is still there */ wctc4xxp_disable_interrupts(wc); - + free_irq(pdev->irq, wc); /* There isn't anything that would run in the workqueue that will wait @@ -3290,16 +3659,11 @@ static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev) /* Free Resources */ release_region(wc->iobase, 0xff); - spin_lock_bh(&wc->cmd_list_lock); - if (wc->txd) { - if (wc->txd->desc) wctc4xxp_cleanup_descriptor_ring(wc->txd); - kfree(wc->txd); - } - if (wc->rxd) { - if (wc->rxd && wc->rxd->desc) wctc4xxp_cleanup_descriptor_ring(wc->rxd); - kfree(wc->rxd); - } - spin_unlock_bh(&wc->cmd_list_lock); + wctc4xxp_cleanup_descriptor_ring(wc->txd); + kfree(wc->txd); + wctc4xxp_cleanup_descriptor_ring(wc->rxd); + kfree(wc->rxd); + wctc4xxp_cleanup_command_list(wc); wctc4xxp_cleanup_channels(wc); @@ -3313,48 +3677,69 @@ static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev) } static struct pci_device_id wctc4xxp_pci_tbl[] = { - { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* Digium board */ - { 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctce400 }, /* Digium board */ + { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, (unsigned long) &wctc400p }, /* Digium board */ + { 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, (unsigned long) &wctce400 }, /* Digium board */ { 0 } }; MODULE_DEVICE_TABLE(pci, wctc4xxp_pci_tbl); static struct pci_driver wctc4xxp_driver = { - name: "wctc4xxp", - probe: wctc4xxp_init_one, - remove: __devexit_p(wctc4xxp_remove_one), - suspend: NULL, - resume: NULL, - id_table: wctc4xxp_pci_tbl, + .name = "wctc4xxp", + .probe = wctc4xxp_init_one, + .remove = __devexit_p(wctc4xxp_remove_one), + .id_table = wctc4xxp_pci_tbl, }; -int __init wctc4xxp_init(void) +static int __init wctc4xxp_init(void) { int res; -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) - cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0, - SLAB_HWCACHE_ALIGN, NULL, NULL); + unsigned long cache_flags; + +#if defined(CONFIG_SLUB) && (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)) + cache_flags = SLAB_HWCACHE_ALIGN | SLAB_STORE_USER | SLAB_DEBUG_FREE; +#else + cache_flags = SLAB_HWCACHE_ALIGN; +#endif + +#ifdef USE_CUSTOM_MEMCACHE + cmd_cache = my_cache_create(); +#else +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), + 0, cache_flags, NULL, NULL); # else - cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), 0, - SLAB_HWCACHE_ALIGN, NULL); + cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb), + 0, cache_flags, NULL); # endif - - if (!cmd_cache) { +#endif + + if (!cmd_cache) return -ENOMEM; - } spin_lock_init(&wctc4xxp_list_lock); INIT_LIST_HEAD(&wctc4xxp_list); res = zap_pci_module(&wctc4xxp_driver); - if (res) + if (res) { +#ifdef USE_CUSTOM_MEMCACHE + my_cache_destroy(cmd_cache); +#else + kmem_cache_destroy(cmd_cache); +#endif return -ENODEV; + } return 0; } -void __exit wctc4xxp_cleanup(void) +static void __exit wctc4xxp_cleanup(void) { pci_unregister_driver(&wctc4xxp_driver); +#ifdef USE_CUSTOM_MEMCACHE + my_cache_destroy(cmd_cache); +#else kmem_cache_destroy(cmd_cache); +#endif } module_param(debug, int, S_IRUGO | S_IWUSR); @@ -3362,9 +3747,7 @@ module_param(mode, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(mode, "'g729', 'g723.1', or 'any'. Default 'any'."); MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver"); MODULE_AUTHOR("Digium Incorporated "); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif module_init(wctc4xxp_init); module_exit(wctc4xxp_cleanup); diff --git a/kernel/zaptel.h b/kernel/zaptel.h index 98f514b..019b01c 100644 --- a/kernel/zaptel.h +++ b/kernel/zaptel.h @@ -1742,7 +1742,8 @@ zt_tc_clear_data_waiting(struct zt_transcoder_channel *dtc) { } struct zt_transcoder { - struct list_head node; + struct list_head active_list_node; + struct list_head registration_list_node; char name[80]; int pos; int numchannels; diff --git a/kernel/zttranscode.c b/kernel/zttranscode.c index 58d098c..5f1b3c0 100644 --- a/kernel/zttranscode.c +++ b/kernel/zttranscode.c @@ -3,7 +3,7 @@ * * Written by Mark Spencer * - * Copyright (C) 2006-2008, Digium, Inc. + * Copyright (C) 2006-2009, Digium, Inc. * * All rights reserved. * @@ -39,7 +39,13 @@ #include static int debug; -LIST_HEAD(trans); +/* The registration list contains transcoders in the order in which they were + * registered. */ +static LIST_HEAD(registration_list); +/* The active list is sorted by the most recently used transcoder is last. This + * is used as a simplistic way to spread the load amongst the different hardware + * transcoders in the system. */ +static LIST_HEAD(active_list); static spinlock_t translock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(zt_transcoder_register); @@ -60,7 +66,9 @@ struct zt_transcoder *zt_transcoder_alloc(int numchans) memset(tc, 0, size); strcpy(tc->name, ""); tc->numchannels = numchans; - INIT_LIST_HEAD(&tc->node); + INIT_LIST_HEAD(&tc->registration_list_node); + INIT_LIST_HEAD(&tc->active_list_node); + for (x=0;xnumchannels;x++) { init_waitqueue_head(&tc->channels[x].ready); tc->channels[x].parent = tc; @@ -93,11 +101,10 @@ static int is_on_list(struct list_head *entry, struct list_head *head) /* Register a transcoder */ int zt_transcoder_register(struct zt_transcoder *tc) { - static int count = 0; - tc->pos = count++; spin_lock(&translock); - BUG_ON(is_on_list(&tc->node, &trans)); - list_add_tail(&tc->node, &trans); + BUG_ON(is_on_list(&tc->registration_list_node, ®istration_list)); + list_add_tail(&tc->registration_list_node, ®istration_list); + list_add_tail(&tc->active_list_node, &active_list); spin_unlock(&translock); printk(KERN_INFO "%s: Registered codec translator '%s' " \ @@ -117,13 +124,14 @@ int zt_transcoder_unregister(struct zt_transcoder *tc) * that is still in use? */ spin_lock(&translock); - if (!is_on_list(&tc->node, &trans)) { + if (!is_on_list(&tc->registration_list_node, ®istration_list)) { spin_unlock(&translock); printk(KERN_WARNING "%s: Failed to unregister %s, which is " \ "not currently registerd.\n", THIS_MODULE->name, tc->name); return -EINVAL; } - list_del_init(&tc->node); + list_del_init(&tc->registration_list_node); + list_del_init(&tc->active_list_node); spin_unlock(&translock); printk(KERN_INFO "Unregistered codec translator '%s' with %d " \ @@ -223,7 +231,7 @@ __find_free_channel(struct list_head *list, const struct zt_transcoder_formats * struct zt_transcoder_channel *chan = NULL; unsigned int match = 0; - list_for_each_entry(tc, list, node) { + list_for_each_entry(tc, list, active_list_node) { if ((tc->dstfmts & fmts->dstfmt) && (tc->srcfmts & fmts->srcfmt)) { /* We found a transcoder that can handle our formats. * Now look for an available channel. */ @@ -234,7 +242,7 @@ __find_free_channel(struct list_head *list, const struct zt_transcoder_formats * * transcoders (when there are more than one * transcoder in the system) we'll move tc * to the end of the list. */ - list_move_tail(&tc->node, list); + list_move_tail(&tc->active_list_node, list); return chan; } } @@ -253,7 +261,7 @@ static long zt_tc_allocate(struct file *file, unsigned long data) } spin_lock(&translock); - chan = __find_free_channel(&trans, &fmts); + chan = __find_free_channel(&active_list, &fmts); spin_unlock(&translock); if (IS_ERR(chan)) { @@ -303,14 +311,15 @@ static long zt_tc_getinfo(unsigned long data) struct zt_transcoder_info info; struct zt_transcoder *cur; struct zt_transcoder *tc = NULL; + unsigned int count = 0; if (copy_from_user(&info, (const void *) data, sizeof(info))) { return -EFAULT; } spin_lock(&translock); - list_for_each_entry(cur, &trans, node) { - if (cur->pos == info.tcnum) { + list_for_each_entry(cur, ®istration_list, registration_list_node) { + if (info.tcnum == count++) { tc = cur; break; } -- cgit v1.2.3