diff options
author | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2004-08-16 17:27:12 +0000 |
---|---|---|
committer | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2004-08-16 17:27:12 +0000 |
commit | 8239ad02390c0feec4c726160b7519f04caf25b9 (patch) | |
tree | 3566504c9c9f3ba77127c954d4f6d46bd565d02e | |
parent | e4dfecf0f034a72e26d3cc0fc96b245e191fc553 (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-x | ztd-eth.c | 39 | ||||
-rwxr-xr-x | ztdynamic.c | 73 |
2 files changed, 101 insertions, 11 deletions
@@ -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"); |