[svn-commits] fjoe: freebsd/trunk r8353 - /freebsd/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Thu Mar 18 10:16:00 CDT 2010
Author: fjoe
Date: Thu Mar 18 10:15:56 2010
New Revision: 8353
URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8353
Log:
dynamic_ethmf driver was added to the linux trunk recently: merge it from there.
Modified:
freebsd/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c
Modified: freebsd/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c?view=diff&rev=8353&r1=8352&r2=8353
==============================================================================
--- freebsd/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c (original)
+++ freebsd/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c Thu Mar 18 10:15:56 2010
@@ -3,7 +3,7 @@
*
* Written by Joseph Benden <joe at thrallingpenguin.com>
*
- * Copyright (C) 2007-2008, Thralling Penguin LLC.
+ * Copyright (C) 2007-2010, Thralling Penguin LLC.
*
* All rights reserved.
*
@@ -11,15 +11,15 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
@@ -30,9 +30,6 @@
#include <sys/module.h>
#include "ng_dahdi_netdev.h"
-
-#define ETH_ALEN ETHER_ADDR_LEN
-#define crc32_le(crc, data, len) crc32_raw(data, len, crc)
#else /* !__FreeBSD__ */
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -95,6 +92,9 @@
#if defined(__FreeBSD__)
static char g_padding[ETHMF_MAX_CHANNELS * 8];
static char g_padding_ignore[8];
+
+#define ETH_ALEN ETHER_ADDR_LEN
+#define crc32_le(crc, data, len) crc32_raw(data, len, crc)
#else
static struct sk_buff_head skbs;
#endif
@@ -147,9 +147,33 @@
};
/**
- * Lock for ethmf_list
+ * Lock for adding and removing items in ethmf_list
*/
-static DEFINE_RWLOCK(ethmf_lock);
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(ethmf_lock);
+#else
+static spinlock_t ethmf_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+#if defined(__FreeBSD__)
+static inline void
+rcu_read_lock(void)
+{
+ spin_lock(ðmf_lock);
+}
+
+static inline void
+rcu_read_unlock(void)
+{
+ spin_unlock(ðmf_lock);
+}
+
+#define synchronize_rcu()
+
+#define list_add_rcu(e, l) list_add(e, l)
+#define list_del_rcu(e) list_del(e)
+#define list_for_each_entry_rcu(e, l, elem) list_for_each_entry(e, l, elem)
+#endif /* __FreeBSD__ */
/**
* The active list of all running spans
@@ -191,7 +215,7 @@
{
struct ztdeth *z;
- list_for_each_entry(z, ðmf_list, list) {
+ list_for_each_entry_rcu(z, ðmf_list, list) {
if (!atomic_read(&z->delay)) {
if (!memcmp(addr, z->addr, ETH_ALEN)
&& z->subaddr == subaddr) {
@@ -219,7 +243,7 @@
struct ztdeth *t;
int span_count = 0, spans_ready = 0;
- list_for_each_entry(t, ðmf_list, list) {
+ list_for_each_entry_rcu(t, ðmf_list, list) {
if (!atomic_read(&t->delay) && t->addr_hash == addr_hash) {
++span_count;
if (atomic_read(&t->ready)) {
@@ -228,7 +252,7 @@
(*ready_spans)[subaddr] = t;
++spans_ready;
} else {
- printk(KERN_ERR "More than %d spans per multi-frame group are not currently supported.",
+ printk(KERN_ERR "More than %d spans per multi-frame group are not currently supported.",
ETHMF_MAX_PER_SPAN_GROUP);
}
}
@@ -247,7 +271,7 @@
#if defined(__FreeBSD__)
static int ztdethmf_rcv(struct net_device *dev, struct ether_header *eh,
unsigned char *msg, int msglen)
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
static int ztdethmf_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
#else
@@ -268,7 +292,7 @@
if (msglen < sizeof(*zh))
return 0;
zh = (struct ztdeth_header *) msg;
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
zh = (struct ztdeth_header *) skb_network_header(skb);
#else
zh = (struct ztdeth_header *) skb->nh.raw;
@@ -295,14 +319,14 @@
skb_linearize(skb, GFP_KERNEL);
#endif
data = (unsigned char *) skb->data;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
src_addr = eth_hdr(skb)->h_source;
#else
src_addr = skb->mac.ethernet->h_source;
#endif
#endif /* !__FreeBSD__ */
- read_lock(ðmf_lock);
+ rcu_read_lock();
do {
find_ethmf(src_addr, htons(span_index), &z, &span);
if (unlikely(!z || !span)) {
@@ -315,8 +339,6 @@
samples = data[(span_index * 6)] & 0xFF;
flags = data[((span_index * 6) + 1)] & 0xFF;
channels = data[((span_index * 6) + 5)] & 0xFF;
-
- /* Precomputed defaults for most typical values */
rbslen = ((channels + 3) / 4) * 2;
if (unlikely(samples != 8 || channels > ETHMF_MAX_CHANNELS || channels == 0)) {
@@ -327,7 +349,7 @@
if (atomic_dec_and_test(&z->refcnt) == 0) {
memcpy(z->rcvbuf, data + 6*span_index, 6); /* TDM Header */
- /*
+ /*
* If we ignore channel zero we must skip the first eight bytes and
* ensure that ztdynamic doesn't get confused by this new flag
*/
@@ -369,7 +391,7 @@
#endif
++span_index;
} while (!atomic_read(&shutdown) && span_index < num_spans);
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
}
out:
@@ -388,8 +410,8 @@
switch (event) {
case NETDEV_GOING_DOWN:
case NETDEV_DOWN:
- read_lock(ðmf_lock);
- list_for_each_entry(z, ðmf_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(z, ðmf_list, list) {
/* Note that the device no longer exists */
if (z->dev == dev) {
z->dev = NULL;
@@ -398,11 +420,11 @@
#endif
}
}
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
break;
case NETDEV_UP:
- read_lock(ðmf_lock);
- list_for_each_entry(z, ðmf_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(z, ðmf_list, list) {
/* Now that the device exists again, use it */
if (!strcmp(z->ethdev, dev->name)) {
z->dev = dev;
@@ -411,7 +433,7 @@
#endif
}
}
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
break;
}
return 0;
@@ -432,26 +454,49 @@
unsigned short subaddr;
struct net_device *dev;
int spans_ready = 0, index = 0;
+#if !defined(__FreeBSD__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
+ static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ unsigned long flags;
+#endif
if (atomic_read(&shutdown))
return 0;
- read_lock(ðmf_lock);
+ rcu_read_lock();
+
if (unlikely(!z || !z->dev)) {
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
return 0;
}
#if defined(__FreeBSD__)
if (atomic_cmpset_int(&z->ready, 0, 1)) {
-#else
- if (atomic_cmpxchg(&z->ready, 0, 1) == 0) {
-#endif
memcpy(z->msgbuf, msg, msglen);
z->msgbuf_len = msglen;
}
-
- if ((spans_ready = ethmf_trx_spans_ready(z->addr_hash, &ready_spans))) {
+#else /* !__FreeBSD__ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
+ if (!atomic_read(&z->ready)) {
+ spin_lock_irqsave(&lock, flags);
+ atomic_inc(&z->ready);
+ if (1 == atomic_read(&z->ready)) {
+ memcpy(z->msgbuf, msg, msglen);
+ z->msgbuf_len = msglen;
+ }
+ spin_unlock_irqrestore(&lock, flags);
+ }
+#else
+ if (!atomic_read(&z->ready)) {
+ if (atomic_inc_return(&z->ready) == 1) {
+ memcpy(z->msgbuf, msg, msglen);
+ z->msgbuf_len = msglen;
+ }
+ }
+#endif
+#endif /* !__FreeBSD__ */
+
+ spans_ready = ethmf_trx_spans_ready(z->addr_hash, &ready_spans);
+ if (spans_ready) {
int pad[ETHMF_MAX_SPANS], rbs[ETHMF_MAX_SPANS];
dev = z->dev;
@@ -479,7 +524,7 @@
#if defined(__FreeBSD__)
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
ethmf_errors_inc();
return 0;
}
@@ -495,7 +540,7 @@
skb = dev_alloc_skb(1112 + dev->hard_header_len
+ sizeof(struct ztdeth_header) + 32);
if (unlikely(!skb)) {
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
ethmf_errors_inc();
return 0;
}
@@ -503,7 +548,8 @@
/* Reserve header space */
skb_reserve(skb, dev->hard_header_len
+ sizeof(struct ztdeth_header));
-#endif
+#endif /* !__FreeBSD__ */
+
/* copy each spans header */
for (index = 0; index < spans_ready; index++) {
if (!atomic_read(&(ready_spans[index]->no_front_padding))) {
@@ -572,13 +618,13 @@
/* Setup protocol type */
skb->protocol = __constant_htons(ETH_P_ZTDETH);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
skb_set_network_header(skb, 0);
#else
skb->nh.raw = skb->data;
#endif
skb->dev = dev;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
dev_hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
#else
if (dev->hard_header)
@@ -586,14 +632,17 @@
dev->dev_addr, skb->len);
#endif
/* queue frame for delivery */
- skb_queue_tail(&skbs, skb);
+ if (dev) {
+ skb_queue_tail(&skbs, skb);
+ }
#endif /* !__FreeBSD__ */
#ifdef USE_PROC_FS
atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].txframecount));
atomic_add(skb->len, &(ethmf_groups[hashaddr_to_index(z->addr_hash)].txbytecount));
#endif
}
- read_unlock(ðmf_lock);
+
+ rcu_read_unlock();
return 0;
}
@@ -611,8 +660,7 @@
return 0;
}
-static struct packet_type ztdethmf_ptype =
-{
+static struct packet_type ztdethmf_ptype = {
.type = __constant_htons(ETH_P_ZTDETH), /* Protocol */
.dev = NULL, /* Device (NULL = wildcard) */
.func = ztdethmf_rcv, /* Receiver */
@@ -621,12 +669,15 @@
static void ztdethmf_destroy(void *pvt)
{
struct ztdeth *z = pvt;
+ unsigned long flags;
atomic_set(&shutdown, 1);
-
- write_lock(ðmf_lock);
- list_del(&z->list);
- write_unlock(ðmf_lock);
+ synchronize_rcu();
+
+ spin_lock_irqsave(ðmf_lock, flags);
+ list_del_rcu(&z->list);
+ spin_unlock_irqrestore(ðmf_lock, flags);
+ synchronize_rcu();
#if defined(USE_PROC_FS)
atomic_dec(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans));
#endif
@@ -651,6 +702,7 @@
char src[256];
char *src_ptr;
int x, bufsize, num_matched;
+ unsigned long flags;
BUG_ON(!span);
BUG_ON(!addr);
@@ -669,7 +721,7 @@
/* set a delay for xmit/recv to workaround Zaptel problems */
atomic_set(&z->delay, 4);
- /* create a msg buffer. max of ETHMF_MAX_CHANNELS channels */
+ /* create a msg buffer. MAX OF 31 CHANNELS!!!! */
bufsize = ETHMF_MAX_CHANNELS * DAHDI_CHUNKSIZE + ETHMF_MAX_CHANNELS / 4 + 48;
z->msgbuf = kmalloc(bufsize, GFP_KERNEL);
z->rcvbuf = kmalloc(bufsize, GFP_KERNEL);
@@ -683,18 +735,19 @@
*src_ptr = ' ';
++src_ptr;
}
- if (8 != (num_matched = sscanf(src,
+ num_matched = sscanf(src,
"%16s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hu",
z->ethdev, &z->addr[0], &z->addr[1],
&z->addr[2], &z->addr[3], &z->addr[4],
- &z->addr[5], &z->subaddr))) {
+ &z->addr[5], &z->subaddr);
+ if (8 != num_matched) {
printk(KERN_ERR "Only matched %d entries in '%s'\n", num_matched, src);
printk(KERN_ERR "Invalid TDMoE Multiframe address: %s\n", addr);
kfree(z);
return NULL;
}
z->dev = dev_get_by_name(
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
&init_net,
#endif
z->ethdev);
@@ -708,8 +761,8 @@
z->addr_hash = crc32_le(0, z->addr, ETH_ALEN);
z->real_channels = span->channels;
- src[0] ='\0';
- for (x=0; x<5; x++)
+ src[0] = '\0';
+ for (x = 0; x < 5; x++)
sprintf(src + strlen(src), "%02x:", z->dev->dev_addr[x]);
sprintf(src + strlen(src), "%02x", z->dev->dev_addr[5]);
@@ -720,9 +773,9 @@
atomic_set(&z->ready, 0);
atomic_set(&z->refcnt, 0);
- write_lock(ðmf_lock);
- list_add(&z->list, ðmf_list);
- write_unlock(ðmf_lock);
+ spin_lock_irqsave(ðmf_lock, flags);
+ list_add_rcu(&z->list, ðmf_list);
+ spin_unlock_irqrestore(ðmf_lock, flags);
#if defined(USE_PROC_FS)
atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans));
#endif
@@ -758,15 +811,15 @@
struct ztdeth *z;
int count_nonzero = 0;
- read_lock(ðmf_lock);
- list_for_each_entry(z, ðmf_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(z, ðmf_list, list) {
if (atomic_read(&z->delay)) {
atomic_dec(&z->delay);
++count_nonzero;
} else
atomic_set(&z->delay, 0);
}
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
return count_nonzero;
}
@@ -796,7 +849,8 @@
int len = 0, i = 0;
unsigned int group = 0, c = 0;
- read_lock(ðmf_lock);
+ rcu_read_lock();
+
len += sprintf(page + len, "Errors: %d\n\n", atomic_read(&errcount));
for (group = 0; group < ETHMF_MAX_GROUPS; ++group) {
@@ -805,9 +859,8 @@
len += sprintf(page + len, " Spans: %d\n",
atomic_read(&(ethmf_groups[group].spans)));
-
c = 1;
- list_for_each_entry(z, ðmf_list, list) {
+ list_for_each_entry_rcu(z, ðmf_list, list) {
if (z->addr_hash == ethmf_groups[group].hash_addr) {
if (c == 1) {
len += sprintf(page + len,
@@ -842,7 +895,7 @@
break;
}
}
- read_unlock(ðmf_lock);
+ rcu_read_unlock();
if (len <= off) {
off -= len;
@@ -852,7 +905,7 @@
len -= off;
if (len > count)
len = count;
- return (len);
+ return len;
}
#endif
@@ -873,6 +926,7 @@
#else
skb_queue_head_init(&skbs);
#endif
+
#ifdef USE_PROC_FS
proc_entry = create_proc_read_entry(ztdethmf_procname, 0444, NULL,
ztdethmf_proc_read, NULL);
More information about the svn-commits
mailing list