summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-08-16 17:27:12 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-08-16 17:27:12 +0000
commit8239ad02390c0feec4c726160b7519f04caf25b9 (patch)
tree3566504c9c9f3ba77127c954d4f6d46bd565d02e
parente4dfecf0f034a72e26d3cc0fc96b245e191fc553 (diff)
Merge Paul Cadach's TDMoE fixes for using tasklet (Thanks!)
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@450 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xztd-eth.c39
-rwxr-xr-xztdynamic.c73
2 files changed, 101 insertions, 11 deletions
diff --git a/ztd-eth.c b/ztd-eth.c
index 91745f7..4975d0c 100755
--- a/ztd-eth.c
+++ b/ztd-eth.c
@@ -134,32 +134,41 @@ static int ztdeth_transmit(void *pvt, unsigned char *msg, int msglen)
struct sk_buff *skb;
struct ztdeth_header *zh;
unsigned long flags;
+ struct net_device *dev;
+ unsigned char addr[ETH_ALEN];
+ unsigned short subaddr; /* Network byte order */
spin_lock_irqsave(&zlock, flags);
z = pvt;
if (z->dev) {
- skb = dev_alloc_skb(msglen + z->dev->hard_header_len + sizeof(struct ztdeth_header) + 32);
+ /* Copy fields to local variables to remove spinlock ASAP */
+ dev = z->dev;
+ memcpy(addr, z->addr, sizeof(z->addr));
+ subaddr = z->subaddr;
+ spin_unlock_irqrestore(&zlock, flags);
+ skb = dev_alloc_skb(msglen + dev->hard_header_len + sizeof(struct ztdeth_header) + 32);
if (skb) {
/* Reserve header space */
- skb_reserve(skb, z->dev->hard_header_len + sizeof(struct ztdeth_header));
+ skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header));
/* Copy message body */
memcpy(skb_put(skb, msglen), msg, msglen);
/* Throw on header */
zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header));
- zh->subaddr = z->subaddr;
+ zh->subaddr = subaddr;
/* Setup protocol and such */
skb->protocol = __constant_htons(ETH_P_ZTDETH);
skb->nh.raw = skb->data;
- skb->dev = z->dev;
- if (z->dev->hard_header)
- z->dev->hard_header(skb, z->dev, ETH_P_ZTDETH, z->addr, z->dev->dev_addr, skb->len);
+ skb->dev = dev;
+ if (dev->hard_header)
+ dev->hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
dev_queue_xmit(skb);
}
}
- spin_unlock_irqrestore(&zlock, flags);
+ else
+ spin_unlock_irqrestore(&zlock, flags);
return 0;
}
@@ -245,6 +254,13 @@ static void ztdeth_destroy(void *pvt)
cur = cur->next;
}
spin_unlock_irqrestore(&zlock, flags);
+ if (cur == z) { /* Successfully removed */
+ printk("TDMoE: Removed interface for %s\n", z->span->name);
+ kfree(z);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ }
}
static void *ztdeth_create(struct zt_span *span, char *addr)
@@ -341,6 +357,9 @@ static void *ztdeth_create(struct zt_span *span, char *addr)
z->next = zdevs;
zdevs = z;
spin_unlock_irqrestore(&zlock, flags);
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
}
return z;
}
@@ -372,5 +391,11 @@ static void __exit ztdeth_exit(void)
zt_dynamic_unregister(&ztd_eth);
}
+MODULE_DESCRIPTION("Zaptel Dynamic TDMoE Support");
+MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
module_init(ztdeth_init);
module_exit(ztdeth_exit);
diff --git a/ztdynamic.c b/ztdynamic.c
index 90aa4fa..3515e16 100755
--- a/ztdynamic.c
+++ b/ztdynamic.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/sched.h>
+#include <linux/interrupt.h>
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif
@@ -41,6 +42,16 @@
#endif
/*
+ * Tasklets provide better system interactive response at the cost of the
+ * possibility of losing a frame of data at very infrequent intervals. If
+ * you are more concerned with the performance of your machine, enable the
+ * tasklets. If you are strict about absolutely no drops, then do not enable
+ * tasklets.
+ */
+
+#define ENABLE_TASKLETS
+
+/*
* Dynamic spans implemented using TDM over X with standard message
* types. Message format is as follows:
*
@@ -74,6 +85,18 @@ EXPORT_SYMBOL(zt_dynamic_register);
EXPORT_SYMBOL(zt_dynamic_unregister);
EXPORT_SYMBOL(zt_dynamic_receive);
+#ifdef ENABLE_TASKLETS
+static int taskletrun;
+static int taskletsched;
+static int taskletpending;
+static int taskletexec;
+static int txerrors;
+static struct tasklet_struct ztd_tlet;
+
+static void ztd_tasklet(unsigned long data);
+#endif
+
+
static struct zt_dynamic {
char addr[40];
char dname[20];
@@ -189,15 +212,15 @@ static void ztd_sendmessage(struct zt_dynamic *z)
for (x=0;x<z->span.channels;x++) {
memcpy(buf, z->chans[x].writechunk, ZT_CHUNKSIZE);
- buf += 8;
- msglen += 8;
+ buf += ZT_CHUNKSIZE;
+ msglen += ZT_CHUNKSIZE;
}
z->driver->transmit(z->pvt, z->msgbuf, msglen);
}
-static void ztdynamic_run(void)
+static void __ztdynamic_run(void)
{
unsigned long flags;
struct zt_dynamic *z;
@@ -221,6 +244,21 @@ static void ztdynamic_run(void)
spin_unlock_irqrestore(&dlock, flags);
}
+#ifdef ENABLE_TASKLETS
+static void ztdynamic_run(void)
+{
+ if (!taskletpending) {
+ taskletpending = 1;
+ taskletsched++;
+ tasklet_hi_schedule(&ztd_tlet);
+ } else {
+ txerrors++;
+ }
+}
+#else
+#define ztdynamic_run __ztdynamic_run
+#endif
+
void zt_dynamic_receive(struct zt_span *span, unsigned char *msg, int msglen)
{
struct zt_dynamic *ztd = span->pvt;
@@ -409,6 +447,12 @@ static int destroy_dynamic(ZT_DYNAMIC_SPAN *zds)
spin_unlock_irqrestore(&dlock, flags);
return -EINVAL;
}
+ /* Don't destroy span until it is in use */
+ if (z->usecount) {
+ spin_unlock_irqrestore(&dlock, flags);
+ printk("Attempt to destroy dynamic span while it is in use\n");
+ return -EBUSY;
+ }
/* Unlink it */
cur = dspans;
while(cur) {
@@ -563,7 +607,7 @@ static int create_dynamic(ZT_DYNAMIC_SPAN *zds)
spin_unlock_irqrestore(&dlock, flags);
sprintf(fn, "ztd-%s", zds->driver);
request_module(fn);
- spin_unlock_irqrestore(&dlock, flags);
+ spin_lock_irqsave(&dlock, flags);
ztd = find_driver(zds->driver);
}
spin_unlock_irqrestore(&dlock, flags);
@@ -608,6 +652,18 @@ static int create_dynamic(ZT_DYNAMIC_SPAN *zds)
}
+#ifdef ENABLE_TASKLETS
+static void ztd_tasklet(unsigned long data)
+{
+ taskletrun++;
+ if (taskletpending) {
+ taskletexec++;
+ __ztdynamic_run();
+ }
+ taskletpending = 0;
+}
+#endif
+
static int ztdynamic_ioctl(unsigned int cmd, unsigned long data)
{
ZT_DYNAMIC_SPAN zds;
@@ -741,12 +797,21 @@ int ztdynamic_init(void)
alarmcheck.function = check_for_red_alarm;
/* Check once per second */
mod_timer(&alarmcheck, jiffies + 1 * HZ);
+#ifdef ENABLE_TASKLETS
+ tasklet_init(&ztd_tlet, ztd_tasklet, 0);
+#endif
printk("Zaptel Dynamic Span support LOADED\n");
return 0;
}
void ztdynamic_cleanup(void)
{
+#ifdef ENABLE_TASKLETS
+ if (taskletpending) {
+ tasklet_disable(&ztd_tlet);
+ tasklet_kill(&ztd_tlet);
+ }
+#endif
zt_set_dynamic_ioctl(NULL);
del_timer(&alarmcheck);
printk("Zaptel Dynamic Span support unloaded\n");