summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2009-03-24 19:59:43 +0000
committersruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2009-03-24 19:59:43 +0000
commit275a39b01ad9f8ccf9d31cf5bd78dc4bc82c5659 (patch)
treecd6ea2f85172442f52e3c8bb3b5d7196b3583290
parentd8562c778088ff6ab3383df5ceead41eff4bf124 (diff)
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
-rw-r--r--kernel/wctc4xxp/base.c2757
-rw-r--r--kernel/zaptel.h3
-rw-r--r--kernel/zttranscode.c37
3 files changed, 1595 insertions, 1202 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 <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
@@ -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;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+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;
+}
+
+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,132 +1103,490 @@ 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)
{
- struct csm_create_channel_cmd *c;
- c = hdr_from_cmd(cmd);
+ 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);
+}
- BUG_ON(timeslot > 0x01ff);
+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_encaps_hdr *hdr = cmd->data;
+ int i;
- setup_supervisor_header(wc, &c->hdr);
+ if (cmd->response) {
+ free_cmd(cmd->response);
+ cmd->response = NULL;
+ }
+
+ 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;
+
+ setup_channel_header(pvt, 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;
+
+ 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);
}
-void
-__wctc4xxp_create_set_arm_clk_cmd(struct wcdte *wc, struct tcb *cmd)
+static int
+send_create_channel_cmd(struct wcdte *wc, struct tcb *cmd, u16 timeslot,
+ u16 *channel_number)
{
- struct csm_encaps_hdr *hdr = cmd->data;
- BUG_ON(SIZE_WITH_N_PARAMETERS(2) > cmd->data_len);
+ int res;
+ const u16 parameters[] = {0x0002, timeslot};
- setup_supervisor_header(wc, hdr);
+ create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
+ CONFIG_DEVICE_CLASS, SUPVSR_CREATE_CHANNEL,
+ parameters, ARRAY_SIZE(parameters));
- 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;
+ res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
+ if (res)
+ return res;
+
+ 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;
+ }
+
+ *channel_number = le16_to_cpu(response_header(cmd)->params[1]);
+ free_cmd(cmd->response);
+ cmd->response = NULL;
+ return 0;
+}
+
+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);
}
-struct tcb *
-wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct zt_transcoder_channel *dtc, size_t inbytes)
+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 int
+send_tdm_select_bus_mode_cmd(struct wcdte *wc, struct tcb *cmd)
+{
+ 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 int
+send_set_eth_header_cmd(struct wcdte *wc, struct tcb *cmd,
+ const u8 *host_mac, const u8 *assigned_mac)
+{
+ u16 parameters[8];
+ u16 *part;
+
+ 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;
+
+ create_supervisor_cmd(wc, cmd, CONFIG_CHANGE_TYPE,
+ CONFIG_DEVICE_CLASS, 0x0100, parameters,
+ ARRAY_SIZE(parameters));
+ return wctc4xxp_transmit_cmd_and_wait(wc, cmd);
+}
+
+static int
+send_supvsr_setup_tdm_parms(struct wcdte *wc, struct tcb *cmd,
+ u8 bus_number)
+{
+ 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 int
+send_ip_service_config_cmd(struct wcdte *wc, struct tcb *cmd)
+{
+ 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;
- if (!(cmd = alloc_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 = 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));
+ 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.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_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;
-
+ 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)
+wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr)
{
- int i;
+ int i;
struct wctc4xxp_descriptor *d;
- unsigned long flags;
-
- /* NOTE: The DTE must be in the stopped state. */
- spin_lock_irqsave(&dr->lock, flags);
+
+ 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);
+ 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
@@ -1280,24 +1599,24 @@ wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr)
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);
+ 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_bh(&wc->cmd_list_lock);
+ 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_bh(&wc->cmd_list_lock);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
- while(!list_empty(&local_list)) {
- cmd = list_entry(local_list.next, struct tcb, node);
+ while (!list_empty(&local_list)) {
+ cmd = list_entry(local_list.next, struct tcb, node);
list_del_init(&cmd->node);
free_cmd(cmd);
}
@@ -1305,42 +1624,45 @@ static void wctc4xxp_cleanup_command_list(struct wcdte *wc)
/**
* The command list is used to store commands that couldn't fit in the tx
- * descriptor list when they were requested.
+ * descriptor list when they were requested.
*/
-static void
-wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd)
+static void
+wctc4xxp_add_to_command_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_add_tail(&cmd->node, &wc->cmd_list);
- spin_unlock_bh(&wc->cmd_list_lock);
+ spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
}
static void
wctc4xxp_add_to_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_add_tail(&cmd->node, &wc->waiting_for_response_list);
- spin_unlock_bh(&wc->cmd_list_lock);
+ 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);
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");
return 0;
}
-static int
-wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
+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,
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;
+ DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
+ "DTE is using the following channels encoder_channel: " \
+ "%d decoder_channel: %d\n", encoder_channel, decoder_channel);
- 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);
-
- 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;
+ encoder_pvt = dtc1->pvt;
+ decoder_pvt = 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;
- }
-
- /* 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 <support@digium.com>");
-#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 <markster@digium.com>
*
- * Copyright (C) 2006-2008, Digium, Inc.
+ * Copyright (C) 2006-2009, Digium, Inc.
*
* All rights reserved.
*
@@ -39,7 +39,13 @@
#include <zaptel.h>
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, "<unspecified>");
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;x<tc->numchannels;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, &registration_list));
+ list_add_tail(&tc->registration_list_node, &registration_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, &registration_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, &registration_list, registration_list_node) {
+ if (info.tcnum == count++) {
tc = cur;
break;
}