* [IPV4 0/9] TRIE performance patches
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Time to handle a full BGP load (163K of routes).
Before: Load Dump Flush
hash 3.5 0.5 0.7
2.6.23.14 3.4 19.3 10.3
net-2.6.25 3.4 18.7 9.8
After:
kmem_cache 3.8 13.0 7.2
iter 3.9 12.3 6.9
unordered 3.1 11.9 4.9
find_node 3.1 0.3 1.2
Load: ip -batch iproute-table
Dump: ip route >/dev/null
Flush: ip route flush table main
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 3/9] fib_trie: compute size when needed
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: fib-trie-stats-x.patch --]
[-- Type: text/plain, Size: 2412 bytes --]
Compute the number of prefixes when needed, rather than doing bookeeping.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-21 17:45:03.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-21 17:45:03.000000000 -0800
@@ -143,12 +143,12 @@ struct trie_stat {
unsigned int tnodes;
unsigned int leaves;
unsigned int nullpointers;
+ unsigned int prefixes;
unsigned int nodesizes[MAX_STAT_DEPTH];
};
struct trie {
struct node *trie;
- unsigned int size;
#ifdef CONFIG_IP_FIB_TRIE_STATS
struct trie_use_stats stats;
#endif
@@ -1289,8 +1289,6 @@ static int fn_trie_insert(struct fib_tab
list_add_tail_rcu(&new_fa->fa_list,
(fa ? &fa->fa_list : fa_head));
- t->size++;
-
rt_cache_flush(-1);
rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
&cfg->fc_nlinfo, 0);
@@ -1576,9 +1574,6 @@ static int trie_leaf_remove(struct trie
* Key found.
* Remove the leaf and rebalance the tree
*/
-
- t->size--;
-
tp = node_parent(n);
tnode_free((struct tnode *) n);
@@ -2111,10 +2106,17 @@ static void trie_collect_stats(struct tr
for (n = fib_trie_get_first(&iter, t); n;
n = fib_trie_get_next(&iter)) {
if (IS_LEAF(n)) {
+ struct leaf *l = (struct leaf *)n;
+ struct leaf_info *li;
+ struct hlist_node *tmp;
+
s->leaves++;
s->totdepth += iter.depth;
if (iter.depth > s->maxdepth)
s->maxdepth = iter.depth;
+
+ hlist_for_each_entry_rcu(li, tmp, &l->list, hlist)
+ ++s->prefixes;
} else {
const struct tnode *tn = (const struct tnode *) n;
int i;
@@ -2148,8 +2150,11 @@ static void trie_show_stats(struct seq_f
seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth);
seq_printf(seq, "\tLeaves: %u\n", stat->leaves);
-
bytes = sizeof(struct leaf) * stat->leaves;
+
+ seq_printf(seq, "\tPrefixes: %u\n", stat->prefixes);
+ bytes += sizeof(struct leaf_info) * stat->prefixes;
+
seq_printf(seq, "\tInternal nodes: %u\n\t", stat->tnodes);
bytes += sizeof(struct tnode) * stat->tnodes;
@@ -2193,8 +2198,8 @@ static void fib_trie_show(struct seq_fil
{
struct trie_stat stat;
- seq_printf(seq, "%s: %d\n", name, trie->size);
trie_collect_stats(trie, &stat);
+ seq_printf(seq, "%s:\n", name);
trie_show_stats(seq, &stat);
#ifdef CONFIG_IP_FIB_TRIE_STATS
trie_show_usage(seq, &trie->stats);
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 1/9] fib_trie: put leaf nodes in a slab cache
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Stephen Hemminger
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: leaf-kmem-cache.patch --]
[-- Type: text/plain, Size: 1669 bytes --]
This improves locality for operations that touch all the leaves.
Save space since these entries don't need to be hardware cache aligned.
Signed-off-by: Stephen Hemminger <stephen.hemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-21 10:16:10.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-21 10:18:42.000000000 -0800
@@ -162,6 +162,7 @@ static struct tnode *halve(struct trie *
static void tnode_free(struct tnode *tn);
static struct kmem_cache *fn_alias_kmem __read_mostly;
+static struct kmem_cache *trie_leaf_kmem __read_mostly;
static inline struct tnode *node_parent(struct node *node)
{
@@ -325,7 +326,8 @@ static inline void alias_free_mem_rcu(st
static void __leaf_free_rcu(struct rcu_head *head)
{
- kfree(container_of(head, struct leaf, rcu));
+ struct leaf *l = container_of(head, struct leaf, rcu);
+ kmem_cache_free(trie_leaf_kmem, l);
}
static void __leaf_info_free_rcu(struct rcu_head *head)
@@ -375,7 +377,7 @@ static inline void tnode_free(struct tno
static struct leaf *leaf_new(void)
{
- struct leaf *l = kmalloc(sizeof(struct leaf), GFP_KERNEL);
+ struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
if (l) {
l->parent = T_LEAF;
INIT_HLIST_HEAD(&l->list);
@@ -1935,7 +1937,12 @@ out:
void __init fib_hash_init(void)
{
fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ 0, SLAB_PANIC, NULL);
+
+ trie_leaf_kmem = kmem_cache_create("ip_fib_trie",
+ max(sizeof(struct leaf),
+ sizeof(struct leaf_info)),
+ 0, SLAB_PANIC, NULL);
}
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 6/9] fib_trie: iterator recode
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
Remove the complex loop structure of nextleaf() andreplace it with a
simpler tree walker. This improves the performance and is much
cleaner.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-22 09:52:46.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-22 12:58:59.000000000 -0800
@@ -1708,64 +1708,65 @@ static int trie_flush_leaf(struct trie *
return found;
}
-/* rcu_read_lock needs to be hold by caller from readside */
-
-static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
+/*
+ * Scan for the next right leaf starting at node p->child[idx]
+ * Since we have back pointer, no recursion necessary.
+ */
+static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
{
- struct node *c = (struct node *) thisleaf;
- struct tnode *p;
- int idx;
- struct node *trie = rcu_dereference(t->trie);
-
- if (c == NULL) {
- if (trie == NULL)
- return NULL;
-
- if (IS_LEAF(trie)) /* trie w. just a leaf */
- return (struct leaf *) trie;
-
- p = (struct tnode *)trie; /* Start */
- } else
- p = node_parent_rcu(c);
+ do {
+ t_key idx;
- while (p) {
- int pos, last;
-
- /* Find the next child of the parent */
if (c)
- pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits);
+ idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1;
else
- pos = 0;
-
- last = 1 << p->bits;
- for (idx = pos; idx < last ; idx++) {
- c = rcu_dereference(p->child[idx]);
+ idx = 0;
+ while (idx < 1u << p->bits) {
+ c = tnode_get_child_rcu(p, idx++);
if (!c)
continue;
- /* Decend if tnode */
- while (IS_TNODE(c)) {
- p = (struct tnode *) c;
- idx = 0;
-
- /* Rightmost non-NULL branch */
- if (p && IS_TNODE(p))
- while (!(c = rcu_dereference(p->child[idx]))
- && idx < (1<<p->bits)) idx++;
-
- /* Done with this tnode? */
- if (idx >= (1 << p->bits) || !c)
- goto up;
+ if (IS_LEAF(c)) {
+ prefetch(p->child[idx]);
+ return (struct leaf *) c;
}
- return (struct leaf *) c;
+
+ /* Rescan start scanning in new node */
+ p = (struct tnode *) c;
+ idx = 0;
}
-up:
- /* No more children go up one step */
+
+ /* Node empty, walk back up to parent */
c = (struct node *) p;
- p = node_parent_rcu(c);
- }
- return NULL; /* Ready. Root of trie */
+ } while ( (p = node_parent_rcu(c)) != NULL);
+
+ return NULL; /* Root of trie */
+}
+
+
+static struct leaf *trie_firstleaf(struct trie *t)
+{
+ struct tnode *n = (struct tnode *) rcu_dereference(t->trie);
+
+ if (!n)
+ return NULL;
+
+ if (IS_LEAF(n)) /* trie is just a leaf */
+ return (struct leaf *) n;
+
+ return leaf_walk_rcu(n, NULL);
+}
+
+static struct leaf *trie_nextleaf(struct leaf *l)
+{
+ struct node *c = (struct node *) l;
+ struct tnode *p = node_parent(c);
+
+ if (!p)
+ return NULL; /* trie with just one leaf */
+
+ return leaf_walk_rcu(p, c);
}
/*
@@ -1775,9 +1776,9 @@ static int fn_trie_flush(struct fib_tabl
{
struct trie *t = (struct trie *) tb->tb_data;
struct leaf *ll = NULL, *l = NULL;
- int found = 0, h;
+ int found = 0;
- for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
+ for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
found += trie_flush_leaf(t, l);
if (ll && hlist_empty(&ll->list))
@@ -1884,7 +1885,6 @@ static int fn_trie_dump_fa(t_key key, in
i++;
continue;
}
- BUG_ON(!fa->fa_info);
if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
@@ -1913,8 +1913,9 @@ static int fn_trie_dump_plen(struct trie
struct leaf *l = NULL;
s_h = cb->args[3];
+ h = 0;
- for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
+ for (l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) {
if (h < s_h)
continue;
if (h > s_h)
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 8/9] fib_trie: avoid extra search on delete
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: trie-remove-desquare.patch --]
[-- Type: text/plain, Size: 2593 bytes --]
Get rid of extra search that made route deletion O(n).
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-22 15:24:41.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-22 15:25:32.000000000 -0800
@@ -1542,49 +1542,23 @@ found:
return ret;
}
-/* only called from updater side */
-static int trie_leaf_remove(struct trie *t, t_key key)
+/*
+ * Remove the leaf and return parent.
+ */
+static void trie_leaf_remove(struct trie *t, struct leaf *l)
{
- t_key cindex;
- struct tnode *tp = NULL;
- struct node *n = t->trie;
- struct leaf *l;
-
- pr_debug("entering trie_leaf_remove(%p)\n", n);
-
- /* Note that in the case skipped bits, those bits are *not* checked!
- * When we finish this, we will have NULL or a T_LEAF, and the
- * T_LEAF may or may not match our key.
- */
-
- while (n != NULL && IS_TNODE(n)) {
- struct tnode *tn = (struct tnode *) n;
- check_tnode(tn);
- n = tnode_get_child(tn, tkey_extract_bits(key,
- tn->pos, tn->bits));
-
- BUG_ON(n && node_parent(n) != tn);
- }
- l = (struct leaf *) n;
-
- if (!n || !tkey_equals(l->key, key))
- return 0;
+ struct tnode *tp = node_parent((struct node *) l);
- /*
- * Key found.
- * Remove the leaf and rebalance the tree
- */
- tp = node_parent(n);
- tnode_free((struct tnode *) n);
+ pr_debug("entering trie_leaf_remove(%p)\n", l);
if (tp) {
- cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+ t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
put_child(t, (struct tnode *)tp, cindex, NULL);
rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
} else
rcu_assign_pointer(t->trie, NULL);
- return 1;
+ tnode_free((struct tnode *) l);
}
/*
@@ -1662,7 +1636,7 @@ static int fn_trie_delete(struct fib_tab
}
if (hlist_empty(&l->list))
- trie_leaf_remove(t, key);
+ trie_leaf_remove(t, l);
if (fa->fa_state & FA_S_ACCESSED)
rt_cache_flush(-1);
@@ -1775,19 +1749,19 @@ static struct leaf *trie_nextleaf(struct
static int fn_trie_flush(struct fib_table *tb)
{
struct trie *t = (struct trie *) tb->tb_data;
- struct leaf *ll = NULL, *l = NULL;
+ struct leaf *l, *ll = NULL;
int found = 0;
for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
found += trie_flush_leaf(t, l);
if (ll && hlist_empty(&ll->list))
- trie_leaf_remove(t, ll->key);
+ trie_leaf_remove(t, ll);
ll = l;
}
if (ll && hlist_empty(&ll->list))
- trie_leaf_remove(t, ll->key);
+ trie_leaf_remove(t, ll);
pr_debug("trie_flush found=%d\n", found);
return found;
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 5/9] fib_trie: dump message multiple part flag
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: fib-multi.patch --]
[-- Type: text/plain, Size: 528 bytes --]
Match fib_hash, and set NLM_F_MULTI to handle multiple part messages.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-21 17:52:10.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-21 17:52:11.000000000 -0800
@@ -1895,7 +1895,7 @@ static int fn_trie_dump_fa(t_key key, in
xkey,
plen,
fa->fa_tos,
- fa->fa_info, 0) < 0) {
+ fa->fa_info, NLM_F_MULTI) < 0) {
cb->args[4] = i;
return -1;
}
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 4/9] fib_trie: use hash list
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Stephen Hemminger
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: fib-use-the-list.patch --]
[-- Type: text/plain, Size: 2587 bytes --]
The code to dump can use the existing hash chain rather
than doing repeated lookup.
Signed-off-by: Stephen Hemminger <stephen.hemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-21 17:45:03.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-21 17:45:08.000000000 -0800
@@ -2396,31 +2396,30 @@ static int fib_trie_seq_show(struct seq_
} else {
struct leaf *l = (struct leaf *) n;
- int i;
+ struct leaf_info *li;
+ struct hlist_node *node;
+
__be32 val = htonl(l->key);
seq_indent(seq, iter->depth);
seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));
- for (i = 32; i >= 0; i--) {
- struct leaf_info *li = find_leaf_info(l, i);
- if (li) {
- struct fib_alias *fa;
+ hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
+ struct fib_alias *fa;
- list_for_each_entry_rcu(fa, &li->falh, fa_list) {
- char buf1[32], buf2[32];
+ list_for_each_entry_rcu(fa, &li->falh, fa_list) {
+ char buf1[32], buf2[32];
- seq_indent(seq, iter->depth+1);
- seq_printf(seq, " /%d %s %s", i,
- rtn_scope(buf1, sizeof(buf1),
- fa->fa_scope),
- rtn_type(buf2, sizeof(buf2),
- fa->fa_type));
- if (fa->fa_tos)
- seq_printf(seq, "tos =%d\n",
- fa->fa_tos);
- seq_putc(seq, '\n');
- }
+ seq_indent(seq, iter->depth+1);
+ seq_printf(seq, " /%d %s %s", li->plen,
+ rtn_scope(buf1, sizeof(buf1),
+ fa->fa_scope),
+ rtn_type(buf2, sizeof(buf2),
+ fa->fa_type));
+ if (fa->fa_tos)
+ seq_printf(seq, "tos =%d\n",
+ fa->fa_tos);
+ seq_putc(seq, '\n');
}
}
}
@@ -2474,8 +2473,8 @@ static int fib_route_seq_show(struct seq
{
const struct fib_trie_iter *iter = seq->private;
struct leaf *l = v;
- int i;
- char bf[128];
+ struct leaf_info *li;
+ struct hlist_node *node;
if (v == SEQ_START_TOKEN) {
seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
@@ -2490,8 +2489,7 @@ static int fib_route_seq_show(struct seq
if (IS_TNODE(l))
return 0;
- for (i = 32; i >= 0; i--) {
- struct leaf_info *li = find_leaf_info(l, i);
+ hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
struct fib_alias *fa;
__be32 mask, prefix;
@@ -2504,6 +2502,7 @@ static int fib_route_seq_show(struct seq
list_for_each_entry_rcu(fa, &li->falh, fa_list) {
const struct fib_info *fi = fa->fa_info;
unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
+ char bf[128];
if (fa->fa_type == RTN_BROADCAST
|| fa->fa_type == RTN_MULTICAST)
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 9/9] fib_trie: avoid rescan on dump
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: trie-dump-desquare.patch --]
[-- Type: text/plain, Size: 1877 bytes --]
This converts dumping (and flushing) of large route tables
form O(N^2) to O(N). If the route dump took multiple pages then
the dump routine gets called again. The old code kept track of
location by counter, the new code instead uses the last key.
This is a really big win ( 0.3 sec vs 12 sec) for big route tables.
One side effect is that if the table changes during the dump,
then the last key will not be found, and we will return -EBUSY.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-22 15:25:32.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-22 15:26:41.000000000 -0800
@@ -1914,35 +1914,43 @@ static int fn_trie_dump_leaf(struct leaf
return skb->len;
}
-
-
static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
struct netlink_callback *cb)
{
struct leaf *l;
struct trie *t = (struct trie *) tb->tb_data;
- int h = 0;
- int s_h = cb->args[2];
+ t_key key = cb->args[2];
rcu_read_lock();
- for (h = 0, l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) {
- if (h < s_h)
- continue;
-
- if (h > s_h) {
- cb->args[3] = 0;
- cb->args[4] = 0;
+ /* Dump starting at last key.
+ * Note: 0.0.0.0/0 (ie default) is first key.
+ */
+ if (!key)
+ l = trie_firstleaf(t);
+ else {
+ l = fib_find_node(t, key);
+ if (!l) {
+ /* The table changed during the dump, rather than
+ * giving partial data, just make application retry.
+ */
+ rcu_read_unlock();
+ return -EBUSY;
}
+ }
+ while (l) {
+ cb->args[2] = l->key;
if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
rcu_read_unlock();
- cb->args[2] = h;
return -1;
}
+
+ l = trie_nextleaf(l);
+ memset(&cb->args[3], 0,
+ sizeof(cb->args) - 3*sizeof(cb->args[0]));
}
rcu_read_unlock();
- cb->args[2] = h;
return skb->len;
}
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 7/9] fib_trie: dump table in sorted order
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: fib-trie-dump-unordered.patch --]
[-- Type: text/plain, Size: 2689 bytes --]
It is easier with TRIE to dump the data traversal rather than
interating over every possible prefix. This saves some time and makes
the dump come out in sorted order.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-22 12:58:59.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-22 12:59:03.000000000 -0800
@@ -1905,67 +1905,71 @@ static int fn_trie_dump_fa(t_key key, in
return skb->len;
}
-static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb,
- struct sk_buff *skb, struct netlink_callback *cb)
+
+static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
+ struct sk_buff *skb, struct netlink_callback *cb)
{
- int h, s_h;
- struct list_head *fa_head;
- struct leaf *l = NULL;
+ struct leaf_info *li;
+ struct hlist_node *node;
+ int i, s_i;
- s_h = cb->args[3];
- h = 0;
+ s_i = cb->args[3];
+ i = 0;
- for (l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) {
- if (h < s_h)
+ /* rcu_read_lock is hold by caller */
+ hlist_for_each_entry_rcu(li, node, &l->list, hlist) {
+ if (i < s_i) {
+ i++;
continue;
- if (h > s_h)
- memset(&cb->args[4], 0,
- sizeof(cb->args) - 4*sizeof(cb->args[0]));
-
- fa_head = get_fa_head(l, plen);
+ }
- if (!fa_head)
- continue;
+ if (i > s_i)
+ cb->args[4] = 0;
- if (list_empty(fa_head))
+ if (list_empty(&li->falh))
continue;
- if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb) < 0) {
- cb->args[3] = h;
+ if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) {
+ cb->args[3] = i;
return -1;
}
+ i++;
}
- cb->args[3] = h;
+
+ cb->args[3] = i;
return skb->len;
}
+
+
static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
struct netlink_callback *cb)
{
- int m, s_m;
+ struct leaf *l;
struct trie *t = (struct trie *) tb->tb_data;
-
- s_m = cb->args[2];
+ int h = 0;
+ int s_h = cb->args[2];
rcu_read_lock();
- for (m = 0; m <= 32; m++) {
- if (m < s_m)
+ for (h = 0, l = trie_firstleaf(t); l != NULL; h++, l = trie_nextleaf(l)) {
+ if (h < s_h)
continue;
- if (m > s_m)
- memset(&cb->args[3], 0,
- sizeof(cb->args) - 3*sizeof(cb->args[0]));
-
- if (fn_trie_dump_plen(t, 32-m, tb, skb, cb) < 0) {
- cb->args[2] = m;
- goto out;
+
+ if (h > s_h) {
+ cb->args[3] = 0;
+ cb->args[4] = 0;
+ }
+
+ if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
+ rcu_read_unlock();
+ cb->args[2] = h;
+ return -1;
}
}
rcu_read_unlock();
- cb->args[2] = m;
+
+ cb->args[2] = h;
return skb->len;
-out:
- rcu_read_unlock();
- return -1;
}
void __init fib_hash_init(void)
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* [IPV4 2/9] fib_trie: style cleanup
From: Stephen Hemminger @ 2008-01-22 23:37 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Stephen Hemminger
In-Reply-To: <20080122233733.404145234@linux-foundation.org>
[-- Attachment #1: fib-trie-style.patch --]
[-- Type: text/plain, Size: 18775 bytes --]
Style cleanups:
* make check_leaf return -1 or plen, rather than by reference
* Get rid of #ifdef that is always set
* split out embedded function calls in if statements.
* checkpatch warnings
Signed-off-by: Stephen Hemminger <stephen.hemminger@vyatta.com>
--- a/net/ipv4/fib_trie.c 2008-01-21 10:18:42.000000000 -0800
+++ b/net/ipv4/fib_trie.c 2008-01-21 10:19:00.000000000 -0800
@@ -155,7 +155,8 @@ struct trie {
};
static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
+static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n,
+ int wasfull);
static struct node *resize(struct trie *t, struct tnode *tn);
static struct tnode *inflate(struct trie *t, struct tnode *tn);
static struct tnode *halve(struct trie *t, struct tnode *tn);
@@ -395,7 +396,7 @@ static struct leaf_info *leaf_info_new(i
return li;
}
-static struct tnode* tnode_new(t_key key, int pos, int bits)
+static struct tnode *tnode_new(t_key key, int pos, int bits)
{
size_t sz = sizeof(struct tnode) + (sizeof(struct node *) << bits);
struct tnode *tn = tnode_alloc(sz);
@@ -427,7 +428,8 @@ static inline int tnode_full(const struc
return ((struct tnode *) n)->pos == tn->pos + tn->bits;
}
-static inline void put_child(struct trie *t, struct tnode *tn, int i, struct node *n)
+static inline void put_child(struct trie *t, struct tnode *tn, int i,
+ struct node *n)
{
tnode_put_child_reorg(tn, i, n, -1);
}
@@ -437,7 +439,8 @@ static inline void put_child(struct trie
* Update the value of full_children and empty_children.
*/
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull)
+static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n,
+ int wasfull)
{
struct node *chi = tn->child[i];
int isfull;
@@ -577,11 +580,13 @@ static struct node *resize(struct trie *
err = 0;
max_resize = 10;
while ((tn->full_children > 0 && max_resize-- &&
- 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
- inflate_threshold_use * tnode_child_length(tn))) {
+ 50 * (tn->full_children + tnode_child_length(tn)
+ - tn->empty_children)
+ >= inflate_threshold_use * tnode_child_length(tn))) {
old_tn = tn;
tn = inflate(t, tn);
+
if (IS_ERR(tn)) {
tn = old_tn;
#ifdef CONFIG_IP_FIB_TRIE_STATS
@@ -593,11 +598,13 @@ static struct node *resize(struct trie *
if (max_resize < 0) {
if (!tn->parent)
- printk(KERN_WARNING "Fix inflate_threshold_root. Now=%d size=%d bits\n",
- inflate_threshold_root, tn->bits);
+ pr_warning("Fix inflate_threshold_root."
+ " Now=%d size=%d bits\n",
+ inflate_threshold_root, tn->bits);
else
- printk(KERN_WARNING "Fix inflate_threshold. Now=%d size=%d bits\n",
- inflate_threshold, tn->bits);
+ pr_warning("Fix inflate_threshold."
+ " Now=%d size=%d bits\n",
+ inflate_threshold, tn->bits);
}
check_tnode(tn);
@@ -634,11 +641,13 @@ static struct node *resize(struct trie *
if (max_resize < 0) {
if (!tn->parent)
- printk(KERN_WARNING "Fix halve_threshold_root. Now=%d size=%d bits\n",
- halve_threshold_root, tn->bits);
+ pr_warning("Fix halve_threshold_root."
+ " Now=%d size=%d bits\n",
+ halve_threshold_root, tn->bits);
else
- printk(KERN_WARNING "Fix halve_threshold. Now=%d size=%d bits\n",
- halve_threshold, tn->bits);
+ pr_warning("Fix halve_threshold."
+ " Now=%d size=%d bits\n",
+ halve_threshold, tn->bits);
}
/* Only one child remains */
@@ -681,8 +690,9 @@ static struct tnode *inflate(struct trie
*/
for (i = 0; i < olen; i++) {
- struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
+ struct tnode *inode;
+ inode = (struct tnode *) tnode_get_child(oldtnode, i);
if (inode &&
IS_TNODE(inode) &&
inode->pos == oldtnode->pos + oldtnode->bits &&
@@ -722,8 +732,9 @@ static struct tnode *inflate(struct trie
if (IS_LEAF(node) || ((struct tnode *) node)->pos >
tn->pos + tn->bits - 1) {
- if (tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,
- 1) == 0)
+ if (tkey_extract_bits(node->key,
+ oldtnode->pos + oldtnode->bits,
+ 1) == 0)
put_child(t, tn, 2*i, node);
else
put_child(t, tn, 2*i+1, node);
@@ -899,7 +910,7 @@ static struct leaf_info *find_leaf_info(
return NULL;
}
-static inline struct list_head * get_fa_head(struct leaf *l, int plen)
+static inline struct list_head *get_fa_head(struct leaf *l, int plen)
{
struct leaf_info *li = find_leaf_info(l, plen);
@@ -949,7 +960,10 @@ fib_find_node(struct trie *t, u32 key)
if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
pos = tn->pos + tn->bits;
- n = tnode_get_child_rcu(tn, tkey_extract_bits(key, tn->pos, tn->bits));
+ n = tnode_get_child_rcu(tn,
+ tkey_extract_bits(key,
+ tn->pos,
+ tn->bits));
} else
break;
}
@@ -970,8 +984,10 @@ static struct node *trie_rebalance(struc
while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
- tn = (struct tnode *) resize (t, (struct tnode *)tn);
- tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
+ tn = (struct tnode *) resize(t, (struct tnode *)tn);
+
+ tnode_put_child_reorg((struct tnode *)tp, cindex,
+ (struct node *)tn, wasfull);
tp = node_parent((struct node *) tn);
if (!tp)
@@ -981,9 +997,9 @@ static struct node *trie_rebalance(struc
/* Handle last (top) tnode */
if (IS_TNODE(tn))
- tn = (struct tnode*) resize(t, (struct tnode *)tn);
+ tn = (struct tnode *)resize(t, (struct tnode *)tn);
- return (struct node*) tn;
+ return (struct node *)tn;
}
/* only used from updater-side */
@@ -1028,7 +1044,10 @@ static struct list_head *fib_insert_node
if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
tp = tn;
pos = tn->pos + tn->bits;
- n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
+ n = tnode_get_child(tn,
+ tkey_extract_bits(key,
+ tn->pos,
+ tn->bits));
BUG_ON(n && node_parent(n) != tn);
} else
@@ -1113,16 +1132,18 @@ static struct list_head *fib_insert_node
if (tp) {
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
- put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);
+ put_child(t, (struct tnode *)tp, cindex,
+ (struct node *)tn);
} else {
- rcu_assign_pointer(t->trie, (struct node *)tn); /* First tnode */
+ rcu_assign_pointer(t->trie, (struct node *)tn);
tp = tn;
}
}
if (tp && tp->pos + tp->bits > 32)
- printk(KERN_WARNING "fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
- tp, tp->pos, tp->bits, key, plen);
+ pr_warning("fib_trie"
+ " tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
+ tp, tp->pos, tp->bits, key, plen);
/* Rebalance the trie */
@@ -1232,10 +1253,10 @@ static int fn_trie_insert(struct fib_tab
break;
if (fa->fa_type == cfg->fc_type &&
fa->fa_scope == cfg->fc_scope &&
- fa->fa_info == fi) {
+ fa->fa_info == fi)
goto out;
- }
}
+
if (!(cfg->fc_nlflags & NLM_F_APPEND))
fa = fa_orig;
}
@@ -1286,38 +1307,40 @@ err:
/* should be called with rcu_read_lock */
-static inline int check_leaf(struct trie *t, struct leaf *l,
- t_key key, int *plen, const struct flowi *flp,
- struct fib_result *res)
+static int check_leaf(struct trie *t, struct leaf *l,
+ t_key key, const struct flowi *flp,
+ struct fib_result *res)
{
- int err, i;
- __be32 mask;
struct leaf_info *li;
struct hlist_head *hhead = &l->list;
struct hlist_node *node;
hlist_for_each_entry_rcu(li, node, hhead, hlist) {
- i = li->plen;
- mask = inet_make_mask(i);
+ int err;
+ int plen = li->plen;
+ __be32 mask = inet_make_mask(plen);
+
if (l->key != (key & ntohl(mask)))
continue;
- if ((err = fib_semantic_match(&li->falh, flp, res, htonl(l->key), mask, i)) <= 0) {
- *plen = i;
+ err = fib_semantic_match(&li->falh, flp, res,
+ htonl(l->key), mask, plen);
+
#ifdef CONFIG_IP_FIB_TRIE_STATS
+ if (err <= 0)
t->stats.semantic_match_passed++;
+ else
+ t->stats.semantic_match_miss++;
#endif
- return err;
- }
-#ifdef CONFIG_IP_FIB_TRIE_STATS
- t->stats.semantic_match_miss++;
-#endif
+ if (err <= 0)
+ return plen;
}
- return 1;
+
+ return -1;
}
-static int
-fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
+ struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
int plen, ret = 0;
@@ -1344,10 +1367,13 @@ fn_trie_lookup(struct fib_table *tb, con
/* Just a leaf? */
if (IS_LEAF(n)) {
- if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
- goto found;
- goto failed;
+ plen = check_leaf(t, (struct leaf *)n, key, flp, res);
+ if (plen < 0)
+ goto failed;
+ ret = 0;
+ goto found;
}
+
pn = (struct tnode *) n;
chopped_off = 0;
@@ -1369,14 +1395,14 @@ fn_trie_lookup(struct fib_table *tb, con
}
if (IS_LEAF(n)) {
- if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
- goto found;
- else
+ plen = check_leaf(t, (struct leaf *)n, key, flp, res);
+ if (plen < 0)
goto backtrace;
+
+ ret = 0;
+ goto found;
}
-#define HL_OPTIMIZE
-#ifdef HL_OPTIMIZE
cn = (struct tnode *)n;
/*
@@ -1405,12 +1431,13 @@ fn_trie_lookup(struct fib_table *tb, con
* *are* zero.
*/
- /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
+ /* NOTA BENE: Checking only skipped bits
+ for the new node here */
if (current_prefix_length < pos+bits) {
if (tkey_extract_bits(cn->key, current_prefix_length,
- cn->pos - current_prefix_length) != 0 ||
- !(cn->child[0]))
+ cn->pos - current_prefix_length)
+ || !(cn->child[0]))
goto backtrace;
}
@@ -1433,14 +1460,17 @@ fn_trie_lookup(struct fib_table *tb, con
* new tnode's key.
*/
- /* Note: We aren't very concerned about the piece of the key
- * that precede pn->pos+pn->bits, since these have already been
- * checked. The bits after cn->pos aren't checked since these are
- * by definition "unknown" at this point. Thus, what we want to
- * see is if we are about to enter the "prefix matching" state,
- * and in that case verify that the skipped bits that will prevail
- * throughout this subtree are zero, as they have to be if we are
- * to find a matching prefix.
+ /*
+ * Note: We aren't very concerned about the piece of
+ * the key that precede pn->pos+pn->bits, since these
+ * have already been checked. The bits after cn->pos
+ * aren't checked since these are by definition
+ * "unknown" at this point. Thus, what we want to see
+ * is if we are about to enter the "prefix matching"
+ * state, and in that case verify that the skipped
+ * bits that will prevail throughout this subtree are
+ * zero, as they have to be if we are to find a
+ * matching prefix.
*/
node_prefix = mask_pfx(cn->key, cn->pos);
@@ -1448,13 +1478,15 @@ fn_trie_lookup(struct fib_table *tb, con
pref_mismatch = key_prefix^node_prefix;
mp = 0;
- /* In short: If skipped bits in this node do not match the search
- * key, enter the "prefix matching" state.directly.
+ /*
+ * In short: If skipped bits in this node do not match
+ * the search key, enter the "prefix matching"
+ * state.directly.
*/
if (pref_mismatch) {
while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
mp++;
- pref_mismatch = pref_mismatch <<1;
+ pref_mismatch = pref_mismatch << 1;
}
key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
@@ -1464,7 +1496,7 @@ fn_trie_lookup(struct fib_table *tb, con
if (current_prefix_length >= cn->pos)
current_prefix_length = mp;
}
-#endif
+
pn = (struct tnode *)n; /* Descend */
chopped_off = 0;
continue;
@@ -1473,12 +1505,14 @@ backtrace:
chopped_off++;
/* As zero don't change the child key (cindex) */
- while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1))))
+ while ((chopped_off <= pn->bits)
+ && !(cindex & (1<<(chopped_off-1))))
chopped_off++;
/* Decrease current_... with bits chopped off */
if (current_prefix_length > pn->pos + pn->bits - chopped_off)
- current_prefix_length = pn->pos + pn->bits - chopped_off;
+ current_prefix_length = pn->pos + pn->bits
+ - chopped_off;
/*
* Either we do the actual chop off according or if we have
@@ -1528,7 +1562,8 @@ static int trie_leaf_remove(struct trie
while (n != NULL && IS_TNODE(n)) {
struct tnode *tn = (struct tnode *) n;
check_tnode(tn);
- n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
+ n = tnode_get_child(tn, tkey_extract_bits(key,
+ tn->pos, tn->bits));
BUG_ON(n && node_parent(n) != tn);
}
@@ -1694,7 +1729,7 @@ static struct leaf *nextleaf(struct trie
if (IS_LEAF(trie)) /* trie w. just a leaf */
return (struct leaf *) trie;
- p = (struct tnode*) trie; /* Start */
+ p = (struct tnode *)trie; /* Start */
} else
p = node_parent_rcu(c);
@@ -1762,8 +1797,9 @@ static int fn_trie_flush(struct fib_tabl
return found;
}
-static void
-fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+static void fn_trie_select_default(struct fib_table *tb,
+ const struct flowi *flp,
+ struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
int order, last_idx;
@@ -1834,7 +1870,8 @@ out:
rcu_read_unlock();
}
-static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fib_table *tb,
+static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
+ struct fib_table *tb,
struct sk_buff *skb, struct netlink_callback *cb)
{
int i, s_i;
@@ -1873,8 +1910,8 @@ static int fn_trie_dump_fa(t_key key, in
return skb->len;
}
-static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, struct sk_buff *skb,
- struct netlink_callback *cb)
+static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb,
+ struct sk_buff *skb, struct netlink_callback *cb)
{
int h, s_h;
struct list_head *fa_head;
@@ -1897,7 +1934,7 @@ static int fn_trie_dump_plen(struct trie
if (list_empty(fa_head))
continue;
- if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
+ if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb) < 0) {
cb->args[3] = h;
return -1;
}
@@ -1906,7 +1943,8 @@ static int fn_trie_dump_plen(struct trie
return skb->len;
}
-static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
+static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
+ struct netlink_callback *cb)
{
int m, s_m;
struct trie *t = (struct trie *) tb->tb_data;
@@ -1921,7 +1959,7 @@ static int fn_trie_dump(struct fib_table
memset(&cb->args[3], 0,
sizeof(cb->args) - 3*sizeof(cb->args[0]));
- if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
+ if (fn_trie_dump_plen(t, 32-m, tb, skb, cb) < 0) {
cb->args[2] = m;
goto out;
}
@@ -1936,7 +1974,8 @@ out:
void __init fib_hash_init(void)
{
- fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias),
+ fn_alias_kmem = kmem_cache_create("ip_fib_alias",
+ sizeof(struct fib_alias),
0, SLAB_PANIC, NULL);
trie_leaf_kmem = kmem_cache_create("ip_fib_trie",
@@ -1970,7 +2009,7 @@ struct fib_table *fib_hash_table(u32 id)
memset(t, 0, sizeof(*t));
if (id == RT_TABLE_LOCAL)
- printk(KERN_INFO "IPv4 FIB: Using LC-trie version %s\n", VERSION);
+ pr_info("IPv4 FIB: Using LC-trie version %s\n", VERSION);
return tb;
}
@@ -2104,7 +2143,8 @@ static void trie_show_stats(struct seq_f
else
avdepth = 0;
- seq_printf(seq, "\tAver depth: %u.%02d\n", avdepth / 100, avdepth % 100 );
+ seq_printf(seq, "\tAver depth: %u.%02d\n",
+ avdepth / 100, avdepth % 100);
seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth);
seq_printf(seq, "\tLeaves: %u\n", stat->leaves);
@@ -2136,16 +2176,20 @@ static void trie_show_usage(struct seq_f
const struct trie_use_stats *stats)
{
seq_printf(seq, "\nCounters:\n---------\n");
- seq_printf(seq,"gets = %u\n", stats->gets);
- seq_printf(seq,"backtracks = %u\n", stats->backtrack);
- seq_printf(seq,"semantic match passed = %u\n", stats->semantic_match_passed);
- seq_printf(seq,"semantic match miss = %u\n", stats->semantic_match_miss);
- seq_printf(seq,"null node hit= %u\n", stats->null_node_hit);
- seq_printf(seq,"skipped node resize = %u\n\n", stats->resize_node_skipped);
+ seq_printf(seq, "gets = %u\n", stats->gets);
+ seq_printf(seq, "backtracks = %u\n", stats->backtrack);
+ seq_printf(seq, "semantic match passed = %u\n",
+ stats->semantic_match_passed);
+ seq_printf(seq, "semantic match miss = %u\n",
+ stats->semantic_match_miss);
+ seq_printf(seq, "null node hit= %u\n", stats->null_node_hit);
+ seq_printf(seq, "skipped node resize = %u\n\n",
+ stats->resize_node_skipped);
}
#endif /* CONFIG_IP_FIB_TRIE_STATS */
-static void fib_trie_show(struct seq_file *seq, const char *name, struct trie *trie)
+static void fib_trie_show(struct seq_file *seq, const char *name,
+ struct trie *trie)
{
struct trie_stat stat;
@@ -2163,7 +2207,8 @@ static int fib_triestat_seq_show(struct
struct fib_table *tb;
seq_printf(seq,
- "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n",
+ "Basic info: size of leaf:"
+ " %Zd bytes, size of tnode: %Zd bytes.\n",
sizeof(struct leaf), sizeof(struct tnode));
tb = fib_get_table(net, RT_TABLE_LOCAL);
@@ -2436,10 +2481,11 @@ static int fib_route_seq_show(struct seq
if (iter->trie == iter->trie_local)
return 0;
+
if (IS_TNODE(l))
return 0;
- for (i=32; i>=0; i--) {
+ for (i = 32; i >= 0; i--) {
struct leaf_info *li = find_leaf_info(l, i);
struct fib_alias *fa;
__be32 mask, prefix;
@@ -2466,7 +2512,8 @@ static int fib_route_seq_show(struct seq
fi->fib_nh->nh_gw, flags, 0, 0,
fi->fib_priority,
mask,
- (fi->fib_advmss ? fi->fib_advmss + 40 : 0),
+ (fi->fib_advmss ?
+ fi->fib_advmss + 40 : 0),
fi->fib_window,
fi->fib_rtt >> 3);
else
--
Stephen Hemminger <stephen.hemminger@vyatta.com>
^ permalink raw reply
* Re: [PATCH 09/26] atl1: refactor tx processing
From: Jay Cliburn @ 2008-01-23 0:31 UTC (permalink / raw)
To: Jeff Garzik; +Cc: csnook, linux-kernel, atl1-devel, netdev
In-Reply-To: <4795BE39.6000505@garzik.org>
On Tue, 22 Jan 2008 04:58:17 -0500
Jeff Garzik <jeff@garzik.org> wrote:
> jacliburn@bellsouth.net wrote:
> > From: Jay Cliburn <jacliburn@bellsouth.net>
> >
> > Refactor tx processing to use a less convoluted tx packet
> > descriptor and to conform generally with the vendor's current
> > version 1.2.40.2.
> >
> > Signed-off-by: Jay Cliburn <jacliburn@bellsouth.net>
> > ---
> > drivers/net/atlx/atl1.c | 265
> > +++++++++++++++++++++++++----------------------
> > drivers/net/atlx/atl1.h | 201 +++++++++++++++++++-----------------
> > 2 files changed, 246 insertions(+), 220 deletions(-)
>
> for such a huge patch, this description is very tiny. [describe]
> what is refactored, and why.
Okay, I'll go back and rework the offending descriptions for this and
the other patches in this set.
> what does "less convoluted" mean?
I should have written "simpler," I suppose.
Before:
=======
struct tso_param {
u32 tsopu; /* tso_param upper word */
u32 tsopl; /* tso_param lower word */
};
struct csum_param {
u32 csumpu; /* csum_param upper word */
u32 csumpl; /* csum_param lower word */
};
union tpd_descr {
u64 data;
struct csum_param csum;
struct tso_param tso;
};
struct tx_packet_desc {
__le64 buffer_addr;
union tpd_descr desc;
};
After:
======
struct tx_packet_desc {
__le64 buffer_addr;
__le32 word2;
__le32 word3;
};
^ permalink raw reply
* Re: [PATCH 0/6] PS3: gelic: gelic updates for 2.6.25
From: Benjamin Herrenschmidt @ 2008-01-23 0:40 UTC (permalink / raw)
To: John W. Linville; +Cc: Geert.Uytterhoeven, netdev, Linux/PPC Development
In-Reply-To: <20080122211239.GC3206@tuxdriver.com>
On Tue, 2008-01-22 at 16:12 -0500, John W. Linville wrote:
> On Thu, Dec 13, 2007 at 07:38:28PM +0900, Masakazu Mokuno wrote:
>
> > Here is a set of updates for PS3 gelic network driver.
> > This patch set requires other patches which were already submitted by
> > Geert (http://marc.info/?l=linux-kernel&m=119626095605487).
> >
> > [1] PS3: gelic: Fix the wrong dev_id passed
> > [2] PS3: gelic: Add endianness macros
> > [3] PS3: gelic: Code cleanup
> > [4] PS3: gelic: Remove duplicated ethtool handers
> > [5] PS3: gelic: Add support for port link status
> > [6] PS3: gelic: Add support for dual network interface
> >
> > This is also a set of prerequisite for new wireless driver for PS3, which
> > I'll submit later.
>
> These seem to not have been applied, but I couldn't find any stated
> reason. Did they just get lost? Withdrawn?
>
> Will these be applied? There is a wireless patch that depends on them.
> If not, will the wireless portion be refactored to not require these
> patches?
The list of 6 patches above are the patches that Masakazu Mukono is
submitting, the pre-reqs are different patches (see the linked URL),
though I can't see them in either (they should probably go through
paulus for-2.6.25). Geert, what's up with these ?
Cheers,
Ben.
^ permalink raw reply
* Re: Netperf TCP_RR(loopback) 10% regression in 2.6.24-rc6, comparing with 2.6.22
From: Zhang, Yanmin @ 2008-01-23 0:42 UTC (permalink / raw)
To: Rick Jones; +Cc: netdev, David Miller
In-Reply-To: <479637B1.5000706@hp.com>
On Tue, 2008-01-22 at 10:36 -0800, Rick Jones wrote:
> When parsing the -P option in scan_socket_args() of src/nettest_bsd.c,
> netperf is using "break_args()" from src/netsh.c which indeed if the
> command line says "-P 12345" will set both the local and remote port
> numbers to 12345. If instead you were to say "-P 12345," it will use
> 12345 only for the netperf side. If you say "-P ,12345" it will use
> 12345 only for the netserver side. To set both sides at once to
> different values it would be "-P 12345,54321"
>
> In theory, send_udp_rr() in src/nettest_bsd.c (or I suppose
> scan_socket_args() could have more code added to it to check for a UDP
> test over loopback, but probably needs to be a check for any local IP,
> and unless this becomes something bigger than "Doctor! Doctor! It hurts
> when I do this!" :) I'm inclined to leave it as caveat benchmarker and
> perhaps some additional text in the manual.
I will instrument kernel to see if kernel does work like it is expected.
When an issue is found, we shouldn't escape by saying it's nothing to do
with me.
-yanmin
^ permalink raw reply
* [PATCH 2.6.25 1/1]S2io: Multiqueue network device support implementation
From: Sreenivasa Honnur @ 2008-01-23 0:45 UTC (permalink / raw)
To: netdev, jeff; +Cc: support
Multiqueue netwrok device support implementation.
- Added a loadable parameter "multiq" to enable/disable multiqueue support,
by default it is disabled.
- skb->queue_mapping is not used for queue/fifo selection. FIFO iselection is
based on IP-TOS value, 0x0-0xF TOS values are mapped to 8 FIFOs.
- Added per FIFO flags FIFO_QUEUE_START and FIFO_QUEUE_STOP. Check this flag
for starting and stopping netif queue and update the flags accordingly.
- In tx_intr_handler added a check to ensure that we have free TXDs before wak-
ing up the queue.
- Added helper functions for queue manipulation(start/stop/wakeup) to invoke
appropriate netif_ functions.
- Calling netif_start/stop for link up/down case respectively.
Signed-off-by: Surjit Reang <surjit.reang@neterion.com>
Signed-off-by: Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
---
diff -Nurp orig/drivers/net/s2io.c patch1/drivers/net/s2io.c
--- orig/drivers/net/s2io.c 2007-12-21 12:10:29.000000000 -0800
+++ patch1/drivers/net/s2io.c 2007-12-21 13:36:59.000000000 -0800
@@ -50,6 +50,8 @@
* Possible values '1' for enable , '0' for disable.
* Default is '2' - which means disable in promisc mode
* and enable in non-promiscuous mode.
+ * multiq: This parameter used to enable/disable MULTIQUEUE support. *
+ * Possible values '1' for enable and '0' for disable. Default is '0' *
************************************************************************/
#include <linux/module.h>
@@ -84,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.15-2"
+#define DRV_VERSION "2.0.26.16"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -93,6 +95,12 @@ static char s2io_driver_version[] = DRV_
static int rxd_size[2] = {32,48};
static int rxd_count[2] = {127,85};
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+/* mapping from tos value to fifo number
+ * 0x0-0xF TOS values are mapped to 8 FIFOs */
+static int tos_map[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
+#endif
+
static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
int ret;
@@ -458,6 +466,7 @@ MODULE_VERSION(DRV_VERSION);
/* Module Loadable parameters. */
S2IO_PARM_INT(tx_fifo_num, 1);
S2IO_PARM_INT(rx_ring_num, 1);
+S2IO_PARM_INT(multiq, 0);
S2IO_PARM_INT(rx_ring_mode, 1);
@@ -533,6 +542,101 @@ static struct pci_driver s2io_driver = {
/* A simplifier macro used both by init and free shared_mem Fns(). */
#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
+/* netqueue manipulation helper functions */
+static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp)
+{
+ int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ netif_stop_subqueue(sp->dev, i);
+ } else
+#endif
+ {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP;
+ netif_stop_queue(sp->dev);
+ }
+}
+
+static inline void s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq)
+ netif_stop_subqueue(sp->dev, fifo_no);
+ else
+#endif
+ {
+ sp->mac_control.fifos[fifo_no].queue_state =
+ FIFO_QUEUE_STOP;
+ netif_stop_queue(sp->dev);
+ }
+}
+
+static inline void s2io_start_all_tx_queue(struct s2io_nic *sp)
+{
+ int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ netif_start_subqueue(sp->dev, i);
+ } else
+#endif
+ {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
+ netif_start_queue(sp->dev);
+ }
+}
+
+static inline void s2io_start_tx_queue(struct s2io_nic *sp, int fifo_no)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (multiq)
+ netif_start_subqueue(sp->dev, fifo_no);
+ else
+#endif
+ {
+ sp->mac_control.fifos[fifo_no].queue_state =
+ FIFO_QUEUE_START;
+ netif_start_queue(sp->dev);
+ }
+}
+
+static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp)
+{
+ int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ netif_wake_subqueue(sp->dev, i);
+ } else
+#endif
+ {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
+ netif_wake_queue(sp->dev);
+ }
+}
+
+static inline void s2io_wake_tx_queue(
+ struct fifo_info *fifo, int cnt, u8 multiq)
+{
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (multiq) {
+ if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no))
+ netif_wake_subqueue(fifo->dev, fifo->fifo_no);
+ } else
+#endif
+ if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) {
+ if (netif_queue_stopped(fifo->dev)) {
+ fifo->queue_state = FIFO_QUEUE_START;
+ netif_wake_queue(fifo->dev);
+ }
+ }
+}
+
/**
* init_shared_mem - Allocation and Initialization of Memory
* @nic: Device private variable.
@@ -614,6 +718,7 @@ static int init_shared_mem(struct s2io_n
mac_control->fifos[i].fifo_no = i;
mac_control->fifos[i].nic = nic;
mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
+ mac_control->fifos[i].dev = dev;
for (j = 0; j < page_num; j++) {
int k = 0;
@@ -2975,10 +3080,10 @@ static void rx_intr_handler(struct ring_
static void tx_intr_handler(struct fifo_info *fifo_data)
{
struct s2io_nic *nic = fifo_data->nic;
- struct net_device *dev = (struct net_device *) nic->dev;
struct tx_curr_get_info get_info, put_info;
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct TxD *txdlp;
+ int pkt_cnt = 0;
unsigned long flags = 0;
u8 err_mask;
@@ -3040,6 +3145,8 @@ static void tx_intr_handler(struct fifo_
return;
}
+ pkt_cnt++;
+
/* Updating the statistics block */
nic->stats.tx_bytes += skb->len;
nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
@@ -3054,8 +3161,7 @@ static void tx_intr_handler(struct fifo_
get_info.offset;
}
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
+ s2io_wake_tx_queue(fifo_data, pkt_cnt, nic->config.multiq);
spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
}
@@ -3939,7 +4045,7 @@ static int s2io_open(struct net_device *
goto hw_init_failed;
}
- netif_start_queue(dev);
+ s2io_start_all_tx_queue(sp);
return 0;
hw_init_failed:
@@ -3985,7 +4091,7 @@ static int s2io_close(struct net_device
if (!is_s2io_card_up(sp))
return 0;
- netif_stop_queue(dev);
+ s2io_stop_all_tx_queue(sp);
/* delete all populated mac entries */
for (offset = 1; offset < config->max_mc_addr; offset++) {
@@ -4055,9 +4161,34 @@ static int s2io_xmit(struct sk_buff *skb
vlan_priority = vlan_tag >> 13;
queue = config->fifo_mapping[vlan_priority];
}
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ else if (skb->protocol == htons(ETH_P_IP) && sp->config.multiq) {
+ struct iphdr *ip;
+ ip = ip_hdr(skb);
+
+ /* get fifo number based on TOS value */
+ queue = tos_map[IPTOS_TOS(ip->tos) >> 1];
+ }
+#endif
fifo = &mac_control->fifos[queue];
spin_lock_irqsave(&fifo->tx_lock, flags);
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (sp->config.multiq) {
+ if (__netif_subqueue_stopped(dev, fifo->fifo_no)) {
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ } else
+#endif
+ if (unlikely(fifo->queue_state == FIFO_QUEUE_STOP)) {
+ if (netif_queue_stopped(dev)) {
+ spin_unlock_irqrestore(&fifo->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ }
+
put_off = (u16) fifo->tx_curr_put_info.offset;
get_off = (u16) fifo->tx_curr_get_info.offset;
txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr;
@@ -4067,7 +4198,7 @@ static int s2io_xmit(struct sk_buff *skb
if (txdp->Host_Control ||
((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
- netif_stop_queue(dev);
+ s2io_stop_tx_queue(sp, fifo->fifo_no);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
return 0;
@@ -4173,7 +4304,7 @@ static int s2io_xmit(struct sk_buff *skb
DBG_PRINT(TX_DBG,
"No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
put_off, get_off);
- netif_stop_queue(dev);
+ s2io_stop_tx_queue(sp, fifo->fifo_no);
}
mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
dev->trans_start = jiffies;
@@ -4182,7 +4313,7 @@ static int s2io_xmit(struct sk_buff *skb
return 0;
pci_map_failed:
stats->pci_map_fail_cnt++;
- netif_stop_queue(dev);
+ s2io_stop_tx_queue(sp, fifo->fifo_no);
stats->mem_freed += skb->truesize;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
@@ -4594,7 +4725,7 @@ static void s2io_handle_errors(void * de
return;
reset:
- netif_stop_queue(dev);
+ s2io_stop_all_tx_queue(sp);
schedule_work(&sp->rst_timer_task);
sw_stat->soft_reset_cnt++;
return;
@@ -6581,16 +6712,16 @@ static int s2io_change_mtu(struct net_de
dev->mtu = new_mtu;
if (netif_running(dev)) {
+ s2io_stop_all_tx_queue(sp);
s2io_card_down(sp);
- netif_stop_queue(dev);
+
ret = s2io_card_up(sp);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
__FUNCTION__);
return ret;
}
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
+ s2io_wake_all_tx_queue(sp);
} else { /* Device is down */
struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = new_mtu;
@@ -6698,7 +6829,7 @@ static void s2io_set_link(struct work_st
} else {
DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
- netif_stop_queue(dev);
+ s2io_stop_all_tx_queue(nic);
}
}
val64 = readq(&bar0->adapter_control);
@@ -7177,7 +7308,8 @@ static void s2io_restart_nic(struct work
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
dev->name);
}
- netif_wake_queue(dev);
+ s2io_wake_all_tx_queue(sp);
+
DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
dev->name);
out_unlock:
@@ -7456,6 +7588,7 @@ static void s2io_link(struct s2io_nic *
init_tti(sp, link);
if (link == LINK_DOWN) {
DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
+ s2io_stop_all_tx_queue(sp);
netif_carrier_off(dev);
if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
sp->mac_control.stats_info->sw_stat.link_up_time =
@@ -7468,6 +7601,7 @@ static void s2io_link(struct s2io_nic *
jiffies - sp->start_time;
sp->mac_control.stats_info->sw_stat.link_up_cnt++;
netif_carrier_on(dev);
+ s2io_wake_all_tx_queue(sp);
}
}
sp->last_link_state = link;
@@ -7504,7 +7638,8 @@ static void s2io_init_pci(struct s2io_ni
pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
}
-static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
+static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
+ u8 *dev_multiq)
{
if ((tx_fifo_num > MAX_TX_FIFOS) ||
(tx_fifo_num < FIFO_DEFAULT_NUM)) {
@@ -7518,6 +7653,19 @@ static int s2io_verify_parm(struct pci_d
DBG_PRINT(ERR_DBG, "tx fifos\n");
}
+#ifndef CONFIG_NETDEVICES_MULTIQUEUE
+ if (multiq) {
+ DBG_PRINT(ERR_DBG, "s2io: Multiqueue support not enabled\n");
+ multiq = 0;
+ }
+#endif
+
+ /* if multiqueue is enabled configure all fifos */
+ if (multiq) {
+ tx_fifo_num = MAX_TX_FIFOS;
+ *dev_multiq = multiq;
+ }
+
if ( rx_ring_num > 8) {
DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
"supported\n");
@@ -7609,9 +7757,11 @@ s2io_init_nic(struct pci_dev *pdev, cons
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
+ u8 dev_multiq = 0;
DECLARE_MAC_BUF(mac);
- if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
+ ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq);
+ if (ret)
return ret;
if ((ret = pci_enable_device(pdev))) {
@@ -7643,7 +7793,13 @@ s2io_init_nic(struct pci_dev *pdev, cons
return -ENODEV;
}
- dev = alloc_etherdev(sizeof(struct s2io_nic));
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (dev_multiq)
+ dev = alloc_etherdev_mq(sizeof(struct s2io_nic), MAX_TX_FIFOS);
+ else
+#endif
+ dev = alloc_etherdev(sizeof(struct s2io_nic));
+
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Device allocation failed\n");
pci_disable_device(pdev);
@@ -7694,6 +7850,7 @@ s2io_init_nic(struct pci_dev *pdev, cons
/* Tx side parameters. */
config->tx_fifo_num = tx_fifo_num;
+ config->multiq = dev_multiq;
for (i = 0; i < MAX_TX_FIFOS; i++) {
config->tx_cfg[i].fifo_len = tx_fifo_len[i];
config->tx_cfg[i].fifo_priority = i;
@@ -7807,6 +7964,11 @@ s2io_init_nic(struct pci_dev *pdev, cons
dev->features |= NETIF_F_HW_CSUM;
}
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (config->multiq)
+ dev->features |= NETIF_F_MULTI_QUEUE;
+#endif
+
dev->tx_timeout = &s2io_tx_watchdog;
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
@@ -7963,6 +8125,16 @@ s2io_init_nic(struct pci_dev *pdev, cons
DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
break;
}
+
+ if (sp->config.multiq) {
+ for (i = 0; i < sp->config.tx_fifo_num; i++)
+ mac_control->fifos[i].multiq = config->multiq;
+ DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n",
+ dev->name);
+ } else
+ DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n",
+ dev->name);
+
if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name);
diff -Nurp orig/drivers/net/s2io.h patch1/drivers/net/s2io.h
--- orig/drivers/net/s2io.h 2007-12-21 12:10:29.000000000 -0800
+++ patch1/drivers/net/s2io.h 2007-12-21 13:36:28.000000000 -0800
@@ -464,6 +464,7 @@ struct config_param {
int max_mc_addr; /* xena=64 herc=256 */
int max_mac_addr; /* xena=16 herc=64 */
int mc_start_offset; /* xena=16 herc=64 */
+ u8 multiq;
};
/* Structure representing MAC Addrs */
@@ -721,6 +722,17 @@ struct fifo_info {
*/
struct tx_curr_get_info tx_curr_get_info;
+
+#define FIFO_QUEUE_START 0
+#define FIFO_QUEUE_STOP 1
+ int queue_state;
+
+ /* copy of sp->dev pointer */
+ struct net_device *dev;
+
+ /* copy of multiq status */
+ u8 multiq;
+
/* Per fifo lock */
spinlock_t tx_lock;
@@ -756,7 +768,7 @@ struct mac_info {
dma_addr_t stats_mem_phy; /* Physical address of the stat block */
u32 stats_mem_sz;
struct stat_block *stats_info; /* Logical address of the stat block */
-};
+} ____cacheline_aligned;
/* structure representing the user defined MAC addresses */
struct usr_addr {
^ permalink raw reply
* Re: [PATCH 2.6.25 1/1]S2io: Multiqueue network device support implementation
From: Jeff Garzik @ 2008-01-23 0:55 UTC (permalink / raw)
To: Sreenivasa Honnur; +Cc: netdev, support
In-Reply-To: <Pine.GSO.4.10.10801221942530.24414-100000@guinness>
Sreenivasa Honnur wrote:
> Multiqueue netwrok device support implementation.
> - Added a loadable parameter "multiq" to enable/disable multiqueue support,
> by default it is disabled.
> - skb->queue_mapping is not used for queue/fifo selection. FIFO iselection is
> based on IP-TOS value, 0x0-0xF TOS values are mapped to 8 FIFOs.
> - Added per FIFO flags FIFO_QUEUE_START and FIFO_QUEUE_STOP. Check this flag
> for starting and stopping netif queue and update the flags accordingly.
> - In tx_intr_handler added a check to ensure that we have free TXDs before wak-
> ing up the queue.
> - Added helper functions for queue manipulation(start/stop/wakeup) to invoke
> appropriate netif_ functions.
> - Calling netif_start/stop for link up/down case respectively.
>
> Signed-off-by: Surjit Reang <surjit.reang@neterion.com>
> Signed-off-by: Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
thanks, at a quick glance, the use of the new multi-queue APIs look ok.
I'll give it another in-depth look and merge it.
^ permalink raw reply
* Re: [PATCH 0/6] PS3: gelic: gelic updates for 2.6.25
From: John W. Linville @ 2008-01-23 0:58 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Geert.Uytterhoeven, netdev, Linux/PPC Development
In-Reply-To: <1201048834.6807.55.camel@pasglop>
On Wed, Jan 23, 2008 at 11:40:34AM +1100, Benjamin Herrenschmidt wrote:
>
> On Tue, 2008-01-22 at 16:12 -0500, John W. Linville wrote:
> > On Thu, Dec 13, 2007 at 07:38:28PM +0900, Masakazu Mokuno wrote:
> >
> > > Here is a set of updates for PS3 gelic network driver.
> > > This patch set requires other patches which were already submitted by
> > > Geert (http://marc.info/?l=linux-kernel&m=119626095605487).
> > >
> > > [1] PS3: gelic: Fix the wrong dev_id passed
> > > [2] PS3: gelic: Add endianness macros
> > > [3] PS3: gelic: Code cleanup
> > > [4] PS3: gelic: Remove duplicated ethtool handers
> > > [5] PS3: gelic: Add support for port link status
> > > [6] PS3: gelic: Add support for dual network interface
> > >
> > > This is also a set of prerequisite for new wireless driver for PS3, which
> > > I'll submit later.
> >
> > These seem to not have been applied, but I couldn't find any stated
> > reason. Did they just get lost? Withdrawn?
> >
> > Will these be applied? There is a wireless patch that depends on them.
> > If not, will the wireless portion be refactored to not require these
> > patches?
>
> The list of 6 patches above are the patches that Masakazu Mukono is
> submitting, the pre-reqs are different patches (see the linked URL),
> though I can't see them in either (they should probably go through
> paulus for-2.6.25). Geert, what's up with these ?
The wireless patch depends on the patches 1-6, which then depend on
Geert's patches.
I thought Geert's had been applied, but I guess I was looking at
it wrong. Is there a powerpc tree that has them? Perhaps 1-6 above
and the wireless patch should just be applied to that tree (if there
is one) and all merged together?
John
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply
* Re: [PATCH net-2.6.25] Add packet filtering based on process\'s security context.
From: Tetsuo Handa @ 2008-01-23 1:26 UTC (permalink / raw)
To: casey; +Cc: linux-security-module, netfilter-devel, netdev, davem
In-Reply-To: <634344.24836.qm@web36604.mail.mud.yahoo.com>
Hello.
Casey Schaufler wrote:
> Do you have a real situation where two user processes with different
> security contexts share a socket? How do you get into that situation,
> and is it appropriate to have that situation in your security scheme?
> Can this occur without using privilege?
I hope such situation won't occur, as I have mentioned in the previous
posting.
| Precautions: This approach has a side effect which unlikely occurs.
|
| If a socket is shared by multiple processes with differnt policy,
| the process who should be able to accept this connection
| will not be able to accept this connection
| because socket_post_accept() aborts this connection.
| But if socket_post_accept() doesn't abort this connection,
| the process who must not be able to accept this connection
| will repeat accept() forever, which is a worse side effect.
|
| Similarly, if a socket is shared by multiple processes with differnt policy,
| the process who should be able to pick up this datagram
| will not be able to pick up this datagram
| because socket_post_recv_datagram() discards this datagram.
| But if socket_post_recv_datagram() doesn't discard this datagram,
| the process who must not be able to pick up this datagram
| will repeat recvmsg() forever, which is a worse side effect.
|
| So, don't give different permissions between processes who shares one socket.
| Otherwise, some connections/datagrams cannot be delivered to intended process.
But it is possible to write a code like
---------- app3.c start ----------
/* gcc -Wall -O2 -o /tmp/app3 app3.c */
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
const int fd1 = socket(PF_INET, SOCK_DGRAM, 0), fd2 = socket(PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
char buf[16];
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(10000);
fprintf(stderr, "%s started.\n", argv[0]);
if (bind(fd1, (struct sockaddr *) &addr, sizeof(addr))) {
fprintf(stderr, "Can't bind()\n");
return 1;
}
if (sendto(fd2, "hello\n", 6, 0, (struct sockaddr *) &addr, sizeof(addr)) != 6 ||
sendto(fd2, "world\n", 6, 0, (struct sockaddr *) &addr, sizeof(addr)) != 6) {
fprintf(stderr, "Can't sendto()\n");
return 1;
}
while (1) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd1, &rfds);
select(fd1 + 1, &rfds, NULL, NULL, NULL);
if (FD_ISSET(fd1, &rfds)) break;
fprintf(stderr, "Can't select()\n");
return 1;
}
if (fcntl(fd1, FD_CLOEXEC, 0)) {
fprintf(stderr, "Can't fcntl()\n");
return 1;
}
snprintf(buf, sizeof(buf), "%d", fd1);
execlp("/tmp/app4", "app4", buf, NULL);
fprintf(stderr, "Can't execve()\n");
return 1;
}
---------- app3.c end ----------
---------- app4.c start ----------
/* gcc -Wall -O2 -o /tmp/app4 app4.c */
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd;
if (argc != 2) {
fprintf(stderr, "Bad parameter.\n");
return 1;
}
fprintf(stderr, "%s started.\n", argv[0]);
fd = atoi(argv[1]);
while (1) {
struct sockaddr_in addr;
socklen_t size = sizeof(addr);
char buffer[1024];
int len;
len = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &size);
if (len == EOF) {
fprintf(stderr, "Can't recvfrom()\n");
return 1;
}
write(1, buffer, len);
}
return 0;
}
---------- app4.c end ----------
and assign different policy to /tmp/app1 and /tmp/app2 .
Therefore, I want to check at sys_recvmsg() time.
(Usage: Compile app3 and app4 and run /tmp/app3 .)
For TCP's case, see http://www.mail-archive.com/linux-security-module@vger.kernel.org/msg02531.html
What I want to do is perform connection/packet filtering
with the recipient of the incoming connection/packet known.
My security scheme controls based on the recipient of the incoming connection/packet.
In this case, not /tmp/app1 or /tmp/app3 , but /tmp/app2 or /tmp/app4.
This case occurs without using privilege.
Regards.
^ permalink raw reply
* Re: 2.6.24-rc8-mm1 : net tcp_input.c warnings
From: Dave Young @ 2008-01-23 1:44 UTC (permalink / raw)
To: Ilpo Järvinen; +Cc: LKML, David Miller, Netdev, Andrew Morton
In-Reply-To: <Pine.LNX.4.64.0801221115150.31652@kivilampi-30.cs.helsinki.fi>
On Jan 22, 2008 6:47 PM, Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> wrote:
>
> On Tue, 22 Jan 2008, Dave Young wrote:
>
> > On Jan 22, 2008 12:37 PM, Dave Young <hidave.darkstar@gmail.com> wrote:
> > >
> > > On Jan 22, 2008 5:14 AM, Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> wrote:
> > > >
> > > > On Mon, 21 Jan 2008, Dave Young wrote:
> > > >
> > > > > Please see the kernel messages following,(trigged while using some qemu session)
> > > > > BTW, seems there's some e100 error message as well.
> > > > >
> > > > > PCI: Setting latency timer of device 0000:00:1b.0 to 64
> > > > > e100: Intel(R) PRO/100 Network Driver, 3.5.23-k4-NAPI
> > > > > e100: Copyright(c) 1999-2006 Intel Corporation
> > > > > ACPI: PCI Interrupt 0000:03:08.0[A] -> GSI 20 (level, low) -> IRQ 20
> > > > > modprobe:2331 conflicting cache attribute efaff000-efb00000 uncached<->default
> > > > > e100: 0000:03:08.0: e100_probe: Cannot map device registers, aborting.
> > > > > ACPI: PCI interrupt for device 0000:03:08.0 disabled
> > > > > e100: probe of 0000:03:08.0 failed with error -12
> > > > > eth0: setting full-duplex.
> > > > > ------------[ cut here ]------------
> > > > > WARNING: at net/ipv4/tcp_input.c:2169 tcp_mark_head_lost+0x121/0x150()
> > > > > Modules linked in: snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss eeprom e100 psmouse snd_hda_intel snd_pcm snd_timer btusb rtc_cmos thermal bluetooth rtc_core serio_raw intel_agp button processor sg snd rtc_lib i2c_i801 evdev agpgart soundcore dcdbas 3c59x pcspkr snd_page_alloc
> > > > > Pid: 0, comm: swapper Not tainted 2.6.24-rc8-mm1 #4
> > > > > [<c0132100>] ? printk+0x0/0x20
> > > > > [<c0131834>] warn_on_slowpath+0x54/0x80
> > > > > [<c03e8df8>] ? ip_finish_output+0x128/0x2e0
> > > > > [<c03e9527>] ? ip_output+0xe7/0x100
> > > > > [<c03e8a88>] ? ip_local_out+0x18/0x20
> > > > > [<c03e991c>] ? ip_queue_xmit+0x3dc/0x470
> > > > > [<c043641e>] ? _spin_unlock_irqrestore+0x5e/0x70
> > > > > [<c0186be1>] ? check_pad_bytes+0x61/0x80
> > > > > [<c03f6031>] tcp_mark_head_lost+0x121/0x150
> > > > > [<c03f60ac>] tcp_update_scoreboard+0x4c/0x170
> > > > > [<c03f6e0a>] tcp_fastretrans_alert+0x48a/0x6b0
> > > > > [<c03f7d93>] tcp_ack+0x1b3/0x3a0
> > > > > [<c03fa14b>] tcp_rcv_established+0x3eb/0x710
> > > > > [<c04015c5>] tcp_v4_do_rcv+0xe5/0x100
> > > > > [<c0401bbb>] tcp_v4_rcv+0x5db/0x660
> > > >
> > > > Doh, once more these S+L things..., the rest are symptom of the first
> > > > problem.
> > >
> > > What is the S+L thing? Could you explain a bit?
>
> It means that one of the skbs is both SACKed and marked as LOST at the
> same time in the counters (might be due to miscount of lost/sacked_out
> too, not necessarilily in the ->sacked bits). Such state is logically
> invalid because it would mean that the sender thinks that the same packet
> both reached the receiver and is lost in the network.
>
> Traditionally TCP has just silently "corrected" over-estimates
> (sacked_out+lost_out > packets_out). I changed this couple of releases ago
> because those over-estimates often are due to bugs that should be fixed
> (there have been couple of them but it has been very quite on this front
> long time, months or even half year already; but I might have broken
> something with the early Dec changes).
>
> These problem may originate from a bug that occurred a number of ACKs
> earlier the WARN_ON triggered, therefore they are a bit tricky to track,
> those WARN_ON serve just for alerting purposes and usually do not point
> out where the bug actually occurred.
>
> I usually just asked people to include exhaustive verifier which compares
> ->sacked bitmaps with sacked/lost_out counters and report immediately when
> the problem shows up, rather than waiting for the cheaper S+L check we do
> in the WARN_ON to trigger. I tried to collect tracking patch from the
> previous efforts (hopefully got it right after modifications).
>
> > > I'm a bit worried about its
> > > > reproducability if it takes this far to see it...
> > > >
> >
> > It's trigged again in my pc, just while using firefox.
>
> ...Good, then there's some chance to catch it.
>
> --
> i.
>
> [PATCH] [TCP]: debug S+L
Thanks, If there's new findings I will let you know.
>
> ---
> include/net/tcp.h | 8 +++-
> net/ipv4/tcp_input.c | 6 +++
> net/ipv4/tcp_ipv4.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++
> net/ipv4/tcp_output.c | 21 +++++++---
> 4 files changed, 129 insertions(+), 7 deletions(-)
>
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 7de4ea3..0685035 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -272,6 +272,8 @@ DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics);
> #define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(tcp_statistics, field, val)
> #define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val)
>
> +extern void tcp_verify_wq(struct sock *sk);
> +
> extern void tcp_v4_err(struct sk_buff *skb, u32);
>
> extern void tcp_shutdown (struct sock *sk, int how);
> @@ -768,7 +770,11 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk)
> }
>
> /* Use define here intentionally to get WARN_ON location shown at the caller */
> -#define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out)
> +#define tcp_verify_left_out(tp) \
> + do { \
> + WARN_ON(tcp_left_out(tp) > tp->packets_out); \
> + tcp_verify_wq((struct sock *)tp); \
> + } while(0)
>
> extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh);
> extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst);
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index fa2c85c..0bda0e1 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -2645,6 +2645,10 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
> if (do_lost || (tcp_is_fack(tp) && tcp_head_timedout(sk)))
> tcp_update_scoreboard(sk, fast_rexmit);
> tcp_cwnd_down(sk, flag);
> +
> + WARN_ON(tcp_write_queue_head(sk) == NULL);
> + WARN_ON(!tp->packets_out);
> +
> tcp_xmit_retransmit_queue(sk);
> }
>
> @@ -2848,6 +2852,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets)
> tcp_clear_all_retrans_hints(tp);
> }
>
> + tcp_verify_left_out(tp);
> +
> if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
> flag |= FLAG_SACK_RENEGING;
>
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index 9aea88b..21f5888 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -108,6 +108,107 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
> .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
> };
>
> +void tcp_print_queue(struct sock *sk)
> +{
> + struct tcp_sock *tp = tcp_sk(sk);
> + struct sk_buff *skb;
> + char s[50+1];
> + char h[50+1];
> + int idx = 0;
> + int i;
> +
> + tcp_for_write_queue(skb, sk) {
> + if (skb == tcp_send_head(sk))
> + break;
> +
> + for (i = 0; i < tcp_skb_pcount(skb); i++) {
> + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) {
> + s[idx] = 'S';
> + if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
> + s[idx] = 'B';
> +
> + } else if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
> + s[idx] = 'L';
> + } else {
> + s[idx] = ' ';
> + }
> + if (s[idx] != ' ' && skb->len < tp->mss_cache)
> + s[idx] += 'a' - 'A';
> +
> + if (i == 0) {
> + if (TCP_SKB_CB(skb)->seq == tcp_highest_sack_seq(tp))
> + h[idx] = 'h';
> + else
> + h[idx] = '+';
> + } else {
> + h[idx] = '-';
> + }
> +
> + if (++idx >= 50) {
> + s[idx] = 0;
> + h[idx] = 0;
> + printk(KERN_ERR "TCP wq(s) %s\n", s);
> + printk(KERN_ERR "TCP wq(h) %s\n", h);
> + idx = 0;
> + }
> + }
> + }
> + if (idx) {
> + s[idx] = '<';
> + s[idx+1] = 0;
> + h[idx] = '<';
> + h[idx+1] = 0;
> + printk(KERN_ERR "TCP wq(s) %s\n", s);
> + printk(KERN_ERR "TCP wq(h) %s\n", h);
> + }
> + printk(KERN_ERR "l%u s%u f%u p%u seq: su%u hs%u sn%u\n",
> + tp->lost_out, tp->sacked_out, tp->fackets_out, tp->packets_out,
> + tp->snd_una, tcp_highest_sack_seq(tp), tp->snd_nxt);
> +}
> +
> +void tcp_verify_wq(struct sock *sk)
> +{
> + struct tcp_sock *tp = tcp_sk(sk);
> + u32 lost = 0;
> + u32 sacked = 0;
> + u32 packets = 0;
> + struct sk_buff *skb;
> +
> + tcp_for_write_queue(skb, sk) {
> + if (skb == tcp_send_head(sk))
> + break;
> +
> + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) {
> + sacked += tcp_skb_pcount(skb);
> + if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
> + printk(KERN_ERR "Sacked bitmap S+L: %u %u-%u/%u\n",
> + TCP_SKB_CB(skb)->sacked,
> + TCP_SKB_CB(skb)->end_seq - tp->snd_una,
> + TCP_SKB_CB(skb)->seq - tp->snd_una,
> + tp->snd_una);
> + }
> + if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
> + lost += tcp_skb_pcount(skb);
> +
> + packets += tcp_skb_pcount(skb);
> + }
> +
> + WARN_ON(lost != tp->lost_out);
> + WARN_ON(sacked != tp->sacked_out);
> + WARN_ON(packets != tp->packets_out);
> + if ((lost != tp->lost_out) ||
> + (sacked != tp->sacked_out) ||
> + (packets != tp->packets_out)) {
> + printk(KERN_ERR "P: %u L: %u vs %u S: %u vs %u w: %u-%u (%u)\n",
> + tp->packets_out,
> + lost, tp->lost_out,
> + sacked, tp->sacked_out,
> + tp->snd_una, tp->snd_nxt,
> + tp->rx_opt.sack_ok);
> + tcp_print_queue(sk);
> + }
> +}
> +
> static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
> {
> return inet_csk_get_port(&tcp_hashinfo, sk, snum,
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> index 89f0188..648340f 100644
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
> @@ -779,10 +779,9 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
> tp->lost_out -= diff;
>
> /* Adjust Reno SACK estimate. */
> - if (tcp_is_reno(tp) && diff > 0) {
> + if (tcp_is_reno(tp) && diff > 0)
> tcp_dec_pcount_approx_int(&tp->sacked_out, diff);
> - tcp_verify_left_out(tp);
> - }
> +
> tcp_adjust_fackets_out(sk, skb, diff);
> }
>
> @@ -790,6 +789,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
> skb_header_release(buff);
> tcp_insert_write_queue_after(skb, buff, sk);
>
> + tcp_verify_left_out(tp);
> +
> return 0;
> }
>
> @@ -1463,6 +1464,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
> } else if (result > 0) {
> sent_pkts = 1;
> }
> + tcp_verify_left_out(tp);
>
> while ((skb = tcp_send_head(sk))) {
> unsigned int limit;
> @@ -1764,6 +1766,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb,
> tcp_clear_retrans_hints_partial(tp);
>
> sk_wmem_free_skb(sk, next_skb);
> + tcp_verify_left_out(tp);
> }
>
> /* Do a simple retransmit without using the backoff mechanisms in
> @@ -1795,13 +1798,13 @@ void tcp_simple_retransmit(struct sock *sk)
> }
> }
>
> + tcp_verify_left_out(tp);
> +
> tcp_clear_all_retrans_hints(tp);
>
> if (!lost)
> return;
>
> - tcp_verify_left_out(tp);
> -
> /* Don't muck with the congestion window here.
> * Reason is that we do not increase amount of _data_
> * in network, but units changed and effective
> @@ -1970,8 +1973,10 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
> * packet to be MSS sized and all the
> * packet counting works out.
> */
> - if (tcp_packets_in_flight(tp) >= tp->snd_cwnd)
> + if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) {
> + tcp_verify_left_out(tp);
> return;
> + }
>
> if (sacked & TCPCB_LOST) {
> if (!(sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) {
> @@ -1997,6 +2002,8 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
> }
> }
>
> + tcp_verify_left_out(tp);
> +
> /* OK, demanded retransmission is finished. */
>
> /* Forward retransmissions are possible only during Recovery. */
> @@ -2054,6 +2061,8 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
>
> NET_INC_STATS_BH(LINUX_MIB_TCPFORWARDRETRANS);
> }
> +
> + tcp_verify_left_out(tp);
> }
>
> /* Send a fin. The caller locks the socket for us. This cannot be
> --
> 1.5.2.2
>
^ permalink raw reply
* pull request: wireless-2.6 'fixes' 2008-01-22
From: John W. Linville @ 2008-01-23 1:44 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA
Dave,
Here is a NULL pointer avoidance fix for iwlwifi that would be nice
to have in 2.6.24 if possible.
Thanks!
John
---
Individual patch available here:
http://www.kernel.org/pub/linux/kernel/people/linville/wireless-2.6/fixes
---
The following changes since commit 889c94a14e38e749c8060f597ee7825ea0764229:
Johann Felix Soden (1):
Fix file references in documentation and Kconfig
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git fixes
Reinette Chatre (1):
iwlwifi: fix possible read attempt on ucode that is not available
drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +++++
drivers/net/wireless/iwlwifi/iwl4965-base.c | 5 +++++
2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1a6b0e0..0b3ec7e 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -6342,6 +6342,11 @@ static int __iwl_up(struct iwl_priv *priv)
return 0;
}
+ if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+ IWL_ERROR("ucode not available for device bringup\n");
+ return -EIO;
+ }
+
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
rc = iwl_hw_nic_init(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 6cd57c2..15a45f4 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -6698,6 +6698,11 @@ static int __iwl_up(struct iwl_priv *priv)
return 0;
}
+ if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+ IWL_ERROR("ucode not available for device bringup\n");
+ return -EIO;
+ }
+
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
rc = iwl_hw_nic_init(priv);
--
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org
^ permalink raw reply related
* pull request: wireless-2.6 'upstream' 2008-01-22
From: John W. Linville @ 2008-01-23 1:45 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-wireless
Dave,
This is another collection of updates intended for 2.6.25. There are
some ath5k cleanups, some b43 stuff, some mac80211 bits, and a few other
miscellaneous patches.
Let me know if there are problems!
Thanks!
John
---
Individual patch available here:
http://www.kernel.org/pub/linux/kernel/people/linville/wireless-2.6/upstream
---
The following changes since commit bae4a7effd59ef0d521de2bc97902fa0a243b544:
David S. Miller (1):
Merge branch 'upstream-davem' of master.kernel.org:/.../jgarzik/netdev-2.6
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
Bruno Randolf (6):
ath5k: use 3 instead of 0x00000003
ath5k: beacon interval is in TU
ath5k: better beacon timer calculation
ath5k: use SWBA to detect IBSS HW merges
ath5k: configure backoff for IBSS beacon queue
ath5k: always extend rx timestamp with tsf
Guy Cohen (1):
mac80211: Assign correct TID for local bridged packets
Johannes Berg (1):
mac80211: fix RCU locking in __ieee80211_rx_handle_packet
John W. Linville (2):
ath5k: use AR5K_KEYTABLE_SIZE when initializing key table
ath5k: reset key cache after resume
Masakazu Mokuno (1):
WEXT: remove unused variable
Michael Buesch (4):
b43legacy: Remove the PHY spinlock
b43: Add more N-PHY init code
b43: Fix firmware caching
b43: Fix MAC control and microcode init
Ron Rindjunsky (2):
mac80211: fixing ieee80211_bar types
mac80211: fix rx flow sparse errors, make functions static
Stefano Brivio (1):
rc80211-pid: fix last_sample initialization
drivers/net/wireless/ath5k/ath5k.h | 4 +-
drivers/net/wireless/ath5k/base.c | 240 +++++++++++++++++++----
drivers/net/wireless/ath5k/base.h | 3 +-
drivers/net/wireless/ath5k/hw.c | 6 +-
drivers/net/wireless/b43/b43.h | 15 +-
drivers/net/wireless/b43/main.c | 290 ++++++++++++++++-----------
drivers/net/wireless/b43/nphy.c | 292 +++++++++++++++++++++++++++-
drivers/net/wireless/b43/nphy.h | 52 +++---
drivers/net/wireless/b43legacy/b43legacy.h | 16 +-
drivers/net/wireless/b43legacy/main.c | 4 -
drivers/net/wireless/b43legacy/phy.c | 35 ++--
drivers/net/wireless/b43legacy/phy.h | 14 +--
drivers/net/wireless/b43legacy/radio.c | 7 +-
include/linux/ieee80211.h | 4 +-
net/mac80211/ieee80211_sta.c | 4 +-
net/mac80211/rc80211_pid_algo.c | 2 +
net/mac80211/rx.c | 13 +-
net/mac80211/wme.c | 9 +-
net/wireless/wext.c | 14 --
19 files changed, 752 insertions(+), 272 deletions(-)
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 878609f..c79066b 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -486,8 +486,8 @@ struct ath5k_beacon_state {
* TSF to TU conversion:
*
* TSF is a 64bit value in usec (microseconds).
- * TU is a 32bit value in roughly msec (milliseconds): usec / 1024
- * (1000ms equals 976 TU)
+ * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of
+ * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024).
*/
#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 742616a..72bcf32 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -290,6 +290,7 @@ static int ath5k_beacon_setup(struct ath5k_softc *sc,
struct ieee80211_tx_control *ctl);
static void ath5k_beacon_send(struct ath5k_softc *sc);
static void ath5k_beacon_config(struct ath5k_softc *sc);
+static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
{
@@ -604,7 +605,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath5k_softc *sc = hw->priv;
- int err;
+ struct ath5k_hw *ah = sc->ah;
+ int i, err;
err = pci_set_power_state(pdev, PCI_D0);
if (err)
@@ -624,10 +626,20 @@ ath5k_pci_resume(struct pci_dev *pdev)
ath5k_init(sc);
if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
- ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
- ath5k_hw_set_gpio(sc->ah, sc->led_pin, 0);
+ ath5k_hw_set_gpio_output(ah, sc->led_pin);
+ ath5k_hw_set_gpio(ah, sc->led_pin, 0);
}
+ /*
+ * Reset the key cache since some parts do not
+ * reset the contents on initial power up or resume.
+ *
+ * FIXME: This may need to be revisited when mac80211 becomes
+ * aware of suspend/resume.
+ */
+ for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
+ ath5k_hw_reset_key(ah, i);
+
return 0;
}
#endif /* CONFIG_PM */
@@ -663,7 +675,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
* Reset the key cache since some parts do not
* reset the contents on initial power up.
*/
- for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+ for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
ath5k_hw_reset_key(ah, i);
/*
@@ -1446,8 +1458,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
if (ret)
return ret;
- if (sc->opmode == IEEE80211_IF_TYPE_AP ||
- sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ if (sc->opmode == IEEE80211_IF_TYPE_AP) {
/*
* Always burst out beacon and CAB traffic
* (aifs = cwmin = cwmax = 0)
@@ -1455,8 +1466,19 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
qi.tqi_aifs = 0;
qi.tqi_cw_min = 0;
qi.tqi_cw_max = 0;
+ } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ /*
+ * Adhoc mode; backoff between 0 and (2 * cw_min).
+ */
+ qi.tqi_aifs = 0;
+ qi.tqi_cw_min = 0;
+ qi.tqi_cw_max = 2 * ah->ah_cw_min;
}
+ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+ "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n",
+ qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max);
+
ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi);
if (ret) {
ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
@@ -1628,6 +1650,34 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
return 0;
}
+
+static void
+ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
+{
+ u32 hw_tu;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+
+ if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) ==
+ IEEE80211_FTYPE_MGMT &&
+ (mgmt->frame_control & IEEE80211_FCTL_STYPE) ==
+ IEEE80211_STYPE_BEACON &&
+ mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
+ memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
+ /*
+ * Received an IBSS beacon with the same BSSID. Hardware might
+ * have updated the TSF, check if we need to update timers.
+ */
+ hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah));
+ if (hw_tu >= sc->nexttbtt) {
+ ath5k_beacon_update_timers(sc,
+ mgmt->u.beacon.timestamp);
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "detected HW merge from received beacon\n");
+ }
+ }
+}
+
+
static void
ath5k_tasklet_rx(unsigned long data)
{
@@ -1725,11 +1775,18 @@ accept:
skb_pull(skb, pad);
}
- if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
- rxs.mactime = ath5k_extend_tsf(sc->ah,
- ds->ds_rxstat.rs_tstamp);
- else
- rxs.mactime = ds->ds_rxstat.rs_tstamp;
+ /*
+ * always extend the mac timestamp, since this information is
+ * also needed for proper IBSS merging.
+ *
+ * XXX: it might be too late to do it here, since rs_tstamp is
+ * 15bit only. that means TSF extension has to be done within
+ * 32768usec (about 32ms). it might be necessary to move this to
+ * the interrupt handler, like it is done in madwifi.
+ */
+ rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp);
+ rxs.flag |= RX_FLAG_TSFT;
+
rxs.freq = sc->curchan->freq;
rxs.channel = sc->curchan->chan;
rxs.phymode = sc->curmode;
@@ -1755,6 +1812,10 @@ accept:
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
+ /* check beacons in IBSS mode */
+ if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+ ath5k_check_ibss_hw_merge(sc, skb);
+
__ieee80211_rx(sc->hw, skb, &rxs);
sc->led_rxrate = ds->ds_rxstat.rs_rate;
ath5k_led_event(sc, ATH_LED_RX);
@@ -1973,47 +2034,120 @@ ath5k_beacon_send(struct ath5k_softc *sc)
}
+/**
+ * ath5k_beacon_update_timers - update beacon timers
+ *
+ * @sc: struct ath5k_softc pointer we are operating on
+ * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a
+ * beacon timer update based on the current HW TSF.
+ *
+ * Calculate the next target beacon transmit time (TBTT) based on the timestamp
+ * of a received beacon or the current local hardware TSF and write it to the
+ * beacon timer registers.
+ *
+ * This is called in a variety of situations, e.g. when a beacon is received,
+ * when a HW merge has been detected, but also when an new IBSS is created or
+ * when we otherwise know we have to update the timers, but we keep it in this
+ * function to have it all together in one place.
+ */
static void
-ath5k_beacon_update_timers(struct ath5k_softc *sc)
+ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
{
struct ath5k_hw *ah = sc->ah;
- u32 uninitialized_var(nexttbtt), intval, tsftu;
- u64 tsf;
+ u32 nexttbtt, intval, hw_tu, bc_tu;
+ u64 hw_tsf;
intval = sc->bintval & AR5K_BEACON_PERIOD;
if (WARN_ON(!intval))
return;
+ /* beacon TSF converted to TU */
+ bc_tu = TSF_TO_TU(bc_tsf);
+
/* current TSF converted to TU */
- tsf = ath5k_hw_get_tsf64(ah);
- tsftu = TSF_TO_TU(tsf);
+ hw_tsf = ath5k_hw_get_tsf64(ah);
+ hw_tu = TSF_TO_TU(hw_tsf);
- /*
- * Pull nexttbtt forward to reflect the current
- * TSF. Add one intval otherwise the timespan
- * can be too short for ibss merges.
- */
- nexttbtt = tsftu + 2 * intval;
+#define FUDGE 3
+ /* we use FUDGE to make sure the next TBTT is ahead of the current TU */
+ if (bc_tsf == -1) {
+ /*
+ * no beacons received, called internally.
+ * just need to refresh timers based on HW TSF.
+ */
+ nexttbtt = roundup(hw_tu + FUDGE, intval);
+ } else if (bc_tsf == 0) {
+ /*
+ * no beacon received, probably called by ath5k_reset_tsf().
+ * reset TSF to start with 0.
+ */
+ nexttbtt = intval;
+ intval |= AR5K_BEACON_RESET_TSF;
+ } else if (bc_tsf > hw_tsf) {
+ /*
+ * beacon received, SW merge happend but HW TSF not yet updated.
+ * not possible to reconfigure timers yet, but next time we
+ * receive a beacon with the same BSSID, the hardware will
+ * automatically update the TSF and then we need to reconfigure
+ * the timers.
+ */
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "need to wait for HW TSF sync\n");
+ return;
+ } else {
+ /*
+ * most important case for beacon synchronization between STA.
+ *
+ * beacon received and HW TSF has been already updated by HW.
+ * update next TBTT based on the TSF of the beacon, but make
+ * sure it is ahead of our local TSF timer.
+ */
+ nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval);
+ }
+#undef FUDGE
- ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
- "hw tsftu %u nexttbtt %u intval %u\n", tsftu, nexttbtt, intval);
+ sc->nexttbtt = nexttbtt;
intval |= AR5K_BEACON_ENA;
-
ath5k_hw_init_beacon(ah, nexttbtt, intval);
+
+ /*
+ * debugging output last in order to preserve the time critical aspect
+ * of this function
+ */
+ if (bc_tsf == -1)
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "reconfigured timers based on HW TSF\n");
+ else if (bc_tsf == 0)
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "reset HW TSF and timers\n");
+ else
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "updated timers based on beacon TSF\n");
+
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+ "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n",
+ bc_tsf, hw_tsf, bc_tu, hw_tu, nexttbtt);
+ ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n",
+ intval & AR5K_BEACON_PERIOD,
+ intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "",
+ intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : "");
}
-/*
- * Configure the beacon timers and interrupts based on the operating mode
+/**
+ * ath5k_beacon_config - Configure the beacon queues and interrupts
+ *
+ * @sc: struct ath5k_softc pointer we are operating on
*
* When operating in station mode we want to receive a BMISS interrupt when we
* stop seeing beacons from the AP we've associated with so we can look for
* another AP to associate with.
*
- * In IBSS mode we need to configure the beacon timers and use a self-linked tx
- * descriptor if possible. If the hardware cannot deal with that we enable SWBA
- * interrupts to send the beacons from the interrupt handler.
+ * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
+ * interrupts to detect HW merges only.
+ *
+ * AP mode is missing.
*/
static void
ath5k_beacon_config(struct ath5k_softc *sc)
@@ -2027,18 +2161,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_BMISS;
} else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
/*
- * In IBSS mode enable the beacon timers but only enable SWBA
- * interrupts if we need to manually prepare beacon frames.
- * Otherwise we use a self-linked tx descriptor and let the
- * hardware deal with things. In that case we have to load it
+ * In IBSS mode we use a self-linked tx descriptor and let the
+ * hardware send the beacons automatically. We have to load it
* only once here.
+ * We use the SWBA interrupt only to keep track of the beacon
+ * timers in order to detect HW merges (automatic TSF updates).
*/
ath5k_beaconq_config(sc);
- ath5k_beacon_update_timers(sc);
- if (!ath5k_hw_hasveol(ah))
- sc->imask |= AR5K_INT_SWBA;
- else
+ sc->imask |= AR5K_INT_SWBA;
+
+ if (ath5k_hw_hasveol(ah))
ath5k_beacon_send(sc);
}
/* TODO else AP */
@@ -2241,8 +2374,24 @@ ath5k_intr(int irq, void *dev_id)
* Handle beacon transmission directly; deferring
* this is too slow to meet timing constraints
* under load.
+ *
+ * In IBSS mode we use this interrupt just to
+ * keep track of the next TBTT (target beacon
+ * transmission time) in order to detect hardware
+ * merges (TSF updates).
*/
- ath5k_beacon_send(sc);
+ if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+ /* XXX: only if VEOL suppported */
+ u64 tsf = ath5k_hw_get_tsf64(ah);
+ sc->nexttbtt += sc->bintval;
+ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+ "SWBA nexttbtt: %x hw_tu: %x "
+ "TSF: %llx\n",
+ sc->nexttbtt,
+ TSF_TO_TU(tsf), tsf);
+ } else {
+ ath5k_beacon_send(sc);
+ }
}
if (status & AR5K_INT_RXEOL) {
/*
@@ -2543,7 +2692,7 @@ ath5k_config(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
- sc->bintval = conf->beacon_int * 1000 / 1024;
+ sc->bintval = conf->beacon_int;
ath5k_setcurmode(sc, conf->phymode);
return ath5k_chan_set(sc, conf->chan);
@@ -2559,7 +2708,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* Set to a reasonable value. Note that this will
* be set to mac80211's value at ath5k_config(). */
- sc->bintval = 1000 * 1000 / 1024;
+ sc->bintval = 1000;
mutex_lock(&sc->lock);
if (sc->vif != vif) {
ret = -EIO;
@@ -2784,7 +2933,14 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
- ath5k_hw_reset_tsf(sc->ah);
+ /*
+ * in IBSS mode we need to update the beacon timers too.
+ * this will also reset the TSF if we call it with 0
+ */
+ if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+ ath5k_beacon_update_timers(sc, 0);
+ else
+ ath5k_hw_reset_tsf(sc->ah);
}
static int
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 7ba2223..8287ae7 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -164,8 +164,9 @@ struct ath5k_softc {
struct ath5k_buf *bbuf; /* beacon buffer */
unsigned int bhalq, /* SW q for outgoing beacons */
bmisscount, /* missed beacon transmits */
- bintval, /* beacon interval */
+ bintval, /* beacon interval in TU */
bsent;
+ unsigned int nexttbtt; /* next beacon time in TU */
struct timer_list calib_tim; /* calibration timer */
};
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index eb00818..3a4bf40 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -2605,10 +2605,8 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
break;
default:
- timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) <<
- 0x00000003;
- timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) <<
- 0x00000003;
+ timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
+ timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
}
timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index c7eea30..32a24f5 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -665,16 +665,23 @@ struct b43_wl {
bool beacon1_uploaded;
};
+/* In-memory representation of a cached microcode file. */
+struct b43_firmware_file {
+ const char *filename;
+ const struct firmware *data;
+};
+
/* Pointers to the firmware data and meta information about it. */
struct b43_firmware {
/* Microcode */
- const struct firmware *ucode;
+ struct b43_firmware_file ucode;
/* PCM code */
- const struct firmware *pcm;
+ struct b43_firmware_file pcm;
/* Initial MMIO values for the firmware */
- const struct firmware *initvals;
+ struct b43_firmware_file initvals;
/* Initial MMIO values for the firmware, band-specific */
- const struct firmware *initvals_band;
+ struct b43_firmware_file initvals_band;
+
/* Firmware revision */
u16 rev;
/* Firmware patchlevel */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 0d9824c..88d2c15 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1557,16 +1557,19 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
return ret;
}
+static void do_release_fw(struct b43_firmware_file *fw)
+{
+ release_firmware(fw->data);
+ fw->data = NULL;
+ fw->filename = NULL;
+}
+
static void b43_release_firmware(struct b43_wldev *dev)
{
- release_firmware(dev->fw.ucode);
- dev->fw.ucode = NULL;
- release_firmware(dev->fw.pcm);
- dev->fw.pcm = NULL;
- release_firmware(dev->fw.initvals);
- dev->fw.initvals = NULL;
- release_firmware(dev->fw.initvals_band);
- dev->fw.initvals_band = NULL;
+ do_release_fw(&dev->fw.ucode);
+ do_release_fw(&dev->fw.pcm);
+ do_release_fw(&dev->fw.initvals);
+ do_release_fw(&dev->fw.initvals_band);
}
static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
@@ -1584,33 +1587,43 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
static int do_request_fw(struct b43_wldev *dev,
const char *name,
- const struct firmware **fw)
+ struct b43_firmware_file *fw)
{
char path[sizeof(modparam_fwpostfix) + 32];
+ const struct firmware *blob;
struct b43_fw_header *hdr;
u32 size;
int err;
- if (!name)
+ if (!name) {
+ /* Don't fetch anything. Free possibly cached firmware. */
+ do_release_fw(fw);
return 0;
+ }
+ if (fw->filename) {
+ if (strcmp(fw->filename, name) == 0)
+ return 0; /* Already have this fw. */
+ /* Free the cached firmware first. */
+ do_release_fw(fw);
+ }
snprintf(path, ARRAY_SIZE(path),
"b43%s/%s.fw",
modparam_fwpostfix, name);
- err = request_firmware(fw, path, dev->dev->dev);
+ err = request_firmware(&blob, path, dev->dev->dev);
if (err) {
b43err(dev->wl, "Firmware file \"%s\" not found "
"or load failed.\n", path);
return err;
}
- if ((*fw)->size < sizeof(struct b43_fw_header))
+ if (blob->size < sizeof(struct b43_fw_header))
goto err_format;
- hdr = (struct b43_fw_header *)((*fw)->data);
+ hdr = (struct b43_fw_header *)(blob->data);
switch (hdr->type) {
case B43_FW_TYPE_UCODE:
case B43_FW_TYPE_PCM:
size = be32_to_cpu(hdr->size);
- if (size != (*fw)->size - sizeof(struct b43_fw_header))
+ if (size != blob->size - sizeof(struct b43_fw_header))
goto err_format;
/* fallthrough */
case B43_FW_TYPE_IV:
@@ -1621,10 +1634,15 @@ static int do_request_fw(struct b43_wldev *dev,
goto err_format;
}
- return err;
+ fw->data = blob;
+ fw->filename = name;
+
+ return 0;
err_format:
b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ release_firmware(blob);
+
return -EPROTO;
}
@@ -1636,97 +1654,96 @@ static int b43_request_firmware(struct b43_wldev *dev)
u32 tmshigh;
int err;
+ /* Get microcode */
tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
- if (!fw->ucode) {
+ if ((rev >= 5) && (rev <= 10))
+ filename = "ucode5";
+ else if ((rev >= 11) && (rev <= 12))
+ filename = "ucode11";
+ else if (rev >= 13)
+ filename = "ucode13";
+ else
+ goto err_no_ucode;
+ err = do_request_fw(dev, filename, &fw->ucode);
+ if (err)
+ goto err_load;
+
+ /* Get PCM code */
+ if ((rev >= 5) && (rev <= 10))
+ filename = "pcm5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_pcm;
+ err = do_request_fw(dev, filename, &fw->pcm);
+ if (err)
+ goto err_load;
+
+ /* Get initvals */
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+ filename = "a0g1initvals5";
+ else
+ filename = "a0g0initvals5";
+ } else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
if ((rev >= 5) && (rev <= 10))
- filename = "ucode5";
- else if ((rev >= 11) && (rev <= 12))
- filename = "ucode11";
+ filename = "b0g0initvals5";
else if (rev >= 13)
- filename = "ucode13";
+ filename = "lp0initvals13";
else
- goto err_no_ucode;
- err = do_request_fw(dev, filename, &fw->ucode);
- if (err)
- goto err_load;
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_N:
+ if ((rev >= 11) && (rev <= 12))
+ filename = "n0initvals11";
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
}
- if (!fw->pcm) {
+ err = do_request_fw(dev, filename, &fw->initvals);
+ if (err)
+ goto err_load;
+
+ /* Get bandswitch initvals */
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+ filename = "a0g1bsinitvals5";
+ else
+ filename = "a0g0bsinitvals5";
+ } else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
if ((rev >= 5) && (rev <= 10))
- filename = "pcm5";
+ filename = "b0g0bsinitvals5";
else if (rev >= 11)
filename = NULL;
else
- goto err_no_pcm;
- err = do_request_fw(dev, filename, &fw->pcm);
- if (err)
- goto err_load;
- }
- if (!fw->initvals) {
- switch (dev->phy.type) {
- case B43_PHYTYPE_A:
- if ((rev >= 5) && (rev <= 10)) {
- if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
- filename = "a0g1initvals5";
- else
- filename = "a0g0initvals5";
- } else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_G:
- if ((rev >= 5) && (rev <= 10))
- filename = "b0g0initvals5";
- else if (rev >= 13)
- filename = "lp0initvals13";
- else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_N:
- if ((rev >= 11) && (rev <= 12))
- filename = "n0initvals11";
- else
- goto err_no_initvals;
- break;
- default:
goto err_no_initvals;
- }
- err = do_request_fw(dev, filename, &fw->initvals);
- if (err)
- goto err_load;
- }
- if (!fw->initvals_band) {
- switch (dev->phy.type) {
- case B43_PHYTYPE_A:
- if ((rev >= 5) && (rev <= 10)) {
- if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
- filename = "a0g1bsinitvals5";
- else
- filename = "a0g0bsinitvals5";
- } else if (rev >= 11)
- filename = NULL;
- else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_G:
- if ((rev >= 5) && (rev <= 10))
- filename = "b0g0bsinitvals5";
- else if (rev >= 11)
- filename = NULL;
- else
- goto err_no_initvals;
- break;
- case B43_PHYTYPE_N:
- if ((rev >= 11) && (rev <= 12))
- filename = "n0bsinitvals11";
- else
- goto err_no_initvals;
- break;
- default:
+ break;
+ case B43_PHYTYPE_N:
+ if ((rev >= 11) && (rev <= 12))
+ filename = "n0bsinitvals11";
+ else
goto err_no_initvals;
- }
- err = do_request_fw(dev, filename, &fw->initvals_band);
- if (err)
- goto err_load;
+ break;
+ default:
+ goto err_no_initvals;
}
+ err = do_request_fw(dev, filename, &fw->initvals_band);
+ if (err)
+ goto err_load;
return 0;
@@ -1761,22 +1778,33 @@ static int b43_upload_microcode(struct b43_wldev *dev)
const __be32 *data;
unsigned int i, len;
u16 fwrev, fwpatch, fwdate, fwtime;
- u32 tmp;
+ u32 tmp, macctl;
int err = 0;
+ /* Jump the microcode PSM to offset 0 */
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
+ macctl |= B43_MACCTL_PSM_JMP0;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Zero out all microcode PSM registers and shared memory. */
+ for (i = 0; i < 64; i++)
+ b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
+ for (i = 0; i < 4096; i += 2)
+ b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
+
/* Upload Microcode. */
- data = (__be32 *) (dev->fw.ucode->data + hdr_len);
- len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+ data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
+ len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
for (i = 0; i < len; i++) {
b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
udelay(10);
}
- if (dev->fw.pcm) {
+ if (dev->fw.pcm.data) {
/* Upload PCM data. */
- data = (__be32 *) (dev->fw.pcm->data + hdr_len);
- len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+ data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
+ len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
/* No need for autoinc bit in SHM_HW */
@@ -1788,9 +1816,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
}
b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
- b43_write32(dev, B43_MMIO_MACCTL,
- B43_MACCTL_PSM_RUN |
- B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+ /* Start the microcode PSM */
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_PSM_JMP0;
+ macctl |= B43_MACCTL_PSM_RUN;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
/* Wait for the microcode to load and respond */
i = 0;
@@ -1799,13 +1830,17 @@ static int b43_upload_microcode(struct b43_wldev *dev)
if (tmp == B43_IRQ_MAC_SUSPENDED)
break;
i++;
- if (i >= 50) {
+ if (i >= 20) {
b43err(dev->wl, "Microcode not responding\n");
b43_print_fw_helptext(dev->wl, 1);
err = -ENODEV;
- goto out;
+ goto error;
+ }
+ msleep_interruptible(50);
+ if (signal_pending(current)) {
+ err = -EINTR;
+ goto error;
}
- udelay(10);
}
b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
@@ -1820,9 +1855,8 @@ static int b43_upload_microcode(struct b43_wldev *dev)
"binary drivers older than version 4.x is unsupported. "
"You must upgrade your firmware files.\n");
b43_print_fw_helptext(dev->wl, 1);
- b43_write32(dev, B43_MMIO_MACCTL, 0);
err = -EOPNOTSUPP;
- goto out;
+ goto error;
}
b43dbg(dev->wl, "Loading firmware version %u.%u "
"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -1839,7 +1873,14 @@ static int b43_upload_microcode(struct b43_wldev *dev)
b43_print_fw_helptext(dev->wl, 0);
}
-out:
+ return 0;
+
+error:
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_PSM_RUN;
+ macctl |= B43_MACCTL_PSM_JMP0;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
return err;
}
@@ -1913,19 +1954,19 @@ static int b43_upload_initvals(struct b43_wldev *dev)
size_t count;
int err;
- hdr = (const struct b43_fw_header *)(fw->initvals->data);
- ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+ hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
+ ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
count = be32_to_cpu(hdr->size);
err = b43_write_initvals(dev, ivals, count,
- fw->initvals->size - hdr_len);
+ fw->initvals.data->size - hdr_len);
if (err)
goto out;
- if (fw->initvals_band) {
- hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
- ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+ if (fw->initvals_band.data) {
+ hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
+ ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
count = be32_to_cpu(hdr->size);
err = b43_write_initvals(dev, ivals, count,
- fw->initvals_band->size - hdr_len);
+ fw->initvals_band.data->size - hdr_len);
if (err)
goto out;
}
@@ -2211,11 +2252,15 @@ static int b43_chip_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
int err, tmp;
- u32 value32;
+ u32 value32, macctl;
u16 value16;
- b43_write32(dev, B43_MMIO_MACCTL,
- B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+ /* Initialize the MAC control */
+ macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+ if (dev->phy.gmode)
+ macctl |= B43_MACCTL_GMODE;
+ macctl |= B43_MACCTL_INFRA;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
err = b43_request_firmware(dev);
if (err)
@@ -3359,12 +3404,19 @@ static void b43_set_retry_limits(struct b43_wldev *dev,
static void b43_wireless_core_exit(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
+ u32 macctl;
B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
if (b43_status(dev) != B43_STAT_INITIALIZED)
return;
b43_set_status(dev, B43_STAT_UNINIT);
+ /* Stop the microcode PSM. */
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_PSM_RUN;
+ macctl |= B43_MACCTL_PSM_JMP0;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
b43_leds_exit(dev);
b43_rng_exit(dev->wl);
b43_dma_free(dev);
diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c
index 0b421b1..705131e 100644
--- a/drivers/net/wireless/b43/nphy.c
+++ b/drivers/net/wireless/b43/nphy.c
@@ -29,6 +29,8 @@
#include "nphy.h"
#include "tables_nphy.h"
+#include <linux/delay.h>
+
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO
@@ -191,9 +193,297 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev)
~B43_NPHY_RFCTL_CMD_EN);
}
+#define ntab_upload(dev, offset, data) do { \
+ unsigned int i; \
+ for (i = 0; i < (offset##_SIZE); i++) \
+ b43_ntab_write(dev, (offset) + i, (data)[i]); \
+ } while (0)
+
+/* Upload the N-PHY tables. */
+static void b43_nphy_tables_init(struct b43_wldev *dev)
+{
+ /* Static tables */
+ ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+ ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+ ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+ ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+ ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+ ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+ ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+ ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+ ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+ ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+ ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+ ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+ ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+ ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+ /* Volatile tables */
+ ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+ ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+ ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+ ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+ ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+ ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+ ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+ ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+ ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+ ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+ ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+ ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ unsigned int i;
+
+ b43_phy_set(dev, B43_NPHY_IQFLIP,
+ B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+ //FIXME the following condition is different in the specs.
+ if (1 /* FIXME band is 2.4GHz */) {
+ b43_phy_set(dev, B43_NPHY_CLASSCTL,
+ B43_NPHY_CLASSCTL_CCKEN);
+ } else {
+ b43_phy_mask(dev, B43_NPHY_CLASSCTL,
+ ~B43_NPHY_CLASSCTL_CCKEN);
+ }
+ b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+ b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
+
+ /* Fixup some tables */
+ b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
+ b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
+
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+ b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+ //TODO set RF sequence
+
+ /* Set narrowband clip threshold */
+ b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
+ b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
+
+ /* Set wideband clip 2 threshold */
+ b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+ ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+ 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
+ b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+ ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+ 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
+
+ /* Set Clip 2 detect */
+ b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+ B43_NPHY_C1_CGAINI_CL2DETECT);
+ b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+ B43_NPHY_C2_CGAINI_CL2DETECT);
+
+ if (0 /*FIXME*/) {
+ /* Set dwell lengths */
+ b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
+ b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
+ b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
+ b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
+
+ /* Set gain backoff */
+ b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+ ~B43_NPHY_C1_CGAINI_GAINBKOFF,
+ 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
+ b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+ ~B43_NPHY_C2_CGAINI_GAINBKOFF,
+ 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
+
+ /* Set HPVGA2 index */
+ b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+ ~B43_NPHY_C1_INITGAIN_HPVGA2,
+ 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+ b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+ ~B43_NPHY_C2_INITGAIN_HPVGA2,
+ 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+ //FIXME verify that the specs really mean to use autoinc here.
+ for (i = 0; i < 3; i++)
+ b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
+ }
+
+ /* Set minimum gain value */
+ b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
+ ~B43_NPHY_C1_MINGAIN,
+ 23 << B43_NPHY_C1_MINGAIN_SHIFT);
+ b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
+ ~B43_NPHY_C2_MINGAIN,
+ 23 << B43_NPHY_C2_MINGAIN_SHIFT);
+
+ if (phy->rev < 2) {
+ b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+ ~B43_NPHY_SCRAM_SIGCTL_SCM);
+ }
+
+ /* Set phase track alpha and beta */
+ b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+ b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+ b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+}
+
+static void b43_nphy_reset_cca(struct b43_wldev *dev)
+{
+ u16 bbcfg;
+
+ ssb_write32(dev->dev, SSB_TMSLOW,
+ ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
+ bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+ b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
+ b43_phy_write(dev, B43_NPHY_BBCFG,
+ bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+ ssb_write32(dev->dev, SSB_TMSLOW,
+ ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+}
+
+enum b43_nphy_rf_sequence {
+ B43_RFSEQ_RX2TX,
+ B43_RFSEQ_TX2RX,
+ B43_RFSEQ_RESET2RX,
+ B43_RFSEQ_UPDATE_GAINH,
+ B43_RFSEQ_UPDATE_GAINL,
+ B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+ enum b43_nphy_rf_sequence seq)
+{
+ static const u16 trigger[] = {
+ [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX,
+ [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX,
+ [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX,
+ [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH,
+ [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL,
+ [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU,
+ };
+ int i;
+
+ B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
+
+ b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+ B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
+ b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
+ for (i = 0; i < 200; i++) {
+ if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
+ goto ok;
+ msleep(1);
+ }
+ b43err(dev->wl, "RF sequence status timeout\n");
+ok:
+ b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+ ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+}
+
+static void b43_nphy_bphy_init(struct b43_wldev *dev)
+{
+ unsigned int i;
+ u16 val;
+
+ val = 0x1E1F;
+ for (i = 0; i < 14; i++) {
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+ val -= 0x202;
+ }
+ val = 0x3E3F;
+ for (i = 0; i < 16; i++) {
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
+ val -= 0x202;
+ }
+ b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/* RSSI Calibration */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+ //TODO
+}
+
int b43_phy_initn(struct b43_wldev *dev)
{
- b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ //TODO: Spectral management
+ b43_nphy_tables_init(dev);
+
+ /* Clear all overrides */
+ b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+ b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+ b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+ ~(B43_NPHY_RFSEQMODE_CAOVER |
+ B43_NPHY_RFSEQMODE_TROVER));
+ b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
+
+ tmp = (phy->rev < 2) ? 64 : 59;
+ b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+ ~B43_NPHY_BPHY_CTL3_SCALE,
+ tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+
+ b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
+ b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
+
+ b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
+ b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
+ b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
+ b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+ //TODO MIMO-Config
+ //TODO Update TX/RX chain
+
+ if (phy->rev < 2) {
+ b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
+ b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
+ }
+ b43_nphy_workarounds(dev);
+ b43_nphy_reset_cca(dev);
+
+ ssb_write32(dev->dev, SSB_TMSLOW,
+ ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+ b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+ b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
+ //TODO read core1/2 clip1 thres regs
+
+ if (1 /* FIXME Band is 2.4GHz */)
+ b43_nphy_bphy_init(dev);
+ //TODO disable TX power control
+ //TODO Fix the TX power settings
+ //TODO Init periodic calibration with reason 3
+ b43_nphy_rssi_cal(dev, 2);
+ b43_nphy_rssi_cal(dev, 0);
+ b43_nphy_rssi_cal(dev, 1);
+ //TODO get TX gain
+ //TODO init superswitch
+ //TODO calibrate LO
+ //TODO idle TSSI TX pctl
+ //TODO TX power control power setup
+ //TODO table writes
+ //TODO TX power control coefficients
+ //TODO enable TX power control
+ //TODO control antenna selection
+ //TODO init radar detection
+ //TODO reset channel if changed
+
+ b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
return 0;
}
diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h
index 896b468..5d95118 100644
--- a/drivers/net/wireless/b43/nphy.h
+++ b/drivers/net/wireless/b43/nphy.h
@@ -25,8 +25,11 @@
#define B43_NPHY_C1_CCK_BCLIPBKOFF B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
#define B43_NPHY_C1_CGAINI B43_PHY_N(0x01C) /* Core 1 compute gain info */
#define B43_NPHY_C1_CGAINI_GAINBKOFF 0x001F /* Gain backoff */
+#define B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT 0
#define B43_NPHY_C1_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */
+#define B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT 5
#define B43_NPHY_C1_CGAINI_GAINSTEP 0x1C00 /* Gain step */
+#define B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT 10
#define B43_NPHY_C1_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */
#define B43_NPHY_C1_CCK_CGAINI B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
#define B43_NPHY_C1_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */
@@ -69,29 +72,32 @@
#define B43_NPHY_C1_CLIP1THRES B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
#define B43_NPHY_C1_CLIP2THRES B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
-#define B43_NPHY_C2_DESPWR B43_PHY_N(0x018 + 22) /* Core 2 desired power */
-#define B43_NPHY_C2_CCK_DESPWR B43_PHY_N(0x019 + 22) /* Core 2 CCK desired power */
-#define B43_NPHY_C2_BCLIPBKOFF B43_PHY_N(0x01A + 22) /* Core 2 barely clip backoff */
-#define B43_NPHY_C2_CCK_BCLIPBKOFF B43_PHY_N(0x01B + 22) /* Core 2 CCK barely clip backoff */
-#define B43_NPHY_C2_CGAINI B43_PHY_N(0x01C + 22) /* Core 2 compute gain info */
+#define B43_NPHY_C2_DESPWR B43_PHY_N(0x02E) /* Core 2 desired power */
+#define B43_NPHY_C2_CCK_DESPWR B43_PHY_N(0x02F) /* Core 2 CCK desired power */
+#define B43_NPHY_C2_BCLIPBKOFF B43_PHY_N(0x030) /* Core 2 barely clip backoff */
+#define B43_NPHY_C2_CCK_BCLIPBKOFF B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
+#define B43_NPHY_C2_CGAINI B43_PHY_N(0x032) /* Core 2 compute gain info */
#define B43_NPHY_C2_CGAINI_GAINBKOFF 0x001F /* Gain backoff */
+#define B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT 0
#define B43_NPHY_C2_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */
+#define B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT 5
#define B43_NPHY_C2_CGAINI_GAINSTEP 0x1C00 /* Gain step */
+#define B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT 10
#define B43_NPHY_C2_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */
-#define B43_NPHY_C2_CCK_CGAINI B43_PHY_N(0x01D + 22) /* Core 2 CCK compute gain info */
+#define B43_NPHY_C2_CCK_CGAINI B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
#define B43_NPHY_C2_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */
#define B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */
-#define B43_NPHY_C2_MINMAX_GAIN B43_PHY_N(0x01E + 22) /* Core 2 min/max gain */
+#define B43_NPHY_C2_MINMAX_GAIN B43_PHY_N(0x034) /* Core 2 min/max gain */
#define B43_NPHY_C2_MINGAIN 0x00FF /* Minimum gain */
#define B43_NPHY_C2_MINGAIN_SHIFT 0
#define B43_NPHY_C2_MAXGAIN 0xFF00 /* Maximum gain */
#define B43_NPHY_C2_MAXGAIN_SHIFT 8
-#define B43_NPHY_C2_CCK_MINMAX_GAIN B43_PHY_N(0x01F + 22) /* Core 2 CCK min/max gain */
+#define B43_NPHY_C2_CCK_MINMAX_GAIN B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
#define B43_NPHY_C2_CCK_MINGAIN 0x00FF /* Minimum gain */
#define B43_NPHY_C2_CCK_MINGAIN_SHIFT 0
#define B43_NPHY_C2_CCK_MAXGAIN 0xFF00 /* Maximum gain */
#define B43_NPHY_C2_CCK_MAXGAIN_SHIFT 8
-#define B43_NPHY_C2_INITGAIN B43_PHY_N(0x020 + 22) /* Core 2 initial gain code */
+#define B43_NPHY_C2_INITGAIN B43_PHY_N(0x036) /* Core 2 initial gain code */
#define B43_NPHY_C2_INITGAIN_EXTLNA 0x0001 /* External LNA index */
#define B43_NPHY_C2_INITGAIN_LNA 0x0006 /* LNA index */
#define B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT 1
@@ -101,23 +107,23 @@
#define B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT 7
#define B43_NPHY_C2_INITGAIN_TRRX 0x1000 /* TR RX index */
#define B43_NPHY_C2_INITGAIN_TRTX 0x2000 /* TR TX index */
-#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x021 + 22) /* Core 2 clip1 high gain code */
-#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x022 + 22) /* Core 2 clip1 medium gain code */
-#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x023 + 22) /* Core 2 clip1 low gain code */
-#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x024 + 22) /* Core 2 clip2 gain code */
-#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x025 + 22) /* Core 2 filter gain */
-#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x026 + 22) /* Core 2 LPF Q HP F bandwidth */
-#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x027 + 22) /* Core 2 clip wideband threshold */
+#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
+#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
+#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
+#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
+#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x03B) /* Core 2 filter gain */
+#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
+#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
#define B43_NPHY_C2_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */
#define B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT 0
#define B43_NPHY_C2_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */
#define B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT 6
-#define B43_NPHY_C2_W1THRES B43_PHY_N(0x028 + 22) /* Core 2 W1 threshold */
-#define B43_NPHY_C2_EDTHRES B43_PHY_N(0x029 + 22) /* Core 2 ED threshold */
-#define B43_NPHY_C2_SMSIGTHRES B43_PHY_N(0x02A + 22) /* Core 2 small sig threshold */
-#define B43_NPHY_C2_NBCLIPTHRES B43_PHY_N(0x02B + 22) /* Core 2 NB clip threshold */
-#define B43_NPHY_C2_CLIP1THRES B43_PHY_N(0x02C + 22) /* Core 2 clip1 threshold */
-#define B43_NPHY_C2_CLIP2THRES B43_PHY_N(0x02D + 22) /* Core 2 clip2 threshold */
+#define B43_NPHY_C2_W1THRES B43_PHY_N(0x03E) /* Core 2 W1 threshold */
+#define B43_NPHY_C2_EDTHRES B43_PHY_N(0x03F) /* Core 2 ED threshold */
+#define B43_NPHY_C2_SMSIGTHRES B43_PHY_N(0x040) /* Core 2 small sig threshold */
+#define B43_NPHY_C2_NBCLIPTHRES B43_PHY_N(0x041) /* Core 2 NB clip threshold */
+#define B43_NPHY_C2_CLIP1THRES B43_PHY_N(0x042) /* Core 2 clip1 threshold */
+#define B43_NPHY_C2_CLIP2THRES B43_PHY_N(0x043) /* Core 2 clip2 threshold */
#define B43_NPHY_CRS_THRES1 B43_PHY_N(0x044) /* CRS threshold 1 */
#define B43_NPHY_CRS_THRES2 B43_PHY_N(0x045) /* CRS threshold 2 */
@@ -225,7 +231,7 @@
#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */
#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */
-#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scran signal control */
+#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */
#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */
#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0
#define B43_NPHY_SCRAM_SIGCTL_SCM 0x0080 /* Scram control mode */
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 8352a4e..93419ad 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -415,7 +415,6 @@ struct b43legacy_phy {
u8 calibrated:1;
u8 radio_rev; /* Radio revision */
- bool locked; /* Only used in b43legacy_phy_{un}lock() */
bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
/* ACI (adjacent channel interference) flags. */
@@ -458,11 +457,6 @@ struct b43legacy_phy {
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
- /* PHY lock for core.rev < 3
- * This lock is only used by b43legacy_phy_{un}lock()
- */
- spinlock_t lock;
-
/* Desired TX power level (in dBm). This is set by the user and
* adjusted in b43legacy_phy_xmitpower(). */
u8 power_level;
@@ -486,9 +480,6 @@ struct b43legacy_phy {
u16 txpwr_offset;
};
-#ifdef CONFIG_B43LEGACY_DEBUG
- bool manual_txpower_control; /* Manual TX-power control enabled? */
-#endif
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
@@ -516,6 +507,13 @@ struct b43legacy_phy {
/* PHY TX errors counter. */
atomic_t txerr_cnt;
+
+#if B43legacy_DEBUG
+ /* Manual TX-power control enabled? */
+ bool manual_txpower_control;
+ /* PHY registers locked by b43legacy_phy_lock()? */
+ bool phy_locked;
+#endif /* B43legacy_DEBUG */
};
/* Data structures for DMA transmission, per 80211 core. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 2d5735d..4ed4243 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2847,8 +2847,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
- /* Flags */
- phy->locked = 0;
/* Assume the radio is enabled. If it's not enabled, the state will
* immediately get fixed on the first periodic work run. */
dev->radio_hw_enable = 1;
@@ -2881,7 +2879,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
phy->lofcal = 0xFFFF;
phy->initval = 0xFFFF;
- spin_lock_init(&phy->lock);
phy->interfmode = B43legacy_INTERFMODE_NONE;
phy->channel = 0xFF;
}
@@ -3013,7 +3010,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
/* Flags */
phy->calibrated = 0;
- phy->locked = 0;
if (phy->_lo_pairs)
memset(phy->_lo_pairs, 0,
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 57c668f..c16febb 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -91,40 +91,36 @@ void b43legacy_voluntary_preempt(void)
#endif /* CONFIG_PREEMPT */
}
-void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev)
+/* Lock the PHY registers against concurrent access from the microcode.
+ * This lock is nonrecursive. */
+void b43legacy_phy_lock(struct b43legacy_wldev *dev)
{
- struct b43legacy_phy *phy = &dev->phy;
+#if B43legacy_DEBUG
+ B43legacy_WARN_ON(dev->phy.phy_locked);
+ dev->phy.phy_locked = 1;
+#endif
- B43legacy_WARN_ON(!irqs_disabled());
- if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) {
- phy->locked = 0;
- return;
- }
if (dev->dev->id.revision < 3) {
b43legacy_mac_suspend(dev);
- spin_lock(&phy->lock);
} else {
if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
b43legacy_power_saving_ctl_bits(dev, -1, 1);
}
- phy->locked = 1;
}
-void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev)
+void b43legacy_phy_unlock(struct b43legacy_wldev *dev)
{
- struct b43legacy_phy *phy = &dev->phy;
+#if B43legacy_DEBUG
+ B43legacy_WARN_ON(!dev->phy.phy_locked);
+ dev->phy.phy_locked = 0;
+#endif
- B43legacy_WARN_ON(!irqs_disabled());
if (dev->dev->id.revision < 3) {
- if (phy->locked) {
- spin_unlock(&phy->lock);
- b43legacy_mac_enable(dev);
- }
+ b43legacy_mac_enable(dev);
} else {
if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
b43legacy_power_saving_ctl_bits(dev, -1, -1);
}
- phy->locked = 0;
}
u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
@@ -1789,7 +1785,6 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
s16 baseband_att_delta;
s16 radio_attenuation;
s16 baseband_attenuation;
- unsigned long phylock_flags;
if (phy->savedpctlreg == 0xFFFF)
return;
@@ -1944,13 +1939,13 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
phy->bbatt = baseband_attenuation;
/* Adjust the hardware */
- b43legacy_phy_lock(dev, phylock_flags);
+ b43legacy_phy_lock(dev);
b43legacy_radio_lock(dev);
b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
radio_attenuation, txpower);
b43legacy_phy_lo_mark_current_used(dev);
b43legacy_radio_unlock(dev);
- b43legacy_phy_unlock(dev, phylock_flags);
+ b43legacy_phy_unlock(dev);
}
static inline
diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
index efa4c5c..ecbe409 100644
--- a/drivers/net/wireless/b43legacy/phy.h
+++ b/drivers/net/wireless/b43legacy/phy.h
@@ -171,18 +171,8 @@ void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
struct b43legacy_wldev;
-void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev);
-#define b43legacy_phy_lock(bcm, flags) \
- do { \
- local_irq_save(flags); \
- b43legacy_raw_phy_lock(bcm); \
- } while (0)
-void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev);
-#define b43legacy_phy_unlock(bcm, flags) \
- do { \
- b43legacy_raw_phy_unlock(bcm); \
- local_irq_restore(flags); \
- } while (0)
+void b43legacy_phy_lock(struct b43legacy_wldev *dev);
+void b43legacy_phy_unlock(struct b43legacy_wldev *dev);
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
index 1a72eb0..318a270 100644
--- a/drivers/net/wireless/b43legacy/radio.c
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -92,6 +92,7 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev)
u32 status;
status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ B43legacy_WARN_ON(status & B43legacy_SBF_RADIOREG_LOCK);
status |= B43legacy_SBF_RADIOREG_LOCK;
b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
mmiowb();
@@ -104,6 +105,7 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ B43legacy_WARN_ON(!(status & B43legacy_SBF_RADIOREG_LOCK));
status &= ~B43legacy_SBF_RADIOREG_LOCK;
b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
mmiowb();
@@ -284,12 +286,11 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
unsigned int j;
unsigned int start;
unsigned int end;
- unsigned long phylock_flags;
if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
return 0;
- b43legacy_phy_lock(dev, phylock_flags);
+ b43legacy_phy_lock(dev);
b43legacy_radio_lock(dev);
b43legacy_phy_write(dev, 0x0802,
b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
@@ -323,7 +324,7 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
ret[j] = 1;
}
b43legacy_radio_unlock(dev);
- b43legacy_phy_unlock(dev, phylock_flags);
+ b43legacy_phy_unlock(dev);
return ret[channel - 1];
}
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4d5a4c9..5de6d91 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -237,8 +237,8 @@ struct ieee80211_bar {
__le16 duration;
__u8 ra[6];
__u8 ta[6];
- __u16 control;
- __u16 start_seq_num;
+ __le16 control;
+ __le16 start_seq_num;
} __attribute__((packed));
/**
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index e7da1cd..2019b4f 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -1154,8 +1154,8 @@ end_no_lock:
sta_info_put(sta);
}
-void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
- u16 initiator, u16 reason_code)
+static void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+ u16 initiator, u16 reason_code)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 962286d..554c4ba 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -496,6 +496,8 @@ static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
if (spinfo == NULL)
return NULL;
+ spinfo->last_sample = jiffies;
+
#ifdef CONFIG_MAC80211_DEBUGFS
spin_lock_init(&spinfo->events.lock);
init_waitqueue_head(&spinfo->events.waitqueue);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 465fce0..89e1e30 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -295,7 +295,7 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
}
-u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
+static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
struct sk_buff *skb,
struct ieee80211_rx_status *status)
{
@@ -1664,8 +1664,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
* This is the actual Rx frames handler. as it blongs to Rx path it must
* be called with rcu_read_lock protection.
*/
-void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_rx_status *status, u32 load)
+static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status,
+ u32 load)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
@@ -1730,7 +1732,6 @@ void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb,
ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
rx.sta);
sta_info_put(sta);
- rcu_read_unlock();
return;
}
@@ -1920,8 +1921,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
return 1;
}
-u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
- struct sk_buff *skb)
+static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
+ struct sk_buff *skb)
{
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 455fadc..0245195 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -28,6 +28,7 @@ struct ieee80211_sched_data
struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
};
+static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
/* given a data frame determine the 802.1p/1d tag to use */
static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
@@ -54,12 +55,12 @@ static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
return skb->priority - 256;
/* check there is a valid IP header present */
- offset = ieee80211_get_hdrlen_from_skb(skb) + 8 /* LLC + proto */;
- if (skb->protocol != htons(ETH_P_IP) ||
- skb->len < offset + sizeof(*ip))
+ offset = ieee80211_get_hdrlen_from_skb(skb);
+ if (skb->len < offset + sizeof(llc_ip_hdr) + sizeof(*ip) ||
+ memcmp(skb->data + offset, llc_ip_hdr, sizeof(llc_ip_hdr)))
return 0;
- ip = (struct iphdr *) (skb->data + offset);
+ ip = (struct iphdr *) (skb->data + offset + sizeof(llc_ip_hdr));
dscp = ip->tos & 0xfc;
if (dscp & 0x1c)
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 1e4cf61..2c569b6 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -417,20 +417,6 @@ static const int event_type_size[] = {
IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
};
-/* Size (in bytes) of various events, as packed */
-static const int event_type_pk_size[] = {
- IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
- 0,
- IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
- 0,
- IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
- IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
- IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
- 0,
- IW_EV_POINT_PK_LEN, /* Without variable payload */
- IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
- IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
-};
/************************ COMMON SUBROUTINES ************************/
/*
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply related
* Re: [PATCH 06/26] atl1: update initialization parameters
From: Jay Cliburn @ 2008-01-23 2:13 UTC (permalink / raw)
To: Jeff Garzik; +Cc: csnook, linux-kernel, atl1-devel, netdev
In-Reply-To: <4795BDBB.10904@garzik.org>
On Tue, 22 Jan 2008 04:56:11 -0500
Jeff Garzik <jeff@garzik.org> wrote:
> jacliburn@bellsouth.net wrote:
> > From: Jay Cliburn <jacliburn@bellsouth.net>
> >
> > Update initialization parameters to match the current vendor driver
> > version 1.2.40.2.
[...]
> ACK without any better knowledge... but is any addition insight
> available at all?
No, sorry Jeff. I simply took the vendor's current driver and matched
his initialization settings. I can only assume he discovered these
values through lab testing.
For this and the other "conform to vendor driver" patches in this set, I
thought it important to have the in-tree driver match the vendor driver
as closely as possible. The primary motivations are (1) my belief that
he's in a better position to test the NIC, and (2) to be able to go to
him for assistance occasionally and not be rejected because of
significant differences between his and our drivers.
Jay
^ permalink raw reply
* Re: [PATCH 06/26] atl1: update initialization parameters
From: Jeff Garzik @ 2008-01-23 2:19 UTC (permalink / raw)
To: Jay Cliburn; +Cc: csnook, linux-kernel, atl1-devel, netdev
In-Reply-To: <20080122201346.6bb36ca2@osprey.hogchain.net>
Jay Cliburn wrote:
> On Tue, 22 Jan 2008 04:56:11 -0500
> Jeff Garzik <jeff@garzik.org> wrote:
>
>> jacliburn@bellsouth.net wrote:
>>> From: Jay Cliburn <jacliburn@bellsouth.net>
>>>
>>> Update initialization parameters to match the current vendor driver
>>> version 1.2.40.2.
>
> [...]
>
>> ACK without any better knowledge... but is any addition insight
>> available at all?
>
> No, sorry Jeff. I simply took the vendor's current driver and matched
> his initialization settings. I can only assume he discovered these
> values through lab testing.
>
> For this and the other "conform to vendor driver" patches in this set, I
> thought it important to have the in-tree driver match the vendor driver
> as closely as possible. The primary motivations are (1) my belief that
> he's in a better position to test the NIC, and (2) to be able to go to
> him for assistance occasionally and not be rejected because of
> significant differences between his and our drivers.
Since these changes are not simply moving code around, we really do need
full explanations for them, and to understand their need.
Blindly copying code from an exterior driver is pointless, and no way at
all to run an engineering process.
If the driver is not going to get the review and attention necessary,
bug fixes and feedback attended-to, then there's not much point in
having this driver in the kernel at all.
You will only lead yourself to frustration, if you set up a system where
changes only flow one way. That's not how Linux development is done at all.
Jeff
^ permalink raw reply
* Re: [PATCH] [IrDA] LMP discovery timer not started by default
From: David Miller @ 2008-01-23 2:28 UTC (permalink / raw)
To: samuel-jcdQHdrhKHMdnm+yROfE0A
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, ross-RWuK6r/cQWRpLGFMi4vTTA,
irda-users-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
In-Reply-To: <20080123033422.GA20754-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org>
From: Samuel Ortiz <samuel-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org>
Date: Wed, 23 Jan 2008 04:34:22 +0100
> By default, LMP sets up a 3 seconds timer for discovery.
> We don't need it until discovery is set to 1.
>
> This patch is against your latest net-2.6.25 tree.
>
> From: Ross Burton <ross-RWuK6r/cQWRpLGFMi4vTTA@public.gmane.org>
> Signed-off-by: Ross Burton <ross-RWuK6r/cQWRpLGFMi4vTTA@public.gmane.org>
> Signed-off-by: Samuel Ortiz <samuel-jcdQHdrhKHMdnm+yROfE0A@public.gmane.org>
Applied, thanks Sam.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
^ permalink raw reply
* Re: [PATCH] [AF_X25]: constify function pointer tables
From: David Miller @ 2008-01-23 2:30 UTC (permalink / raw)
To: jengelh; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0801222051460.5722@fbirervta.pbzchgretzou.qr>
From: Jan Engelhardt <jengelh@computergmbh.de>
Date: Tue, 22 Jan 2008 20:52:04 +0100 (CET)
> Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
Applied.
^ permalink raw reply
* Re: [PATCH 06/26] atl1: update initialization parameters
From: Chris Snook @ 2008-01-23 2:30 UTC (permalink / raw)
To: Jay Cliburn; +Cc: Jeff Garzik, linux-kernel, atl1-devel, netdev
In-Reply-To: <20080122201346.6bb36ca2@osprey.hogchain.net>
Jay Cliburn wrote:
> On Tue, 22 Jan 2008 04:56:11 -0500
> Jeff Garzik <jeff@garzik.org> wrote:
>
>> jacliburn@bellsouth.net wrote:
>>> From: Jay Cliburn <jacliburn@bellsouth.net>
>>>
>>> Update initialization parameters to match the current vendor driver
>>> version 1.2.40.2.
>
> [...]
>
>> ACK without any better knowledge... but is any addition insight
>> available at all?
>
> No, sorry Jeff. I simply took the vendor's current driver and matched
> his initialization settings. I can only assume he discovered these
> values through lab testing.
>
> For this and the other "conform to vendor driver" patches in this set, I
> thought it important to have the in-tree driver match the vendor driver
> as closely as possible. The primary motivations are (1) my belief that
> he's in a better position to test the NIC, and (2) to be able to go to
> him for assistance occasionally and not be rejected because of
> significant differences between his and our drivers.
I don't think we should be doing this without justification. From all the atl1
and atl2 code I've looked at, I've gotten the impression that their driver
development processes are extremely ad-hoc. There is code in the Atheros
version of atl2 that cannot *possibly* apply to that hardware and was just
copied and pasted from atl1, just as much of atl1 was copied and pasted from
e1000. The fact that various versions have different magic numbers may simply
mean they copied and pasted from different irrelevant and incorrect sources.
Our contacts at Atheros seem to be very good electrical engineers, so when they
tell us that a certain setting should be changed to match particular properties
of the hardware, I trust them. They are not, however, experienced and
disciplined kernel developers, so absent such justification I think we should
stick with what we have, which has been improved and reviewed by people who
*are* experienced and disciplined kernel developers.
We have at least as much to teach Atheros about writing kernel code as they have
to teach us about their hardware.
-- Chris
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox