summaryrefslogtreecommitdiff
path: root/ztd-eth.c
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 /ztd-eth.c
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
Diffstat (limited to 'ztd-eth.c')
-rwxr-xr-xztd-eth.c39
1 files changed, 32 insertions, 7 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);