[svn-commits] sruffell: linux/trunk r6223 - /linux/trunk/drivers/dahdi/wctc4xxp/base.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Mar 23 18:48:52 CDT 2009


Author: sruffell
Date: Mon Mar 23 18:48:49 2009
New Revision: 6223

URL: http://svn.digium.com/svn-view/dahdi?view=rev&rev=6223
Log:
Create our own free list for commands instead of using kmem_cache.

Modified:
    linux/trunk/drivers/dahdi/wctc4xxp/base.c

Modified: linux/trunk/drivers/dahdi/wctc4xxp/base.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/wctc4xxp/base.c?view=diff&rev=6223&r1=6222&r2=6223
==============================================================================
--- linux/trunk/drivers/dahdi/wctc4xxp/base.c (original)
+++ linux/trunk/drivers/dahdi/wctc4xxp/base.c Mon Mar 23 18:48:49 2009
@@ -187,6 +187,8 @@
 /* Individual channel config commands */
 #define MAX_FRAME_SIZE 1518
 #define SFRAME_SIZE MAX_FRAME_SIZE
+
+#undef USE_CUSTOM_MEMCACHE
 
 /* Transcoder buffer (tcb) */
 struct tcb {
@@ -213,6 +215,9 @@
 	/* The number of bytes available in data. */
 	int data_len;
 	spinlock_t lock;
+#ifdef USE_CUSTOM_MEMCACHE
+	u32 sentinel;
+#endif
 };
 
 static inline void *hdr_from_cmd(struct tcb *cmd)
@@ -237,7 +242,75 @@
 	cmd->data = &cmd->cmd[0];
 	cmd->data_len = SFRAME_SIZE;
 	spin_lock_init(&cmd->lock);
-}
+#ifdef USE_CUSTOM_MEMCACHE
+	cmd->sentinel = 0xdeadbeef;
+#endif
+}
+
+#ifdef USE_CUSTOM_MEMCACHE
+
+struct my_cache {
+	atomic_t outstanding_count;
+	spinlock_t lock;
+	struct list_head free;
+};
+
+static struct tcb *my_cache_alloc(struct my_cache *c, gfp_t alloc_flags)
+{
+	unsigned long flags;
+	struct tcb *cmd;
+	spin_lock_irqsave(&c->lock, flags);
+	if (!list_empty(&c->free)) {
+		cmd = list_entry(c->free.next, struct tcb, node);
+		list_del_init(&cmd->node);
+		spin_unlock_irqrestore(&c->lock, flags);
+	} else {
+		spin_unlock_irqrestore(&c->lock, flags);
+		cmd = kmalloc(sizeof(*cmd), alloc_flags);
+	}
+	atomic_inc(&c->outstanding_count);
+	return cmd;
+}
+
+static void my_cache_free(struct my_cache *c, struct tcb *cmd)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&c->lock, flags);
+	list_add_tail(&cmd->node, &c->free);
+	spin_unlock_irqrestore(&c->lock, flags);
+	atomic_dec(&c->outstanding_count);
+}
+
+static struct my_cache *my_cache_create(void)
+{
+	struct my_cache *c;
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return NULL;
+	spin_lock_init(&c->lock);
+	INIT_LIST_HEAD(&c->free);
+	return c;
+}
+
+static int my_cache_destroy(struct my_cache *c)
+{
+	struct tcb *cmd;
+	if (atomic_read(&c->outstanding_count)) {
+		printk(KERN_WARNING "%s: Leaked %d commands.\n",
+			THIS_MODULE->name, 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. */
@@ -247,12 +320,18 @@
 static struct kmem_cache *cmd_cache;
 #endif
 
+#endif /* USE_CUSTOM_MEMCACHE */
+
 static inline struct tcb *
 __alloc_cmd(gfp_t alloc_flags, unsigned long cmd_flags)
 {
 	struct tcb *cmd;
 
+#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))
 		initialize_cmd(cmd, cmd_flags);
 	return cmd;
@@ -269,7 +348,11 @@
 {
 	if (cmd->data != &cmd->cmd[0])
 		kfree(cmd->data);
+#ifdef USE_CUSTOM_MEMCACHE
+	my_cache_free(cmd_cache, cmd);
+#else
 	kmem_cache_free(cmd_cache, cmd);
+#endif
 	return;
 }
 
@@ -317,12 +400,13 @@
 #define DTE_SHUTDOWN	2
 	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;
 
 	unsigned int seq_num;
@@ -1374,6 +1458,9 @@
 
 	/* 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;
 	}
@@ -2021,10 +2108,8 @@
 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;
 
 	rxhdr = cmd->data;
@@ -2034,14 +2119,18 @@
 		listhdr = pos->data;
 		if ((listhdr->function == rxhdr->function) &&
 		    (listhdr->channel == rxhdr->channel)) {
+
 			spin_lock_irqsave(&pos->lock, flags);
 			list_del_init(&pos->node);
 			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);
 			} 
 			spin_unlock_irqrestore(&pos->lock, flags);
+
 			break;
 		}
 	}
@@ -2051,10 +2140,9 @@
 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;
 
@@ -2071,15 +2159,19 @@
 			complete(&pos->complete);
 		} else if ((listhdr->seq_num == rxhdr->seq_num) &&
 			   (listhdr->channel == rxhdr->channel)) {
+			spin_lock_irqsave(&pos->lock, flags);
 			if (pos->flags & __WAIT_FOR_RESPONSE) {
 				pos->flags &= ~(__WAIT_FOR_ACK);
+				spin_unlock_irqrestore(&pos->lock, flags);
 			} else {
 				list_del_init(&pos->node);
 
 				if (pos->flags & DO_NOT_AUTO_FREE) {
 					WARN_ON(!(pos->flags & TX_COMPLETE));
 					complete(&pos->complete);
+					spin_unlock_irqrestore(&pos->lock, flags);
 				} else {
+					spin_unlock_irqrestore(&pos->lock, flags);
 					free_cmd(pos);
 				}
 			}
@@ -2259,6 +2351,7 @@
 		} 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. */
@@ -2796,6 +2889,7 @@
 	BUG_ON(!encoder_pvt);
 	BUG_ON(!decoder_pvt);
 
+	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,
@@ -2809,6 +2903,7 @@
 	length = (DTE_FORMAT_G729A == complicated) ? G729_LENGTH :
 		(DTE_FORMAT_G723_1 == complicated) ? G723_LENGTH : 0;
 
+	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;
@@ -3513,13 +3608,17 @@
 static int __init wctc4xxp_init(void)
 {
 	int res;
+#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, SLAB_HWCACHE_ALIGN, NULL, NULL);
+			0, SLAB_HWCACHE_ALIGN | SLAB_STORE_USER | SLAB_DEBUG_FREE, NULL, NULL);
 #	else
 	cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct tcb),
 			0, SLAB_HWCACHE_ALIGN, NULL);
 #	endif
+#endif
 
 	if (!cmd_cache)
 		return -ENOMEM;
@@ -3527,7 +3626,11 @@
 	INIT_LIST_HEAD(&wctc4xxp_list);
 	res = dahdi_pci_module(&wctc4xxp_driver);
 	if (res) {
+#ifdef USE_CUSTOM_MEMCACHE
+		my_cache_destroy(cmd_cache);
+#else
 		kmem_cache_destroy(cmd_cache);
+#endif
 		return -ENODEV;
 	}
 	return 0;
@@ -3536,7 +3639,11 @@
 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);




More information about the svn-commits mailing list