[dahdi-commits] dahdi/linux.git branch "master" updated.

SVN commits to the DAHDI project dahdi-commits at lists.digium.com
Fri May 16 12:09:11 CDT 2014


branch "master" has been updated
       via  8342a3d21b2cf86b0f501fd00bf56fb789eca80a (commit)
       via  ba05e31c8a786d7524fd1aed47feda27331606dd (commit)
       via  b6a8623203df88f3b2ccb75b485502dac487009d (commit)
       via  354d88cd418627285e86e77cceb9318e33f0348c (commit)
       via  0efce00a0948932e2be84bd72eda3d766d34fa9f (commit)
       via  67e422c1efc7a5a7a1a1e4904d8424db55c0b115 (commit)
       via  cbe4825d1a2e8d1accc0a4a8133a5135e4171aea (commit)
       via  b5ac763f29c88b09682d1f50096b21745e9ae8a1 (commit)
       via  6341783cc868dd01896552a458c66a28d5439270 (commit)
       via  ea04099e7769f5e0d9f9681bc044b6544d05014a (commit)
       via  bc274e1b5d9ca3b9e3927568d0860ebe307c1033 (commit)
       via  44a33126e0fa7df0ca568aa749e9db959d64e41c (commit)
       via  3446cdca8f4d4d77aeba73c742448eb438baa836 (commit)
       via  391ca2b7aa531439b0c2ef2cac6b9b3bc868ffb5 (commit)
       via  ec9d162344a8e84a6e0e3f563a800cbfb5bc75ac (commit)
       via  7168b87cb593ebc3025042297c7019402279963a (commit)
       via  f8a6f55e801a2a4f38f6c5efd405a52708920db0 (commit)
       via  6c796d0774f103be5523c29d076b43623a371ef3 (commit)
       via  9c65971863bb9e356b274b3df08a78ea6fe04edd (commit)
       via  2ac233824705e2f5f1cf67b6b22459fa20e9aa4c (commit)
       via  3096ffe95508d0314a00bb5e7511a1d23f343939 (commit)
       via  039daca12e4311d4a7243d8711b5dbe467754509 (commit)
      from  15ff405dc80b3dcb2904c5ff1334defdb6b6d383 (commit)

Summary of changes:
 drivers/dahdi/dahdi_transcode.c |    3 +-
 drivers/dahdi/wctc4xxp/base.c   |  822 +++++++++++++++++++++++++--------------
 2 files changed, 530 insertions(+), 295 deletions(-)


- Log -----------------------------------------------------------------
commit 8342a3d21b2cf86b0f501fd00bf56fb789eca80a
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Mon Feb 10 23:41:12 2014 -0600

    wctc4xxp: Add debug option to print channel stats to kernel log.
    
    This patch does a couple of things. It adds a new DEBUG mode where packet
    statistics are printed when channels are closed which can be used to track where
    packets might be lost in the transcoding chain.
    
    This patch will also print to the kernel log if the AN983 has detected any
    errored received packets. Problems of this type are typically system problems,
    like when the card is having trouble DMAing packets.
    
    Internal-Issue-ID: DAHDI-1071
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 81dec63..af2d72b 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -104,6 +104,7 @@
 #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_ETH_STATS	(1 << 7) /* 128 */
 
 static int debug;
 static char *mode;
@@ -174,6 +175,7 @@ struct csm_encaps_hdr {
 #define SUPVSR_CREATE_CHANNEL	0x0010
 
 #define MONITOR_LIVE_INDICATION_TYPE 0x75
+#define VOIP_VCEINFO_TYPE	0x0e
 #define CONFIG_CHANGE_TYPE	0x00
 #define CONFIG_CHANNEL_CLASS	0x02
 #define CONFIG_DEVICE_CLASS	0x06
@@ -783,6 +785,10 @@ struct wctc4xxp_descriptor_ring {
 	struct pci_dev  *pdev;
 	/*! The size of the dring. */
 	unsigned long size;
+	/*! Total number of packets completed. */
+	unsigned long packet_count;
+	/*! Total number of packets with errors. */
+	unsigned long packet_errors;
 };
 
 /**
@@ -905,6 +911,7 @@ wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr)
 	struct tcb *c;
 	unsigned int head = dr->head;
 	unsigned long flags;
+	u32 des0;
 	spin_lock_irqsave(&dr->lock, flags);
 	d = wctc4xxp_descriptor(dr, head);
 	if (d->buffer1 && !OWNED(d)) {
@@ -916,8 +923,18 @@ wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr)
 		d->buffer1 = 0;
 		--dr->count;
 		WARN_ON(!c);
-		c->data_len = (le32_to_cpu(d->des0) >> 16) & BUFFER1_SIZE_MASK;
-		WARN_ON(c->data_len > SFRAME_SIZE);
+		des0 = le32_to_cpu(d->des0);
+		c->data_len = (des0 >> 16) & BUFFER1_SIZE_MASK;
+		if (des0 & (1<<15)) {
+			++dr->packet_errors;
+			/* The upper layers won't be able to do anything with
+			 * this packet. Free it up and log the error. */
+			free_cmd(c);
+			c = NULL;
+		} else {
+			++dr->packet_count;
+			WARN_ON(c->data_len > SFRAME_SIZE);
+		}
 	} else {
 		c = NULL;
 	}
@@ -935,6 +952,37 @@ static inline int wctc4xxp_getcount(struct wctc4xxp_descriptor_ring *dr)
 	return count;
 }
 
+static inline int wctc4xxp_get_packet_count(struct wctc4xxp_descriptor_ring *dr)
+{
+	unsigned long count;
+	unsigned long flags;
+	spin_lock_irqsave(&dr->lock, flags);
+	count = dr->packet_count;
+	spin_unlock_irqrestore(&dr->lock, flags);
+	return count;
+}
+
+static inline int
+wctc4xxp_get_packet_errors(struct wctc4xxp_descriptor_ring *dr)
+{
+	unsigned long count;
+	unsigned long flags;
+	spin_lock_irqsave(&dr->lock, flags);
+	count = dr->packet_errors;
+	spin_unlock_irqrestore(&dr->lock, flags);
+	return count;
+}
+
+static inline void
+wctc4xxp_set_packet_count(struct wctc4xxp_descriptor_ring *dr,
+			  unsigned long count)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&dr->lock, flags);
+	dr->packet_count = count;
+	spin_unlock_irqrestore(&dr->lock, flags);
+}
+
 static inline void
 __wctc4xxp_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
 {
@@ -1428,6 +1476,54 @@ send_trans_disconnect_cmd(struct wcdte *wc, struct tcb *cmd, const u16
 		decoder_channel, encoder_format, decoder_format);
 }
 
+static int
+send_voip_vceinfo_cmd(struct channel_pvt *pvt, struct tcb *cmd)
+{
+	int res;
+	const u16 parameters[] = {0};
+	static const int CONFIG_CHANNEL_STATS_CLASS = 1;
+	create_channel_cmd(pvt, cmd,
+		VOIP_VCEINFO_TYPE, CONFIG_CHANNEL_STATS_CLASS,
+		0x0000, parameters, 0);
+	res = wctc4xxp_transmit_cmd_and_wait(pvt->wc, cmd);
+	return res;
+}
+
+static int
+send_eth_statistics_cmd(struct wcdte *wc, struct tcb *cmd)
+{
+	int res;
+	const u16 parameters[] = {0};
+
+	create_supervisor_cmd(wc, cmd, 0x00, 0x05, 0x0000,
+		parameters, ARRAY_SIZE(parameters));
+	res = wctc4xxp_transmit_cmd_and_wait(wc, cmd);
+	if (res)
+		return -EIO;
+	if (0x0000 != response_header(cmd)->params[0]) {
+		dev_info(&wc->pdev->dev,
+			 "Failed to get ethernet stats: 0x%04x\n",
+			 response_header(cmd)->params[0]);
+		res = -EIO;
+	}
+	return res;
+}
+
+static void wctc4xxp_match_packet_counts(struct wcdte *wc)
+{
+	struct tcb *cmd  = alloc_cmd(SFRAME_SIZE);
+	int res;
+	u32 *parms;
+
+	res = send_eth_statistics_cmd(wc, cmd);
+	if (0 == res) {
+		parms = (u32 *)(&response_header(cmd)->params[0]);
+		wctc4xxp_set_packet_count(wc->rxd, parms[1]);
+		wctc4xxp_set_packet_count(wc->txd, parms[2]);
+	}
+	free_cmd(cmd);
+}
+
 static struct tcb *
 wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct dahdi_transcoder_channel *dtc,
 	size_t inbytes)
@@ -1874,6 +1970,20 @@ wctc4xxp_disable_polling(struct wcdte *wc)
 	wctc4xxp_enable_interrupts(wc);
 }
 
+static void wctc4xxp_check_for_rx_errors(struct wcdte *wc)
+{
+	static unsigned long last_errors = 0;
+	unsigned long errors = wctc4xxp_get_packet_errors(wc->rxd);
+	if (last_errors != errors) {
+		if (printk_ratelimit()) {
+			dev_err(&wc->pdev->dev,
+				"%lu errored receive packets.\n",
+				errors - last_errors);
+			last_errors = errors;
+		}
+	}
+}
+
 static int
 wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
 {
@@ -1965,6 +2075,9 @@ wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
 	compl_cpvt = compl_dtc->pvt;
 	compl_cpvt->chan_in_num = INVALID;
 	compl_cpvt->chan_out_num = INVALID;
+
+	wctc4xxp_check_for_rx_errors(wc);
+
 error_exit:
 	mutex_unlock(&wc->chanlock);
 	return res;
@@ -2315,7 +2428,10 @@ do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
 static inline int
 is_response(const struct csm_encaps_hdr *hdr)
 {
-	return ((0x02 == hdr->type) || (0x04 == hdr->type)) ? 1 : 0;
+	return ((0x02 == hdr->type) ||
+		(0x04 == hdr->type) ||
+		(0x0e == hdr->type) ||
+		(0x00 == hdr->type)) ? 1 : 0;
 }
 
 static void
@@ -2694,7 +2810,7 @@ wctc4xxp_hardware_init(struct wcdte *wc)
 	wctc4xxp_setctl(wc, 0x0000, reg | 0x60000);
 
 	/* Configure watchdogs, access, etc */
-	wctc4xxp_setctl(wc, 0x0030, 0x00280040);
+	wctc4xxp_setctl(wc, 0x0030, 0x00280048);
 	wctc4xxp_setctl(wc, 0x0078, 0x00000013);
 	reg = wctc4xxp_getctl(wc, 0x00fc);
 	wctc4xxp_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
@@ -3082,6 +3198,94 @@ error_exit:
 	return -EIO;
 }
 
+static void print_vceinfo_packet(struct wcdte *wc, struct tcb *cmd)
+{
+	int i;
+	struct device *const dev = &wc->pdev->dev;
+
+	static const struct {
+		const char *name;
+		bool show;
+	} PARAMETERS[] = {
+		{ "Format Revision                                   ", false},
+		{ "Reserved                                          ", false},
+		{ "Call Timer (seconds)                              ", false},
+		{ "Current Playout Delay [to PCM]                    ", false},
+		{ "Minimum Playout Delay [to PCM]                    ", false},
+		{ "Maximum Playout Delay [to PCM]                    ", false},
+		{ "Clock Offset                                      ", false},
+		{ "PeakJitter (ms)                                   ", true},
+		{ "Interpolative Concealment [to PCM]                ", false},
+		{ "Silence Concealment [to PCM]                      ", false},
+		{ "Jitter Buffer Overflow Discard [from IP]          ", true},
+		{ "End-point Detection Errors                        ", true},
+		{ "Number of Tx Voice Packets [to IP]                ", true},
+		{ "Number of Tx Signalling Packets [to IP]           ", true},
+		{ "Number of Tx Comfort Noise Packets [to IP]        ", true},
+		{ "Total Transmit Duration [to IP]                   ", true},
+		{ "Voice Transmit Duration [to IP]                   ", true},
+		{ "Number of Rx Voice Packets [from IP]              ", true},
+		{ "Number of Rx Signalling Packets [from IP]         ", true},
+		{ "Number of Rx Comfort Noise Packets [from IP]      ", true},
+		{ "Total Receive Duration [from IP]                  ", true},
+		{ "Voice Receive Duration [from IP]                  ", true},
+		{ "Packets Out of Sequence [from IP]                 ", true},
+		{ "Bad Protocol Headers [from IP]                    ", true},
+		{ "Late Packets [from IP]                            ", true},
+		{ "Reserved (Early Packets) always zero              ", false},
+		{ "Number of Rx Voice bytes                          ", true},
+		{ "Number of Lost Packets [from IP]                  ", true},
+		{ "Current Transmit Power [from PCM]                 ", false},
+		{ "Mean Transmit Power [from PCM]                    ", false},
+		{ "Current Receive Power [to PCM]                    ", false},
+		{ "Mean Receive Power [to PCM]                       ", false},
+		{ "Background Noise [to PCM]                         ", false},
+		{ "ERL Level [to PCM]                                ", false},
+		{ "ACOM Level [from PCM]                             ", false},
+		{ "Current Transmit Activity [from PCM]              ", false},
+		{ "Current Receive Activity [to PCM]                 ", false},
+		{ "Discarded Unexpected Packets                      ", true},
+		{ "Discard Packets Due to Rx Disabled                ", true},
+		{ "Discarded Duplicate Packets                       ", true},
+		{ "Discarded Packets Due to Incorrect Payload Length ", true},
+		{ "Discarded Packets Due to Channel Inactive         ", true},
+		{ "Discarded Packets Due to Insufficient Memory      ", true}
+	};
+
+	u32 *parms = (u32 *)(&response_header(cmd)->params[0]);
+	for (i = 0; i < 43; ++i) {
+		if (PARAMETERS[i].show)
+			dev_info(dev, "%s%d\n", PARAMETERS[i].name, parms[i]);
+	}
+}
+
+static void print_eth_statistics_packet(struct wcdte *wc, struct tcb *cmd)
+{
+	int i;
+	struct device *const dev = &wc->pdev->dev;
+
+	static const struct {
+		const char *name;
+		bool show;
+	} PARAMETERS[] = {
+		{ "Format Revision                 ", true},
+		{ "Emitted Frames                  ", true},
+		{ "Received Frames                 ", true},
+		{ "Unknown Packet Type             ", true},
+		{ "Received Broadcast Packets      ", true},
+		{ "Unknown Broadcast               ", true},
+		{ "Emitted VLAN frames             ", true},
+		{ "Received VLAN frames            ", true},
+		{ "Received VLAN frames with E-RIF ", true}
+	};
+
+	u32 *parms = (u32 *)(&response_header(cmd)->params[0]);
+	for (i = 0; i < sizeof(PARAMETERS)/sizeof(PARAMETERS[0]); ++i) {
+		if (PARAMETERS[i].show)
+			dev_info(dev, "%s%d\n", PARAMETERS[i].name, parms[i]);
+	}
+}
+
 static int
 wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt)
 {
@@ -3118,6 +3322,26 @@ wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt)
 	encoder_pvt = dtc1->pvt;
 	decoder_pvt = dtc2->pvt;
 
+	if (debug & DTE_DEBUG_ETH_STATS) {
+		if (send_voip_vceinfo_cmd(encoder_pvt, cmd))
+			goto error_exit;
+		dev_warn(&wc->pdev->dev,
+			 "****************************************\n");
+		dev_warn(&wc->pdev->dev,
+			 "Encoder stats (ch: %d):\n",
+			 encoder_pvt->timeslot_in_num);
+		print_vceinfo_packet(wc, cmd);
+
+		if (send_voip_vceinfo_cmd(decoder_pvt, cmd))
+			goto error_exit;
+		dev_warn(&wc->pdev->dev,
+			 "****************************************\n");
+		dev_warn(&wc->pdev->dev,
+			 "Decoder stats (ch: %d):\n",
+			 decoder_pvt->timeslot_in_num);
+		print_vceinfo_packet(wc, cmd);
+	}
+
 	if (send_voip_vopena_close_cmd(encoder_pvt, cmd))
 		goto error_exit;
 	if (send_voip_vopena_close_cmd(decoder_pvt, cmd))
@@ -3129,6 +3353,15 @@ wctc4xxp_destroy_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt)
 	if (send_destroy_channel_cmd(wc, cmd, chan2))
 		goto error_exit;
 
+	if (debug & DTE_DEBUG_ETH_STATS) {
+		if (send_eth_statistics_cmd(wc, cmd))
+			goto error_exit;
+		print_eth_statistics_packet(wc, cmd);
+		dev_info(&wc->pdev->dev, "AN983 tx packets: %d rx packets: %d\n",
+			 wctc4xxp_get_packet_count(wc->txd),
+			 wctc4xxp_get_packet_count(wc->rxd));
+	}
+
 	free_cmd(cmd);
 	return 0;
 error_exit:
@@ -3611,6 +3844,8 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dahdi_transcoder_register(wc->uencode);
 	dahdi_transcoder_register(wc->udecode);
 
+	wctc4xxp_match_packet_counts(wc);
+
 	return 0;
 
 error_exit_hwinit:

commit ba05e31c8a786d7524fd1aed47feda27331606dd
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Thu May 8 13:40:45 2014 -0500

    wctc4xxp: Allow the tx and rx descriptor rings to be different sizes
    
    Keeping the transmit descriptor ring shorter reduces the time it takes to send
    CSM_ENCAP commands to the transcoding engine when the card is otherwise busy.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 3cab6e8..81dec63 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -182,8 +182,11 @@ struct csm_encaps_hdr {
 #define MAX_FRAME_SIZE 1518
 #define SFRAME_SIZE MAX_FRAME_SIZE
 
-#define DRING_SIZE (1 << 7) /* Must be a power of two */
-#define DRING_MASK (DRING_SIZE-1)
+#define DEFAULT_RX_DRING_SIZE (1 << 6) /* Must be a power of two */
+
+/* Keep the TX ring shorter in order to reduce the amount of time needed to
+ * bring up channels when sending high priority csm_encaps packets. */
+#define DEFAULT_TX_DRING_SIZE (1 << 4) /* Must be a power of two */
 #define MIN_PACKET_LEN  64
 
 /* Transcoder buffer (tcb) */
@@ -765,7 +768,7 @@ struct wctc4xxp_descriptor_ring {
 	/* Write ready buffers to the tail. */
 	unsigned int 	tail;
 	/* Array to save the kernel virtual address of pending commands. */
-	struct tcb *pending[DRING_SIZE];
+	struct tcb **pending;
 	/* PCI Bus address of the descriptor list. */
 	dma_addr_t	desc_dma;
 	/*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
@@ -778,6 +781,8 @@ struct wctc4xxp_descriptor_ring {
 	spinlock_t      lock;
 	/*! PCI device for the card associated with this ring. */
 	struct pci_dev  *pdev;
+	/*! The size of the dring. */
+	unsigned long size;
 };
 
 /**
@@ -797,13 +802,14 @@ wctc4xxp_descriptor(struct wctc4xxp_descriptor_ring *dr, int index)
 
 static int
 wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev,
-	struct wctc4xxp_descriptor_ring *dr, u32 des1, unsigned int direction)
+	struct wctc4xxp_descriptor_ring *dr, u32 des1, unsigned int direction,
+	unsigned long size)
 {
 	int i;
 	const u32 END_OF_RING = 0x02000000;
 	u8 cache_line_size = 0;
-	struct wctc4xxp_descriptor *d;
 	int add_padding;
+	struct wctc4xxp_descriptor *d = NULL;
 
 	BUG_ON(!pdev);
 	BUG_ON(!dr);
@@ -812,6 +818,7 @@ wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev,
 		return -EIO;
 
 	memset(dr, 0, sizeof(*dr));
+	dr->size = size;
 
 	/*
 	 * Add some padding to each descriptor to ensure that they are
@@ -825,14 +832,19 @@ wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev,
 	if (add_padding)
 		dr->padding = (cache_line_size*sizeof(u32)) - sizeof(*d);
 
-	dr->desc = pci_alloc_consistent(pdev,
-			(sizeof(*d)+dr->padding)*DRING_SIZE, &dr->desc_dma);
+	dr->pending = kmalloc(sizeof(struct tcb *) * dr->size, GFP_KERNEL);
+	if (!dr->pending)
+		return -ENOMEM;
 
-	if (!dr->desc)
+	dr->desc = pci_alloc_consistent(pdev,
+			(sizeof(*d)+dr->padding)*dr->size, &dr->desc_dma);
+	if (!dr->desc) {
+		kfree(dr->pending);
 		return -ENOMEM;
+	}
 
-	memset(dr->desc, 0, (sizeof(*d) + dr->padding) * DRING_SIZE);
-	for (i = 0; i < DRING_SIZE; ++i) {
+	memset(dr->desc, 0, (sizeof(*d) + dr->padding) * dr->size);
+	for (i = 0; i < dr->size; ++i) {
 		d = wctc4xxp_descriptor(dr, i);
 		memset(d, 0, sizeof(*d));
 		d->des1 = cpu_to_le32(des1);
@@ -880,7 +892,7 @@ wctc4xxp_submit(struct wctc4xxp_descriptor_ring *dr, struct tcb *c)
 
 	SET_OWNED(d); /* That's it until the hardware is done with it. */
 	dr->pending[dr->tail] = c;
-	dr->tail = (dr->tail + 1) & DRING_MASK;
+	dr->tail = (dr->tail + 1) & (dr->size-1);
 	++dr->count;
 	spin_unlock_irqrestore(&dr->lock, flags);
 	return 0;
@@ -900,7 +912,7 @@ wctc4xxp_retrieve(struct wctc4xxp_descriptor_ring *dr)
 			SFRAME_SIZE, dr->direction);
 		c = dr->pending[head];
 		WARN_ON(!c);
-		dr->head = (++head) & DRING_MASK;
+		dr->head = (++head) & (dr->size-1);
 		d->buffer1 = 0;
 		--dr->count;
 		WARN_ON(!c);
@@ -1484,7 +1496,7 @@ wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr)
 	if (!dr || !dr->desc)
 		return;
 
-	for (i = 0; i < DRING_SIZE; ++i) {
+	for (i = 0; i < dr->size; ++i) {
 		d = wctc4xxp_descriptor(dr, i);
 		if (d->buffer1) {
 			pci_unmap_single(dr->pdev, d->buffer1,
@@ -1501,8 +1513,9 @@ wctc4xxp_cleanup_descriptor_ring(struct wctc4xxp_descriptor_ring *dr)
 	dr->head = 0;
 	dr->tail = 0;
 	dr->count = 0;
-	pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * DRING_SIZE,
+	pci_free_consistent(dr->pdev, (sizeof(*d)+dr->padding) * dr->size,
 		dr->desc, dr->desc_dma);
+	kfree(dr->pending);
 }
 
 static void wctc4xxp_timeout_all_commands(struct wcdte *wc)
@@ -2697,7 +2710,7 @@ wctc4xxp_start_dma(struct wcdte *wc)
 	u32 reg;
 	struct tcb *cmd;
 
-	for (i = 0; i < DRING_SIZE; ++i) {
+	for (i = 0; i < wc->rxd->size; ++i) {
 		cmd = alloc_cmd(SFRAME_SIZE);
 		if (!cmd) {
 			WARN_ALWAYS();
@@ -3463,7 +3476,7 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	}
 
 	res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->txd,
-		0xe0800000, DMA_TO_DEVICE);
+		0xe0800000, DMA_TO_DEVICE, DEFAULT_TX_DRING_SIZE);
 	if (res)
 		goto error_exit_swinit;
 
@@ -3474,7 +3487,7 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	}
 
 	res = wctc4xxp_initialize_descriptor_ring(wc->pdev, wc->rxd, 0,
-		DMA_FROM_DEVICE);
+		DMA_FROM_DEVICE, DEFAULT_RX_DRING_SIZE);
 	if (res)
 		goto error_exit_swinit;
 

commit b6a8623203df88f3b2ccb75b485502dac487009d
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 9 16:09:41 2014 -0500

    wctc4xxp: channel count does not need to be atomic.
    
    It is only modified under the chanlock anyway.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 8a48540..3cab6e8 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -355,7 +355,7 @@ struct wcdte {
 	struct napi_struct napi;
 #endif
 	struct timer_list watchdog;
-	atomic_t open_channels;
+	u16 open_channels;
 #if HZ > 100
 	unsigned long jiffies_at_last_poll;
 #endif
@@ -1744,9 +1744,6 @@ do_channel_allocate(struct dahdi_transcoder_channel *dtc)
 	u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */
 	int res;
 
-	if (mutex_lock_interruptible(&wc->chanlock))
-		return -EINTR;
-
 	/* Check again to see if the channel was built after grabbing the
 	 * channel lock, in case the previous holder of the lock
 	 * built this channel as a complement to itself. */
@@ -1837,8 +1834,8 @@ wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc)
 		goto error_exit;
 	}
 
-	atomic_inc(&wc->open_channels);
-	if (atomic_read(&wc->open_channels) > POLLING_CALL_THRESHOLD) {
+	++wc->open_channels;
+	if (wc->open_channels > POLLING_CALL_THRESHOLD) {
 		if (!test_bit(DTE_POLLING, &wc->flags))
 			wctc4xxp_enable_polling(wc);
 	}
@@ -1846,9 +1843,10 @@ wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc)
 	if (dahdi_tc_is_built(dtc)) {
 		DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
 		  "Allocating channel %p which is already built.\n", dtc);
-		return 0;
+		res = 0;
+	} else {
+		res = do_channel_allocate(dtc);
 	}
-	res = do_channel_allocate(dtc);
 
 error_exit:
 	mutex_unlock(&wc->chanlock);
@@ -1894,14 +1892,16 @@ wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
 		goto error_exit;
 	}
 
-	atomic_dec(&wc->open_channels);
+	if (wc->open_channels) {
+		--wc->open_channels;
 
 #if !defined(CONFIG_WCTC4XXP_POLLING)
-	if (atomic_read(&wc->open_channels) < POLLING_CALL_THRESHOLD) {
-		if (test_bit(DTE_POLLING, &wc->flags))
-			wctc4xxp_disable_polling(wc);
-	}
+		if (wc->open_channels < POLLING_CALL_THRESHOLD) {
+			if (test_bit(DTE_POLLING, &wc->flags))
+				wctc4xxp_disable_polling(wc);
+		}
 #endif
+	}
 
 	packets_received = atomic_read(&cpvt->stats.packets_received);
 	packets_sent = atomic_read(&cpvt->stats.packets_sent);

commit 354d88cd418627285e86e77cceb9318e33f0348c
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 9 13:58:11 2014 -0500

    wctc4xxp: Use hardware timer for polling and not kernel timer
    
    Simplifies the logic when polling is enabled. No need to worry about any system
    factors when scheduling the default kernel timer.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 5dc8daa..8a48540 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -78,7 +78,7 @@
 
 /* The total number of active channels over which the driver will start polling
  * the card every 10 ms. */
-#define POLLING_CALL_THRESHOLD 40
+#define POLLING_CALL_THRESHOLD 8
 
 #define INVALID 999 /* Used to mark invalid channels, commands, etc.. */
 #define MAX_CHANNEL_PACKETS  5
@@ -356,7 +356,6 @@ struct wcdte {
 #endif
 	struct timer_list watchdog;
 	atomic_t open_channels;
-	struct timer_list polling;
 #if HZ > 100
 	unsigned long jiffies_at_last_poll;
 #endif
@@ -1792,10 +1791,12 @@ wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask)
 	wctc4xxp_setctl(wc, 0x0038, intmask);
 }
 
+static const u32 DEFAULT_INTERRUPTS = 0x0001a0c0;
+
 static void
 wctc4xxp_enable_interrupts(struct wcdte *wc)
 {
-	wctc4xxp_setintmask(wc, 0x0001a0c0);
+	wctc4xxp_setintmask(wc, DEFAULT_INTERRUPTS);
 }
 
 static void
@@ -1810,8 +1811,9 @@ static void
 wctc4xxp_enable_polling(struct wcdte *wc)
 {
 	set_bit(DTE_POLLING, &wc->flags);
-	mod_timer(&wc->polling, jiffies + 1);
-	wctc4xxp_disable_interrupts(wc);
+	wctc4xxp_setctl(wc, 0x0058, 0x1000a);
+	/* Enable the general purpose timer interrupt. */
+	wctc4xxp_setintmask(wc, (DEFAULT_INTERRUPTS | (1 << 11)) & ~0x41);
 }
 
 static int
@@ -1857,6 +1859,7 @@ static void
 wctc4xxp_disable_polling(struct wcdte *wc)
 {
 	clear_bit(DTE_POLLING, &wc->flags);
+	wctc4xxp_setctl(wc, 0x0058, 0x0);
 	wctc4xxp_enable_interrupts(wc);
 }
 
@@ -2014,23 +2017,6 @@ wctc4xxp_handle_receive_ring(struct wcdte *wc)
 	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
 wctc4xxp_read(struct file *file, char __user *frame, size_t count, loff_t *ppos)
@@ -2187,18 +2173,6 @@ wctc4xxp_write(struct file *file, const char __user *frame,
 	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;
 }
 
@@ -2581,7 +2555,9 @@ DAHDI_IRQ_HANDLER(wctc4xxp_interrupt)
 	u32 reg;
 #define TX_COMPLETE_INTERRUPT 0x00000001
 #define RX_COMPLETE_INTERRUPT 0x00000040
-#define NORMAL_INTERRUPTS (TX_COMPLETE_INTERRUPT | RX_COMPLETE_INTERRUPT)
+#define TIMER_INTERRUPT	      (1<<11)
+#define NORMAL_INTERRUPTS (TX_COMPLETE_INTERRUPT | RX_COMPLETE_INTERRUPT | \
+			   TIMER_INTERRUPT)
 
 	/* Read and clear interrupts */
 	ints = __wctc4xxp_getctl(wc, 0x0028);
@@ -2601,6 +2577,11 @@ DAHDI_IRQ_HANDLER(wctc4xxp_interrupt)
 			reg |= RX_COMPLETE_INTERRUPT;
 		}
 
+		if (ints & TIMER_INTERRUPT) {
+			wctc4xxp_handle_receive_ring(wc);
+			reg |= TIMER_INTERRUPT;
+		}
+
 #if DEFERRED_PROCESSING == WORKQUEUE
 		schedule_work(&wc->deferred_work);
 #elif DEFERRED_PROCESSING == INTERRUPT
@@ -3556,14 +3537,6 @@ wctc4xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	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.
 	 * --------------------------------------------------------------- */
@@ -3684,9 +3657,6 @@ static void __devexit wctc4xxp_remove_one(struct pci_dev *pdev)
 
 	/* 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);
 
 	/* Stop any DMA */

commit 0efce00a0948932e2be84bd72eda3d766d34fa9f
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 9 09:46:26 2014 -0500

    wctc4xxp: Make sure csm_encaps commands are sent before RTP.
    
    Otherwise, if there are many RTP commands queued on the command list, some of
    the CSM_ENCAP packets, like ACKS, weren't being sent to the firmware within the
    timeout value.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index fb3058d..5dc8daa 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1548,6 +1548,12 @@ static void wctc4xxp_cleanup_command_list(struct wcdte *wc)
 	}
 }
 
+static inline bool is_rtp_packet(const struct tcb *cmd)
+{
+	const struct ethhdr *ethhdr = cmd->data;
+	return (cpu_to_be16(ETH_P_IP) == ethhdr->h_proto);
+}
+
 static void
 wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 {
@@ -1591,6 +1597,14 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 		list_add_tail(&cmd->node, &wc->waiting_for_response_list);
 		mod_timer(&wc->watchdog, jiffies + HZ/2);
 	}
+	if (!list_empty(&wc->cmd_list)) {
+		if (is_rtp_packet(cmd))
+			list_add_tail(&cmd->node, &wc->cmd_list);
+		else
+			list_move(&cmd->node, &wc->cmd_list);
+		spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+		return;
+	}
 	res = wctc4xxp_submit(wc->txd, cmd);
 	if (-EBUSY == res) {
 		/* Looks like we're out of room in the descriptor
@@ -2482,6 +2496,7 @@ static void service_tx_ring(struct wcdte *wc)
 	struct tcb *cmd;
 	unsigned long flags;
 	while ((cmd = wctc4xxp_retrieve(wc->txd))) {
+		spin_lock_irqsave(&wc->cmd_list_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
@@ -2499,17 +2514,16 @@ static void service_tx_ring(struct wcdte *wc)
 		/* 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_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;
+			if (cmd->flags & (WAIT_FOR_ACK | WAIT_FOR_RESPONSE)) {
+				list_add_tail(&cmd->node,
+					      &wc->waiting_for_response_list);
+			}
+			wctc4xxp_submit(wc->txd, cmd);
 		}
 		spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
-
-		if (cmd)
-			wctc4xxp_transmit_cmd(wc, cmd);
 	}
 }
 

commit 67e422c1efc7a5a7a1a1e4904d8424db55c0b115
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 9 09:40:24 2014 -0500

    wctc4xxp: Reduce the number of locks grabbed when sending commands
    
    Not only does this make it atomic when moving commands from the
    waiting_for_response_list to the command_list if the descriptor is full, it will
    also make the entire process of submitting a packet the packet transmission
    logic atomic.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 4a8cf2d..fb3058d 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1548,41 +1548,11 @@ 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.
- */
-static void
-wctc4xxp_add_to_command_list(struct wcdte *wc, struct tcb *cmd)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&wc->cmd_list_lock, flags);
-	list_add_tail(&cmd->node, &wc->cmd_list);
-	spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
-}
-
-static void
-wctc4xxp_add_to_response_list(struct wcdte *wc, struct tcb *cmd)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&wc->cmd_list_lock, flags);
-	list_add_tail(&cmd->node, &wc->waiting_for_response_list);
-	spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
-}
-
-static void
-wctc4xxp_remove_from_response_list(struct wcdte *wc, struct tcb *cmd)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&wc->cmd_list_lock, flags);
-	list_del_init(&cmd->node);
-	spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
-}
-
 static void
 wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 {
 	int res;
+	unsigned long flags;
 
 	/* If we're shutdown all commands will timeout. Just complete the
 	 * command here with the timeout flag */
@@ -1606,6 +1576,8 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 	WARN_ON(cmd->response);
 	WARN_ON(cmd->flags & TX_COMPLETE);
 	cmd->timeout = jiffies + HZ/4;
+
+	spin_lock_irqsave(&wc->cmd_list_lock, flags);
 	if (cmd->flags & (WAIT_FOR_ACK | WAIT_FOR_RESPONSE)) {
 		if (cmd->flags & WAIT_FOR_RESPONSE) {
 			/* We don't need both an ACK and a response.  Let's
@@ -1616,7 +1588,7 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 			hdr->control |= SUPPRESS_ACK;
 		}
 		WARN_ON(!list_empty(&cmd->node));
-		wctc4xxp_add_to_response_list(wc, cmd);
+		list_add_tail(&cmd->node, &wc->waiting_for_response_list);
 		mod_timer(&wc->watchdog, jiffies + HZ/2);
 	}
 	res = wctc4xxp_submit(wc->txd, cmd);
@@ -1626,8 +1598,7 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 		 * 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);
+		list_move_tail(&cmd->node, &wc->cmd_list);
 	} else if (0 == res) {
 		if (!(cmd->flags & DO_NOT_CAPTURE))
 			wctc4xxp_net_capture_cmd(wc, cmd);
@@ -1636,6 +1607,7 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 		/* Unknown return value... */
 		WARN_ON(1);
 	}
+	spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
 }
 
 static int

commit cbe4825d1a2e8d1accc0a4a8133a5135e4171aea
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Thu May 8 16:45:36 2014 -0500

    wctc4xxp: Trivial removal of the receiveprep function.
    
    This was more a holdover when the AN983 interface was brought over from the
    voicebus driver.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 75e67df..4a8cf2d 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -2505,23 +2505,6 @@ queue_rtp_packet(struct wcdte *wc, struct tcb *cmd)
 	return;
 }
 
-static inline void
-wctc4xxp_receiveprep(struct wcdte *wc, struct tcb *cmd)
-{
-	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_DEBUG(DTE_DEBUG_GENERAL,
-		   "Unknown packet protocol received: %04x.\n",
-		   be16_to_cpu(ethhdr->h_proto));
-		free_cmd(cmd);
-	}
-}
-
 static void service_tx_ring(struct wcdte *wc)
 {
 	struct tcb *cmd;
@@ -2571,11 +2554,23 @@ static void service_rx_ring(struct wcdte *wc)
 	 * Process the received packets
 	 */
 	while (!list_empty(&local_list)) {
+		const struct ethhdr *ethhdr;
+
 		cmd = container_of(local_list.next, struct tcb, node);
+		ethhdr = (const struct ethhdr *)(cmd->data);
 		list_del_init(&cmd->node);
 
 		wctc4xxp_net_capture_cmd(wc, cmd);
-		wctc4xxp_receiveprep(wc, cmd);
+		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_DEBUG(DTE_DEBUG_GENERAL,
+			   "Unknown packet protocol received: %04x.\n",
+			   be16_to_cpu(ethhdr->h_proto));
+			free_cmd(cmd);
+		}
 	}
 	wctc4xxp_receive_demand_poll(wc);
 }

commit b5ac763f29c88b09682d1f50096b21745e9ae8a1
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Thu May 8 13:46:18 2014 -0500

    wctc4xxp: Cleanup RTP for unopened channels.
    
    When we start the shutdown sequence for a channel, there is no need to submit
    any RTP packets that are queued on the command list. Under extreme load with
    many backed up RTP packets it was possible to have RTP packets submitted after
    the channel shutdown process started.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/dahdi_transcode.c b/drivers/dahdi/dahdi_transcode.c
index 075391c..a495dcf 100644
--- a/drivers/dahdi/dahdi_transcode.c
+++ b/drivers/dahdi/dahdi_transcode.c
@@ -168,8 +168,9 @@ static void dtc_release(struct dahdi_transcoder_channel *chan)
 	BUG_ON(!chan);
 	if (chan->parent && chan->parent->release) {
 		chan->parent->release(chan);
+	} else {
+		dahdi_tc_clear_busy(chan);
 	}
-	dahdi_tc_clear_busy(chan);
 }
 
 static int dahdi_tc_release(struct inode *inode, struct file *file)
diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 7323535..75e67df 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1421,7 +1421,7 @@ static struct tcb *
 wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct dahdi_transcoder_channel *dtc,
 	size_t inbytes)
 {
-	const struct channel_pvt *cpvt = dtc->pvt;
+	struct channel_pvt *cpvt = dtc->pvt;
 	struct rtp_packet *packet;
 	struct tcb *cmd;
 
@@ -1429,6 +1429,7 @@ wctc4xxp_create_rtp_cmd(struct wcdte *wc, struct dahdi_transcoder_channel *dtc,
 	if (!cmd)
 		return NULL;
 
+	cmd->cpvt = cpvt;
 	packet = cmd->data;
 
 	BUG_ON(cmd->data_len < sizeof(*packet));
@@ -1698,6 +1699,16 @@ wctc4xxp_cleanup_channel_private(struct wcdte *wc,
 	unsigned long flags;
 	LIST_HEAD(local_list);
 
+	/* Once we cleanup this channel, we do not want any queued packets
+	 * waiting to be transmitted. Anything on the hardware descriptor ring
+	 * will be flushed by the csm_encaps command to shutdown the channel. */
+	spin_lock_irqsave(&wc->cmd_list_lock, flags);
+	list_for_each_entry_safe(cmd, temp, &wc->cmd_list, node) {
+		if (cmd->cpvt == cpvt)
+			list_move(&cmd->node, &local_list);
+	}
+	spin_unlock_irqrestore(&wc->cmd_list_lock, flags);
+
 	spin_lock_irqsave(&cpvt->lock, flags);
 	list_splice_init(&cpvt->rx_queue, &local_list);
 	dahdi_tc_clear_data_waiting(dtc);
@@ -1913,7 +1924,9 @@ wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
 			packets_sent, packets_received);
 	}
 
+
 	/* Remove any packets that are waiting on the outbound queue. */
+	dahdi_tc_clear_busy(dtc);
 	wctc4xxp_cleanup_channel_private(wc, dtc);
 	index = cpvt->timeslot_in_num/2;
 	BUG_ON(index >= wc->numchannels);
@@ -2480,11 +2493,15 @@ queue_rtp_packet(struct wcdte *wc, struct tcb *cmd)
 	}
 
 	cpvt = dtc->pvt;
-	spin_lock_irqsave(&cpvt->lock, flags);
-	list_add_tail(&cmd->node, &cpvt->rx_queue);
-	dahdi_tc_set_data_waiting(dtc);
-	spin_unlock_irqrestore(&cpvt->lock, flags);
-	dahdi_transcoder_alert(dtc);
+	if (dahdi_tc_is_busy(dtc)) {
+		spin_lock_irqsave(&cpvt->lock, flags);
+		list_add_tail(&cmd->node, &cpvt->rx_queue);
+		dahdi_tc_set_data_waiting(dtc);
+		spin_unlock_irqrestore(&cpvt->lock, flags);
+		dahdi_transcoder_alert(dtc);
+	} else {
+		free_cmd(cmd);
+	}
 	return;
 }
 

commit 6341783cc868dd01896552a458c66a28d5439270
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Tue May 6 11:47:56 2014 -0500

    wctc4xxp: All the commands do not need to have completions embedded in them.
    
    A small percentage of the total packets sent to the DTE ever wait for
    completions. This will save on the need to keep the completion around in all the
    packets.
    
    Also, since we can use the presence of the completion as the flag whether we
    intend to auto free, we can simplify the flags as well.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 99befe6..7323535 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -192,20 +192,15 @@ struct tcb {
 	struct list_head node;
 	unsigned long timeout;
 	unsigned long retries;
-	/* NOTE:  these flags aren't bit fields because some of the flags are
-	 * combinations of the other ones. */
-#define DO_NOT_AUTO_FREE        (1 << 0)
 #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_ACK		(1 << 3)
+#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)
 	unsigned long flags;
+	struct completion *complete;
 	struct tcb *response;
 	struct channel_pvt *cpvt;
-	struct completion complete;
 	/* The number of bytes available in data. */
 	int data_len;
 };
@@ -221,7 +216,6 @@ static inline void
 initialize_cmd(struct tcb *cmd, unsigned long cmd_flags)
 {
 	INIT_LIST_HEAD(&cmd->node);
-	init_completion(&cmd->complete);
 	cmd->flags = cmd_flags;
 }
 
@@ -1525,9 +1519,9 @@ static void wctc4xxp_timeout_all_commands(struct wcdte *wc)
 
 	list_for_each_entry_safe(cmd, temp, &local_list, node) {
 		list_del_init(&cmd->node);
-		if (cmd->flags & DO_NOT_AUTO_FREE) {
+		if (cmd->complete) {
 			cmd->flags |= DTE_CMD_TIMEOUT;
-			complete(&cmd->complete);
+			complete(cmd->complete);
 		} else {
 			free_cmd(cmd);
 		}
@@ -1592,10 +1586,10 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 	/* If we're shutdown all commands will timeout. Just complete the
 	 * command here with the timeout flag */
 	if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
-		if (cmd->flags & DO_NOT_AUTO_FREE) {
+		if (cmd->complete) {
 			cmd->flags |= DTE_CMD_TIMEOUT;
 			list_del_init(&cmd->node);
-			complete(&cmd->complete);
+			complete(cmd->complete);
 		} else {
 			list_del(&cmd->node);
 			free_cmd(cmd);
@@ -1611,8 +1605,8 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 	WARN_ON(cmd->response);
 	WARN_ON(cmd->flags & TX_COMPLETE);
 	cmd->timeout = jiffies + HZ/4;
-	if (cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE)) {
-		if (cmd->flags & __WAIT_FOR_RESPONSE) {
+	if (cmd->flags & (WAIT_FOR_ACK | WAIT_FOR_RESPONSE)) {
+		if (cmd->flags & WAIT_FOR_RESPONSE) {
 			/* We don't need both an ACK and a response.  Let's
 			 * tell the DTE not to generate an ACK, and we'll just
 			 * retry if we do not get the response within the
@@ -1646,9 +1640,11 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 static int
 wctc4xxp_transmit_cmd_and_wait(struct wcdte *wc, struct tcb *cmd)
 {
-	cmd->flags |= DO_NOT_AUTO_FREE;
+	DECLARE_COMPLETION_ONSTACK(done);
+	cmd->complete = &done;
 	wctc4xxp_transmit_cmd(wc, cmd);
-	wait_for_completion(&cmd->complete);
+	wait_for_completion(&done);
+	cmd->complete = NULL;
 	if (cmd->flags & DTE_CMD_TIMEOUT) {
 		DTE_DEBUG(DTE_DEBUG_GENERAL, "Timeout waiting for command.\n");
 		return -EIO;
@@ -2266,12 +2262,12 @@ static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 			}
 
 			list_del_init(&pos->node);
-			pos->flags &= ~(__WAIT_FOR_RESPONSE);
+			pos->flags &= ~(WAIT_FOR_RESPONSE);
 			pos->response = cmd;
 			/* 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);
+			if (pos->flags & TX_COMPLETE && pos->complete)
+				complete(pos->complete);
 			handled = true;
 
 			break;
@@ -2302,21 +2298,21 @@ do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
 		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->complete));
 			WARN_ON(!(pos->flags & TX_COMPLETE));
 			list_del_init(&pos->node);
-			WARN_ON(!(pos->flags & TX_COMPLETE));
-			complete(&pos->complete);
+			if (pos->complete)
+				complete(pos->complete);
 		} else if ((listhdr->seq_num == rxhdr->seq_num) &&
 			   (listhdr->channel == rxhdr->channel)) {
-			if (pos->flags & __WAIT_FOR_RESPONSE) {
-				pos->flags &= ~(__WAIT_FOR_ACK);
+			if (pos->flags & WAIT_FOR_RESPONSE) {
+				pos->flags &= ~(WAIT_FOR_ACK);
 			} else {
 				list_del_init(&pos->node);
 
-				if (pos->flags & DO_NOT_AUTO_FREE) {
+				if (pos->complete) {
 					WARN_ON(!(pos->flags & TX_COMPLETE));
-					complete(&pos->complete);
+					complete(pos->complete);
 				} else {
 					free_cmd(pos);
 				}
@@ -2368,6 +2364,11 @@ print_command(struct wcdte *wc, const struct tcb *cmd)
 	kfree(buffer);
 }
 
+static inline void wctc4xxp_reset_processor(struct wcdte *wc)
+{
+	wctc4xxp_setctl(wc, 0x00A0, 0x04000000);
+}
+
 static void
 receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 {
@@ -2416,6 +2417,7 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 				   "Received alert (0x%04x) from dsp. Please reload driver.\n",
 				   alert_type);
 
+				wctc4xxp_reset_processor(wc);
 				set_bit(DTE_SHUTDOWN, &wc->flags);
 				wctc4xxp_timeout_all_commands(wc);
 			} else {
@@ -2509,14 +2511,14 @@ static void service_tx_ring(struct wcdte *wc)
 	unsigned long flags;
 	while ((cmd = wctc4xxp_retrieve(wc->txd))) {
 		cmd->flags |= TX_COMPLETE;
-		if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) {
+		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) {
+			if (cmd->complete) {
 				WARN_ON(!(cmd->flags & TX_COMPLETE));
-				complete(&cmd->complete);
+				complete(cmd->complete);
 			} else {
 				free_cmd(cmd);
 			}
@@ -2882,6 +2884,7 @@ wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware)
 	unsigned int byteloc;
 	unsigned int length;
 	struct tcb *cmd;
+	DECLARE_COMPLETION_ONSTACK(done);
 
 	byteloc = 17;
 
@@ -2902,8 +2905,9 @@ wctc4xxp_load_firmware(struct wcdte *wc, const struct firmware *firmware)
 		memcpy(cmd->data, &firmware->data[byteloc], length);
 		byteloc += length;
 		cmd->flags = WAIT_FOR_ACK;
+		cmd->complete = &done;
 		wctc4xxp_transmit_cmd(wc, cmd);
-		wait_for_completion(&cmd->complete);
+		wait_for_completion(&done);
 		if (cmd->flags & DTE_CMD_TIMEOUT) {
 			free_cmd(cmd);
 			dev_err(&wc->pdev->dev, "Failed to load firmware.\n");
@@ -2938,8 +2942,7 @@ wctc4xxp_turn_off_booted_led(struct wcdte *wc)
 	DTE_DEBUG(DTE_DEBUG_GENERAL, "PHY register 0 = %X\n",
 	   wctc4xxp_read_phy(wc, 0));
 
-	/* Set reset */
-	wctc4xxp_setctl(wc, 0x00A0, 0x04000000);
+	wctc4xxp_reset_processor(wc);
 
 	/* Wait 4 ms to ensure processor reset */
 	msleep(4);
@@ -3306,8 +3309,10 @@ wctc4xxp_watchdog(unsigned long data)
 
 					cmd->flags |= DTE_CMD_TIMEOUT;
 					list_del_init(&cmd->node);
-					complete(&cmd->complete);
+					if (cmd->complete)
+						complete(cmd->complete);
 
+					wctc4xxp_reset_processor(wc);
 					set_bit(DTE_SHUTDOWN, &wc->flags);
 					spin_unlock(&wc->cmd_list_lock);
 					_wctc4xxp_stop_dma(wc);
@@ -3323,7 +3328,8 @@ wctc4xxp_watchdog(unsigned long data)
 				 */
 				cmd->flags |= DTE_CMD_TIMEOUT;
 				list_del_init(&cmd->node);
-				complete(&cmd->complete);
+				if (cmd->complete)
+					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

commit ea04099e7769f5e0d9f9681bc044b6544d05014a
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Mon May 5 14:47:44 2014 -0500

    wctc4xxp: Encode the function in the ACK.
    
    While not required by the protocol to the DTE, this does help when debugging the
    trace files.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 5185b7d..99befe6 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -2208,7 +2208,7 @@ wctc4xxp_write(struct file *file, const char __user *frame,
 }
 
 static void
-wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel)
+wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel, __le16 function)
 {
 	struct tcb *cmd;
 	struct csm_encaps_hdr *hdr;
@@ -2224,6 +2224,7 @@ wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel)
 	hdr->seq_num = seqno;
 	hdr->control = 0xe0;
 	hdr->channel = channel;
+	hdr->function = function;
 
 	wctc4xxp_transmit_cmd(wc, cmd);
 }
@@ -2375,8 +2376,10 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 	if (!(hdr->control & MESSAGE_PACKET)) {
 		const bool suppress_ack = ((hdr->control & SUPPRESS_ACK) > 0);
 
-		if (!suppress_ack)
-			wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel);
+		if (!suppress_ack) {
+			wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel,
+					  hdr->function);
+		}
 
 		if (is_response(hdr)) {
 

commit bc274e1b5d9ca3b9e3927568d0860ebe307c1033
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Mon May 5 14:10:57 2014 -0500

    wctc4xxp: We always want to ack the responses.
    
    Furthermore, do it as soon as we know we should to prevent the ack from
    potentially going out after another CSM_ENCAPS packet on another CPU.
    
    Previously, we would not send ACKS to responses we believed we already responded
    to.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 3d67c90..5185b7d 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -2374,19 +2374,15 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 
 	if (!(hdr->control & MESSAGE_PACKET)) {
 		const bool suppress_ack = ((hdr->control & SUPPRESS_ACK) > 0);
+
+		if (!suppress_ack)
+			wctc4xxp_send_ack(wc, hdr->seq_num, hdr->channel);
+
 		if (is_response(hdr)) {
-			u8 seq_num = hdr->seq_num;
-			__be16 channel = hdr->channel;
 
 			do_rx_response_packet(wc, cmd);
-			if (!suppress_ack)
-				wctc4xxp_send_ack(wc, seq_num, channel);
 
 		} else if (0xc1 == hdr->type) {
-			if (!suppress_ack) {
-				wctc4xxp_send_ack(wc, hdr->seq_num,
-						  hdr->channel);
-			}
 
 			if (0x75 == hdr->class) {
 				dev_warn(&wc->pdev->dev,
@@ -2395,10 +2391,6 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 			}
 			free_cmd(cmd);
 		} else if (0xd4 == hdr->type) {
-			if (!suppress_ack) {
-				wctc4xxp_send_ack(wc, hdr->seq_num,
-						  hdr->channel);
-			}
 			if (hdr->params[0] != le16_to_cpu(0xffff)) {
 				dev_warn(&wc->pdev->dev,
 				   "DTE Failed self test (%04x).\n",
@@ -2414,10 +2406,6 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 			}
 			free_cmd(cmd);
 		} else if (MONITOR_LIVE_INDICATION_TYPE == hdr->type) {
-			if (!suppress_ack) {
-				wctc4xxp_send_ack(wc, hdr->seq_num,
-						  hdr->channel);
-			}
 
 			if (hdr->function == 0x0000) {
 				u16 alert_type = le16_to_cpu(hdr->params[0]);
@@ -2434,10 +2422,6 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 			print_command(wc, cmd);
 			free_cmd(cmd);
 		} else {
-			if (!suppress_ack) {
-				wctc4xxp_send_ack(wc, hdr->seq_num,
-						  hdr->channel);
-			}
 			dev_warn(&wc->pdev->dev,
 			  "Unknown command type received. %02x\n", hdr->type);
 			free_cmd(cmd);

commit 44a33126e0fa7df0ca568aa749e9db959d64e41c
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Mon May 5 13:54:47 2014 -0500

    wctc4xxp: Only capture commands once they are on the descriptor ring.
    
    Eliminates some cases where there are duplicated packets in the capture if the
    hardware descriptor ring was already full.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index b3d6714..3d67c90 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1624,8 +1624,6 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 		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);
 	res = wctc4xxp_submit(wc->txd, cmd);
 	if (-EBUSY == res) {
 		/* Looks like we're out of room in the descriptor
@@ -1636,6 +1634,8 @@ wctc4xxp_transmit_cmd(struct wcdte *wc, struct tcb *cmd)
 		wctc4xxp_remove_from_response_list(wc, cmd);
 		wctc4xxp_add_to_command_list(wc, cmd);
 	} else if (0 == res) {
+		if (!(cmd->flags & DO_NOT_CAPTURE))
+			wctc4xxp_net_capture_cmd(wc, cmd);
 		wctc4xxp_transmit_demand_poll(wc);
 	} else {
 		/* Unknown return value... */

commit 3446cdca8f4d4d77aeba73c742448eb438baa836
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Mon May 5 12:08:20 2014 -0500

    wctc4xxp: Do not allow duplicated sequence numbers to be received for the channels.
    
    Makes the channels themselves behave like the supervisor channel. This only
    protects the driver in the case the commands were severly backed up, like when
    there was high packet loss.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 17d0fb6..b3d6714 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -204,6 +204,7 @@ struct tcb {
 #define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE)
 	unsigned long flags;
 	struct tcb *response;
+	struct channel_pvt *cpvt;
 	struct completion complete;
 	/* The number of bytes available in data. */
 	int data_len;
@@ -289,6 +290,7 @@ struct channel_pvt {
 	u16 seqno;
 	u8 cmd_seqno;
 	u8 ssrc;
+	u8 last_rx_seq_num;
 	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 */
@@ -1041,6 +1043,7 @@ create_supervisor_cmd(struct wcdte *wc, struct tcb *cmd, u8 type, u8 class,
 
 	cmd->flags = WAIT_FOR_RESPONSE;
 	cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters);
+	cmd->cpvt = NULL;
 }
 
 static void
@@ -1069,6 +1072,7 @@ create_channel_cmd(struct channel_pvt *pvt, struct tcb *cmd, u8 type, u8 class,
 
 	cmd->flags = WAIT_FOR_RESPONSE;
 	cmd->data_len = SIZE_WITH_N_PARAMETERS(num_parameters);
+	cmd->cpvt = pvt;
 }
 
 static int
@@ -1669,6 +1673,7 @@ wctc4xxp_init_state(struct channel_pvt *cpvt, int encoder,
 	cpvt->ssrc = 0x78;
 	cpvt->timeslot_in_num = channel*2;
 	cpvt->timeslot_out_num = channel*2;
+	cpvt->last_rx_seq_num = 0xff;
 	if (encoder)
 		++cpvt->timeslot_out_num;
 	else
@@ -2223,15 +2228,18 @@ wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel)
 	wctc4xxp_transmit_cmd(wc, cmd);
 }
 
+
 static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 {
-	const struct csm_encaps_hdr *listhdr, *rxhdr;
+	struct csm_encaps_hdr *rxhdr;
+	const struct csm_encaps_hdr *listhdr;
 	struct tcb *pos, *temp;
 	unsigned long flags;
 	bool handled = false;
 	rxhdr = cmd->data;
+
+	/* Check if duplicated response on the supervisor channel. */
 	if (SUPERVISOR_CHANNEL == rxhdr->channel) {
-		/* We received a duplicate response. */
 		if (rxhdr->seq_num == wc->last_rx_seq_num) {
 			free_cmd(cmd);
 			return;
@@ -2246,6 +2254,16 @@ static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 		if ((listhdr->function == rxhdr->function) &&
 		    (listhdr->channel == rxhdr->channel)) {
 
+			/* If this is a channel command, do not complete it if
+			 * the seq_num is the same as previous. */
+			if (pos->cpvt) {
+				if (rxhdr->seq_num ==
+				    pos->cpvt->last_rx_seq_num) {
+					break;
+				}
+				pos->cpvt->last_rx_seq_num = rxhdr->seq_num;
+			}
+
 			list_del_init(&pos->node);
 			pos->flags &= ~(__WAIT_FOR_RESPONSE);
 			pos->response = cmd;
@@ -3029,6 +3047,8 @@ wctc4xxp_create_channel_pair(struct wcdte *wc, struct channel_pvt *cpvt,
 	decoder_pvt = wc->udecode->channels[decoder_timeslot/2].pvt;
 	BUG_ON(!encoder_pvt);
 	BUG_ON(!decoder_pvt);
+	encoder_pvt->last_rx_seq_num = 0xff;
+	decoder_pvt->last_rx_seq_num = 0xff;
 
 	WARN_ON(encoder_timeslot == decoder_timeslot);
 	/* First, let's create two channels, one for the simple -> complex

commit 391ca2b7aa531439b0c2ef2cac6b9b3bc868ffb5
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 2 20:37:51 2014 -0500

    wctc4xxp: Do not need locks on the transcoder buffers.
    
    They are sufficiently protected by the list locks. This also cleans up a case
    where the tcp was unlocked after already completing it, which was corrupting the
    list.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index f6f3d43..17d0fb6 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -207,7 +207,6 @@ struct tcb {
 	struct completion complete;
 	/* The number of bytes available in data. */
 	int data_len;
-	spinlock_t lock;
 };
 
 static inline const struct csm_encaps_hdr *
@@ -223,7 +222,6 @@ initialize_cmd(struct tcb *cmd, unsigned long cmd_flags)
 	INIT_LIST_HEAD(&cmd->node);
 	init_completion(&cmd->complete);
 	cmd->flags = cmd_flags;
-	spin_lock_init(&cmd->lock);
 }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
@@ -2248,7 +2246,6 @@ static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 		if ((listhdr->function == rxhdr->function) &&
 		    (listhdr->channel == rxhdr->channel)) {
 
-			spin_lock(&pos->lock);
 			list_del_init(&pos->node);
 			pos->flags &= ~(__WAIT_FOR_RESPONSE);
 			pos->response = cmd;
@@ -2256,7 +2253,6 @@ static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 			 * be completed in service_tx_ring. */
 			if (pos->flags & TX_COMPLETE)
 				complete(&pos->complete);
-			spin_unlock(&pos->lock);
 			handled = true;
 
 			break;
@@ -2294,19 +2290,15 @@ do_rx_ack_packet(struct wcdte *wc, struct tcb *cmd)
 			complete(&pos->complete);
 		} 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);
 				}
 			}
@@ -2511,7 +2503,6 @@ static void service_tx_ring(struct wcdte *wc)
 	struct tcb *cmd;
 	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
@@ -2519,15 +2510,11 @@ static void service_tx_ring(struct wcdte *wc)
 			 * 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

commit ec9d162344a8e84a6e0e3f563a800cbfb5bc75ac
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 2 11:07:56 2014 -0500

    wctc4xxp: Check for shutdown after acquiring the mutex lock.
    
    In case we missed an alert, this will allow for rapid shutdown of Asterisk.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 0b38a37..f6f3d43 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1658,7 +1658,6 @@ 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 void
 wctc4xxp_init_state(struct channel_pvt *cpvt, int encoder,
@@ -1750,18 +1749,13 @@ do_channel_allocate(struct dahdi_transcoder_channel *dtc)
 	u8 wctc4xxp_dstfmt; /* Digium Transcoder Engine Dest Format */
 	int res;
 
-#ifndef DEBUG_WCTC4XXP
-	mutex_lock(&wc->chanlock);
-#else
 	if (mutex_lock_interruptible(&wc->chanlock))
 		return -EINTR;
-#endif
 
 	/* Check again to see if the channel was built after grabbing the
 	 * channel lock, in case the previous holder of the lock
 	 * built this channel as a complement to itself. */
 	if (dahdi_tc_is_built(dtc)) {
-		mutex_unlock(&wc->chanlock);
 		DTE_DEBUG(DTE_DEBUG_CHANNEL_SETUP,
 		  "Allocating channel %p which is already built.\n", dtc);
 		return 0;
@@ -1779,7 +1773,6 @@ do_channel_allocate(struct dahdi_transcoder_channel *dtc)
 		wctc4xxp_dstfmt);
 	if (res) {
 		/* There was a problem creating the channel.... */
-		mutex_unlock(&wc->chanlock);
 		dev_err(&wc->pdev->dev, "Failed to create channel pair.\n");
 		return res;
 	}
@@ -1792,7 +1785,6 @@ do_channel_allocate(struct dahdi_transcoder_channel *dtc)
 	/* Mark the channel complement (other half of encoder/decoder pair) as
 	 * built */
 	wctc4xxp_mark_channel_complement_built(wc, dtc);
-	mutex_unlock(&wc->chanlock);
 	dahdi_transcoder_alert(dtc);
 	return 0;
 }
@@ -1829,12 +1821,22 @@ wctc4xxp_enable_polling(struct wcdte *wc)
 static int
 wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc)
 {
+	int res;
 	struct wcdte *wc = ((struct channel_pvt *)(dtc->pvt))->wc;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+	mutex_lock(&wc->chanlock);
+#else
+	res = mutex_lock_killable(&wc->chanlock);
+	if (res)
+		return res;
+#endif
+
 	if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
 		/* The shudown flags can also be set if there is a
 		 * catastrophic failure. */
-		return -EIO;
+		res = -EIO;
+		goto error_exit;
 	}
 
 	atomic_inc(&wc->open_channels);
@@ -1848,7 +1850,11 @@ wctc4xxp_operation_allocate(struct dahdi_transcoder_channel *dtc)
 		  "Allocating channel %p which is already built.\n", dtc);
 		return 0;
 	}
-	return do_channel_allocate(dtc);
+	res = do_channel_allocate(dtc);
+
+error_exit:
+	mutex_unlock(&wc->chanlock);
+	return res;
 }
 
 static void
@@ -1874,19 +1880,21 @@ wctc4xxp_operation_release(struct dahdi_transcoder_channel *dtc)
 	BUG_ON(!cpvt);
 	BUG_ON(!wc);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+	mutex_lock(&wc->chanlock);
+#else
+	res = mutex_lock_killable(&wc->chanlock);
+	if (res)
+		return res;
+#endif
+
 	if (unlikely(test_bit(DTE_SHUTDOWN, &wc->flags))) {
 		/* The shudown flags can also be set if there is a
 		 * catastrophic failure. */
-		return -EIO;
+		res = -EIO;
+		goto error_exit;
 	}
 
-#ifndef DEBUG_WCTC4XXP
-	mutex_lock(&wc->chanlock);
-#else
-	if (mutex_lock_interruptible(&wc->chanlock))
-		return -EINTR;
-#endif
-
 	atomic_dec(&wc->open_channels);
 
 #if !defined(CONFIG_WCTC4XXP_POLLING)
@@ -3141,7 +3149,7 @@ error_exit:
 
 
 static int
-__wctc4xxp_setup_channels(struct wcdte *wc)
+wctc4xxp_setup_channels(struct wcdte *wc)
 {
 	struct tcb *cmd;
 	int tdm_bus;
@@ -3198,22 +3206,6 @@ error_exit:
 	return -1;
 }
 
-static int
-wctc4xxp_setup_channels(struct wcdte *wc)
-{
-	int ret;
-#ifndef DEBUG_WCTC4XXP
-	mutex_lock(&wc->chanlock);
-#else
-	if (mutex_lock_interruptible(&wc->chanlock))
-		return -EINTR;
-#endif
-	ret = __wctc4xxp_setup_channels(wc);
-	mutex_unlock(&wc->chanlock);
-
-	return ret;
-}
-
 static void wctc4xxp_setup_file_operations(struct file_operations *fops)
 {
 	fops->owner = THIS_MODULE;

commit 7168b87cb593ebc3025042297c7019402279963a
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 2 11:04:48 2014 -0500

    wctc4xxp: Always ack a response packet.
    
    Even if it is duplicated or we don't have an outbound message waiting, we should
    ack it so that the firmware does not keep trying to send it to the host.
    Otherwise the firmware could get into situations where it was constantly
    retrying to send packets for which it did not receive our previous ACK and
    exhaust memory.
    
    I was only seeing this on platforms were packets were going missing in the
    stream, increasing the probability that the driver would miss early responses.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index d498089..0b38a37 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -2217,7 +2217,7 @@ wctc4xxp_send_ack(struct wcdte *wc, u8 seqno, __be16 channel)
 	wctc4xxp_transmit_cmd(wc, cmd);
 }
 
-static bool do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
+static void do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 {
 	const struct csm_encaps_hdr *listhdr, *rxhdr;
 	struct tcb *pos, *temp;
@@ -2228,7 +2228,7 @@ static bool do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 		/* We received a duplicate response. */
 		if (rxhdr->seq_num == wc->last_rx_seq_num) {
 			free_cmd(cmd);
-			return false;
+			return;
 		}
 		wc->last_rx_seq_num = rxhdr->seq_num;
 	}
@@ -2261,10 +2261,7 @@ static bool do_rx_response_packet(struct wcdte *wc, struct tcb *cmd)
 			"Freeing unhandled response ch:(%04x)\n",
 			be16_to_cpu(rxhdr->channel));
 		free_cmd(cmd);
-		return false;
 	}
-
-	return true;
 }
 
 static void
@@ -2363,7 +2360,8 @@ receive_csm_encaps_packet(struct wcdte *wc, struct tcb *cmd)
 			u8 seq_num = hdr->seq_num;
 			__be16 channel = hdr->channel;
 
-			if (do_rx_response_packet(wc, cmd) && !suppress_ack)
+			do_rx_response_packet(wc, cmd);
+			if (!suppress_ack)
 				wctc4xxp_send_ack(wc, seq_num, channel);
 
 		} else if (0xc1 == hdr->type) {

commit f8a6f55e801a2a4f38f6c5efd405a52708920db0
Author: Shaun Ruffell <sruffell at digium.com>
Date:   Fri May 2 10:48:30 2014 -0500

    wctc4xxp: Enable the fatal bus error interrupt.
    
    The kernel log will now contain reports if there are bus errors.
    This is a troubleshooting aide on systems with bus issues.
    
    Signed-off-by: Shaun Ruffell <sruffell at digium.com>
    Signed-off-by: Russ Meyerriecks <rmeyerriecks at digium.com>

diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
index 3ec969b..d498089 100644
--- a/drivers/dahdi/wctc4xxp/base.c
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -1807,7 +1807,7 @@ wctc4xxp_setintmask(struct wcdte *wc, unsigned int intmask)
 static void
 wctc4xxp_enable_interrupts(struct wcdte *wc)
 {
-	wctc4xxp_setintmask(wc, 0x000180c0);
+	wctc4xxp_setintmask(wc, 0x0001a0c0);
 }
 
 static void
@@ -2617,8 +2617,8 @@ DAHDI_IRQ_HANDLER(wctc4xxp_interrupt)
 		if ((ints & 0x00008000) && debug)
 			dev_info(&wc->pdev->dev, "Abnormal Interrupt.\n");
 
-		if ((ints & 0x00002000) && debug)
-			dev_info(&wc->pdev->dev, "Fatal Bus Error INT\n");
+		if (ints & 0x00002000)
+			dev_err(&wc->pdev->dev, "Fatal Bus Error Detected.\n");
 
 		if ((ints & 0x00000100) && debug)
 			dev_info(&wc->pdev->dev, "Receive Stopped INT\n");

commit 6c796d0774f103be5523c29d076b43623a371ef3
Author: Shaun Ruffell <sruffell at digium.com>
... 419 lines suppressed ...


-- 
dahdi/linux.git



More information about the dahdi-commits mailing list