From 12aa343add3eced38a44bdb612b35fdf634d918c Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Tue, 19 Feb 2008 14:17:04 -0800 Subject: [PATCH 01/37] [NET]: Messed multicast lists after dev_mc_sync/unsync Commit a0a400d79e3dd7843e7e81baa3ef2957bdc292d0 ("[NET]: dev_mcast: add multicast list synchronization helpers") from you introduced a new field "da_synced" to struct dev_addr_list that is not properly initialized to 0. So when any of the current users (8021q, macvlan, mac80211) calls dev_mc_sync/unsync they mess the address list for both devices. The attached patch fixed it for me and avoid future problems. Signed-off-by: Jorge Boncompte [DTI2] Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 6cfc1238c4a6..95161054c4d1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2900,7 +2900,7 @@ int __dev_addr_add(struct dev_addr_list **list, int *count, } } - da = kmalloc(sizeof(*da), GFP_ATOMIC); + da = kzalloc(sizeof(*da), GFP_ATOMIC); if (da == NULL) return -ENOMEM; memcpy(da->da_addr, addr, alen); From 76e87306c2de2a581ec939cf9c97cd18d053f90e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 19 Feb 2008 16:12:08 -0800 Subject: [PATCH 02/37] [RTNL]: Add missing link netlink attribute policy definitions IFLA_LINK is no longer a write-only attribute on the kernel side and must thus be validated. Same goes for the newly introduced IFLA_LINKINFO. Fixes undefined behaviour if either of the attributes are not well formed. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 61ac8d06292c..e170179cc66f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -689,10 +689,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, [IFLA_MTU] = { .type = NLA_U32 }, + [IFLA_LINK] = { .type = NLA_U32 }, [IFLA_TXQLEN] = { .type = NLA_U32 }, [IFLA_WEIGHT] = { .type = NLA_U32 }, [IFLA_OPERSTATE] = { .type = NLA_U8 }, [IFLA_LINKMODE] = { .type = NLA_U8 }, + [IFLA_LINKINFO] = { .type = NLA_NESTED }, [IFLA_NET_NS_PID] = { .type = NLA_U32 }, }; From 15e29b8b0542f28fc0feed2d60e0377b39a45c4f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 19 Feb 2008 16:25:30 -0800 Subject: [PATCH 03/37] net/9p/trans_virtio.c: kmalloc() enough memory The Coverity checker spotted that less memory than required was allocated. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/9p/trans_virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 9e3d81cb9f08..de7a9f532edc 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -110,7 +110,7 @@ static struct p9_req_t *p9_lookup_tag(struct virtio_chan *c, u16 tag) } for (count = old_max; count < c->max_tag; count++) { c->reqs[count].status = REQ_STATUS_IDLE; - c->reqs[count].wq = kmalloc(sizeof(wait_queue_t), + c->reqs[count].wq = kmalloc(sizeof(wait_queue_head_t), GFP_ATOMIC); if (!c->reqs[count].wq) { printk(KERN_ERR "Couldn't grow tag array\n"); From 94cb1503c799c0197e7ef5bad606fee5c84b99d8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 19 Feb 2008 16:28:54 -0800 Subject: [PATCH 04/37] ipv4/fib_hash.c: fix NULL dereference Unless I miss a guaranteed relation between between "f" and "new_fa->fa_info" this patch is required for fixing a NULL dereference introduced by commit a6501e080c318f8d4467679d17807f42b3a33cd5 ("[IPV4] FIB_HASH: Reduce memory needs and speedup lookups") and spotted by the Coverity checker. Eric Dumazet says: Hum, you are right, kmem_cache_free() doesnt allow a NULL object, like kfree() does. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/ipv4/fib_hash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 76b9c684cccd..8d58d85dfac6 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -372,7 +372,8 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key) static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) { struct fn_hash *table = (struct fn_hash *) tb->tb_data; - struct fib_node *new_f, *f; + struct fib_node *new_f = NULL; + struct fib_node *f; struct fib_alias *fa, *new_fa; struct fn_zone *fz; struct fib_info *fi; @@ -496,7 +497,6 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) err = -ENOBUFS; - new_f = NULL; if (!f) { new_f = kmem_cache_zalloc(fn_hash_kmem, GFP_KERNEL); if (new_f == NULL) @@ -512,7 +512,7 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) if (new_fa->fa_info != NULL) { new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) - goto out_free_new_f; + goto out; } new_fa->fa_info = fi; new_fa->fa_tos = tos; @@ -540,9 +540,9 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) &cfg->fc_nlinfo, 0); return 0; -out_free_new_f: - kmem_cache_free(fn_hash_kmem, new_f); out: + if (new_f) + kmem_cache_free(fn_hash_kmem, new_f); fib_release_info(fi); return err; } From e2b58a67b91dec07dfb40ca2056c64011ce8489d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 19 Feb 2008 17:17:52 -0800 Subject: [PATCH 05/37] [NETFILTER]: {ip,ip6,nfnetlink}_queue: fix SKB_LINEAR_ASSERT when mangling packet data As reported by Tomas Simonaitis , inserting new data in skbs queued over {ip,ip6,nfnetlink}_queue triggers a SKB_LINEAR_ASSERT in skb_put(). Going back through the git history, it seems this bug is present since at least 2.6.12-rc2, probably even since the removal of skb_linearize() for netfilter. Linearize non-linear skbs through skb_copy_expand() when enlarging them. Tested by Thomas, fixes bugzilla #9933. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_queue.c | 12 +++++++----- net/ipv6/netfilter/ip6_queue.c | 10 ++++++---- net/netfilter/nfnetlink_queue.c | 10 ++++++---- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 6bda1102851b..fe05da41d6ba 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -283,8 +283,8 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct nf_queue_entry *e) { int diff; - int err; struct iphdr *user_iph = (struct iphdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -296,14 +296,16 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct nf_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "ip_queue: error " - "in mangle, dropping packet: %d\n", -err); - return err; + "in mangle, dropping packet\n"); + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e869916b05f1..cc2f9afcf808 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -285,8 +285,8 @@ static int ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) { int diff; - int err; struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -298,14 +298,16 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "ip6_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index a48b20fe9cd6..0043d3a9f87e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -443,8 +443,8 @@ err_out: static int nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) { + struct sk_buff *nskb; int diff; - int err; diff = data_len - e->skb->len; if (diff < 0) { @@ -454,14 +454,16 @@ nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) if (data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "nf_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } From f449b3b54d2263d65a11429050765c325c9809f4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 19 Feb 2008 17:18:20 -0800 Subject: [PATCH 06/37] [NETFILTER]: xt_u32: drop the actually unused variable from u32_match_it The int ret variable is used only to trigger the BUG_ON() after the skb_copy_bits() call, so check the call failure directly and drop the variable. Signed-off-by: Pavel Emelyanov Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_u32.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c index 9b8ed390a8e0..627e0f336d54 100644 --- a/net/netfilter/xt_u32.c +++ b/net/netfilter/xt_u32.c @@ -26,7 +26,6 @@ static bool u32_match_it(const struct xt_u32 *data, u_int32_t pos; u_int32_t val; u_int32_t at; - int ret; /* * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17" @@ -40,8 +39,8 @@ static bool u32_match_it(const struct xt_u32 *data, if (skb->len < 4 || pos > skb->len - 4) return false; - ret = skb_copy_bits(skb, pos, &n, sizeof(n)); - BUG_ON(ret < 0); + if (skb_copy_bits(skb, pos, &n, sizeof(n)) < 0) + BUG(); val = ntohl(n); nnums = ct->nnums; @@ -67,9 +66,9 @@ static bool u32_match_it(const struct xt_u32 *data, pos > skb->len - at - 4) return false; - ret = skb_copy_bits(skb, at + pos, &n, - sizeof(n)); - BUG_ON(ret < 0); + if (skb_copy_bits(skb, at + pos, &n, + sizeof(n)) < 0) + BUG(); val = ntohl(n); break; } From eb1197bc0e20d3ceb450883dbd181460252f0306 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Tue, 19 Feb 2008 17:18:47 -0800 Subject: [PATCH 07/37] [NETFILTER]: Fix incorrect use of skb_make_writable http://bugzilla.kernel.org/show_bug.cgi?id=9920 The function skb_make_writable returns true or false. Signed-off-by: Joonwoo Park Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/bridge/netfilter/ebt_dnat.c | 2 +- net/bridge/netfilter/ebt_redirect.c | 2 +- net/bridge/netfilter/ebt_snat.c | 2 +- net/ipv4/netfilter/arpt_mangle.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c index e700cbf634c2..1ec671d93dda 100644 --- a/net/bridge/netfilter/ebt_dnat.c +++ b/net/bridge/netfilter/ebt_dnat.c @@ -20,7 +20,7 @@ static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr, { const struct ebt_nat_info *info = data; - if (skb_make_writable(skb, 0)) + if (!skb_make_writable(skb, 0)) return NF_DROP; memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN); diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index bfdf2fb60b1f..bfb9f74e2116 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -21,7 +21,7 @@ static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr, { const struct ebt_redirect_info *info = data; - if (skb_make_writable(skb, 0)) + if (!skb_make_writable(skb, 0)) return NF_DROP; if (hooknr != NF_BR_BROUTING) diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index e252dabbb143..204f9965fb9e 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -22,7 +22,7 @@ static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr, { const struct ebt_nat_info *info = data; - if (skb_make_writable(skb, 0)) + if (!skb_make_writable(skb, 0)) return NF_DROP; memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN); diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index 45fa4e20094a..3f4222b0a803 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -19,7 +19,7 @@ target(struct sk_buff *skb, unsigned char *arpptr; int pln, hln; - if (skb_make_writable(skb, skb->len)) + if (!skb_make_writable(skb, skb->len)) return NF_DROP; arp = arp_hdr(skb); From 651acc9893f2cd036e9485ce782d0c4cffbc27f5 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Tue, 19 Feb 2008 17:19:14 -0800 Subject: [PATCH 08/37] [NETFILTER]: Make sure xt_policy.h is unifdef'ed. Since the header file xt_policy.h tests __KERNEL__, it should be unifdef'ed before exporting to userspace. Signed-off-by: Robert P. J. Day Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/Kbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 91fef0cae42f..3aff513d12c8 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -30,7 +30,6 @@ header-y += xt_mark.h header-y += xt_multiport.h header-y += xt_owner.h header-y += xt_pkttype.h -header-y += xt_policy.h header-y += xt_rateest.h header-y += xt_realm.h header-y += xt_sctp.h @@ -47,3 +46,4 @@ unifdef-y += nfnetlink.h unifdef-y += nfnetlink_compat.h unifdef-y += x_tables.h unifdef-y += xt_physdev.h +unifdef-y += xt_policy.h From 7d9904c2604ce091c97c225b5e2f92f3e7cc2e3a Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 19 Feb 2008 17:19:44 -0800 Subject: [PATCH 09/37] [NETFILTER]: xt_hashlimit: remove unneeded struct member By allocating ->hinfo, we already have the needed indirection to cope with the per-cpu xtables struct match_entry. [Patrick: do this now before the revision 1 struct is used by userspace] Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/xt_hashlimit.h | 1 - net/netfilter/xt_hashlimit.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h index 58b818ee41ca..51b18d83b477 100644 --- a/include/linux/netfilter/xt_hashlimit.h +++ b/include/linux/netfilter/xt_hashlimit.h @@ -61,7 +61,6 @@ struct xt_hashlimit_mtinfo1 { /* Used internally by the kernel */ struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); - struct xt_hashlimit_mtinfo1 *master __attribute__((aligned(8))); }; #endif /*_XT_HASHLIMIT_H*/ diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 744c7f2ab0b1..5418ce59ac3a 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -774,9 +774,6 @@ hashlimit_mt_check(const char *tablename, const void *inf, return false; } mutex_unlock(&hlimit_mutex); - - /* Ugly hack: For SMP, we only want to use one set */ - info->master = info; return true; } From 27ecb1ff0afa2260e6856c05efd6fedcd0cc76b9 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 19 Feb 2008 17:20:06 -0800 Subject: [PATCH 10/37] [NETFILTER]: xt_iprange: fix subtraction-based comparison The host address parts need to be converted to host-endian first before arithmetic makes any sense on them. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_iprange.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c index 4f984dc60319..500528d60cd7 100644 --- a/net/netfilter/xt_iprange.c +++ b/net/netfilter/xt_iprange.c @@ -102,7 +102,7 @@ iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b) int r; for (i = 0; i < 4; ++i) { - r = (__force u32)a->s6_addr32[i] - (__force u32)b->s6_addr32[i]; + r = ntohl(a->s6_addr32[i]) - ntohl(b->s6_addr32[i]); if (r != 0) return r; } From 7b33ed22194d8f0dbcf682f5cdf5b9c2ef551e7c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 19 Feb 2008 17:20:33 -0800 Subject: [PATCH 11/37] [NETFILTER]: Use __u32 in struct nf_inet_addr As reported by David Woodhouse , using u_int32_t in struct nf_inet_addr breaks the busybox build. Fix by using __u32. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index d74e79bacd2d..b74b615492e8 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -51,7 +51,7 @@ enum nf_inet_hooks { }; union nf_inet_addr { - u_int32_t all[4]; + __u32 all[4]; __be32 ip; __be32 ip6[4]; struct in_addr in; From fa907895b7b776208a1406efe5ba7ffe0f49f507 Mon Sep 17 00:00:00 2001 From: Matheos Worku Date: Wed, 20 Feb 2008 00:18:09 -0800 Subject: [PATCH 12/37] [NIU]: More BMAC alt MAC address fixes. From: Matheos Worku 1) niu_enable_alt_mac() needs to be adjusted so that the mask is computed properly for the BMAC case. 2) BMAC has 6 alt MAC addresses available, not 7. Signed-off-by: David S. Miller --- drivers/net/niu.c | 9 +++++---- drivers/net/niu.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/niu.c b/drivers/net/niu.c index e98ce1e4965b..d11ba61baa4f 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -1616,12 +1616,13 @@ static int niu_enable_alt_mac(struct niu *np, int index, int on) if (index >= niu_num_alt_addr(np)) return -EINVAL; - if (np->flags & NIU_FLAGS_XMAC) + if (np->flags & NIU_FLAGS_XMAC) { reg = XMAC_ADDR_CMPEN; - else + mask = 1 << index; + } else { reg = BMAC_ADDR_CMPEN; - - mask = 1 << index; + mask = 1 << (index + 1); + } val = nr64_mac(reg); if (on) diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 0e8626adc573..59dc05fcd371 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -499,7 +499,7 @@ #define BMAC_ADDR2 0x00110UL #define BMAC_ADDR2_ADDR2 0x000000000000ffffULL -#define BMAC_NUM_ALT_ADDR 7 +#define BMAC_NUM_ALT_ADDR 6 #define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL) #define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL From c15853f2c1c9baaa27bbc494cd183be96f6d9bb9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 20 Feb 2008 00:21:47 -0800 Subject: [PATCH 13/37] veth: fix dev refcount race When deleting the veth driver, veth_close calls netif_carrier_off for the two extremities of the network device. netif_carrier_off on the peer device will fire an event and hold a reference on the peer device. Just after, the peer is unregistered taking the rtnl_lock while the linkwatch_event is scheduled. If __linkwatch_run_queue does not occurs before the unregistering, unregister_netdevice will wait for the dev refcount to reach zero holding the rtnl_lock and linkwatch_event will wait for the rtnl_lock and hold the dev refcount. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- drivers/net/veth.c | 53 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 3f67a29593bc..e2ad98bee6e7 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -244,18 +244,6 @@ static int veth_open(struct net_device *dev) return 0; } -static int veth_close(struct net_device *dev) -{ - struct veth_priv *priv; - - if (netif_carrier_ok(dev)) { - priv = netdev_priv(dev); - netif_carrier_off(dev); - netif_carrier_off(priv->peer); - } - return 0; -} - static int veth_dev_init(struct net_device *dev) { struct veth_net_stats *stats; @@ -286,13 +274,50 @@ static void veth_setup(struct net_device *dev) dev->hard_start_xmit = veth_xmit; dev->get_stats = veth_get_stats; dev->open = veth_open; - dev->stop = veth_close; dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->init = veth_dev_init; dev->destructor = veth_dev_free; } +static void veth_change_state(struct net_device *dev) +{ + struct net_device *peer; + struct veth_priv *priv; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (netif_carrier_ok(peer)) { + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + } else { + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + } +} + +static int veth_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + + if (dev->open != veth_open) + goto out; + + switch (event) { + case NETDEV_CHANGE: + veth_change_state(dev); + break; + } +out: + return NOTIFY_DONE; +} + +static struct notifier_block veth_notifier_block __read_mostly = { + .notifier_call = veth_device_event, +}; + /* * netlink interface */ @@ -454,12 +479,14 @@ static struct rtnl_link_ops veth_link_ops = { static __init int veth_init(void) { + register_netdevice_notifier(&veth_notifier_block); return rtnl_link_register(&veth_link_ops); } static __exit void veth_exit(void) { rtnl_link_unregister(&veth_link_ops); + unregister_netdevice_notifier(&veth_notifier_block); } module_init(veth_init); From 5f31886ff03ef68dc078c585fa3a2af9a011a8fa Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 20 Feb 2008 00:23:01 -0800 Subject: [PATCH 14/37] [SCTP]: Pick up an orphaned sctp_sockets_allocated counter. This counter is currently write-only. Drawing an analogy with the similar tcp counter, I think that this one should be pointed by the sockets_allocated members of sctp_prot and sctpv6_prot. Signed-off-by: Pavel Emelyanov Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d47d5787e2e5..44797ad88a05 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6488,6 +6488,7 @@ struct proto sctp_prot = { .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, .memory_allocated = &sctp_memory_allocated, + .sockets_allocated = &sctp_sockets_allocated, REF_PROTO_INUSE(sctp) }; @@ -6521,6 +6522,7 @@ struct proto sctpv6_prot = { .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, .memory_allocated = &sctp_memory_allocated, + .sockets_allocated = &sctp_sockets_allocated, REF_PROTO_INUSE(sctpv6) }; #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ From da12f7356da1dfb97f1c6c418f828b7ce442fef9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 20 Feb 2008 00:26:16 -0800 Subject: [PATCH 15/37] [NETNS]: Namespace leak in pneigh_lookup. release_net is missed on the error path in pneigh_lookup. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/core/neighbour.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a16cf1ec5e5e..4062b88bfc1b 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -507,6 +507,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, if (tbl->pconstructor && tbl->pconstructor(n)) { if (dev) dev_put(dev); + release_net(net); kfree(n); n = NULL; goto out; From 1a17582e64dcc690a7edcd7dcf6fe89f1aa0ef97 Mon Sep 17 00:00:00 2001 From: Ivo Couckuyt Date: Wed, 20 Feb 2008 14:58:00 -0500 Subject: [PATCH 16/37] p54usb: add USB ID for Phillips CPWUA054 Retarget of an old patch against prism54usb in linux-wireless archive: http://marc.info/?l=linux-wireless&m=117449935810254&w=2 Cc: Ivo Couckuyt Signed-off-by: John W. Linville --- drivers/net/wireless/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c index 60d286eb0b8b..f8695665c0ce 100644 --- a/drivers/net/wireless/p54usb.c +++ b/drivers/net/wireless/p54usb.c @@ -35,6 +35,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ + {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */ {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ From 387e100ac24a6c8f2b6f4ce572098447d2893008 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 20 Feb 2008 15:06:02 -0500 Subject: [PATCH 17/37] p54usb: add USB ID for Linksys WUSB54G ver 2 Based on report from Cavan Carroll : http://bugzilla.kernel.org/show_bug.cgi?id=9863 Cc: Cavan Carroll Signed-off-by: John W. Linville --- drivers/net/wireless/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c index f8695665c0ce..e7d4aee8799e 100644 --- a/drivers/net/wireless/p54usb.c +++ b/drivers/net/wireless/p54usb.c @@ -63,6 +63,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ From 65872e6b434ca463123f7d03b530f143aabc6333 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 15 Feb 2008 21:58:51 +0100 Subject: [PATCH 18/37] WDEV: ath5k, fix lock imbalance Omitted lock causes sparse warning drivers/net/wireless/ath5k/base.c:1682:1: warning: context imbalance in 'ath5k_tasklet_rx' - different lock contexts for basic block Add the lock to the guilty fail path. Signed-off-by: Jiri Slaby Acked-by: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index dfdaec020739..062d004076a2 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1715,6 +1715,7 @@ ath5k_tasklet_rx(unsigned long data) break; else if (unlikely(ret)) { ATH5K_ERR(sc, "error in processing rx descriptor\n"); + spin_unlock(&sc->rxbuflock); return; } From b988763857426020e50a19434c8434a1e08e70eb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 15 Feb 2008 21:58:52 +0100 Subject: [PATCH 19/37] WDEV, ath5k, don't return int from bool function sparse sees int -> bool cast as an error: hw.c:3754:10: warning: cast truncates bits from constant value (ffffffea becomes 0) Fix it by converting the rettype to int and check appropriately. Signed-off-by: Jiri Slaby Cc: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath5k/base.c | 5 ++++- drivers/net/wireless/ath5k/hw.c | 8 ++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index c79066b38d3b..69dea3392612 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -1035,7 +1035,7 @@ struct ath5k_hw { unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, + int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 062d004076a2..81b45b3e0f02 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -668,7 +668,10 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) * return false w/o doing anything. MAC's that do * support it will return true w/o doing anything. */ - if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0)) + ret = ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + if (ret < 0) + goto err; + if (ret > 0) __set_bit(ATH_STAT_MRRETRY, sc->status); /* diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 1ab57aa6e4dc..c2de2d958e8e 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -45,7 +45,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); -static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, +static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *); @@ -3743,7 +3743,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* * Initialize a 4-word multirate tx descriptor on 5212 */ -static bool +static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) @@ -3783,10 +3783,10 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, #undef _XTX_TRIES - return true; + return 1; } - return false; + return 0; } /* From 04f93a87a2db84e7214a4ec56fccd2289e973ce5 Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 15 Feb 2008 16:08:59 -0800 Subject: [PATCH 20/37] ath5k: Fix build warnings on some 64-bit platforms. 'u64' is not necessarily 'unsigned long long' drivers/net/wireless/ath5k/base.c: In function 'ath5k_beacon_update_timers': drivers/net/wireless/ath5k/base.c:2130: warning: format '%llx' expects type 'long long unsigned int', but argument 4 has type 'u64' drivers/net/wireless/ath5k/base.c:2130: warning: format '%llx' expects type 'long long unsigned int', but argument 5 has type 'u64' drivers/net/wireless/ath5k/base.c: In function 'ath5k_intr': drivers/net/wireless/ath5k/base.c:2391: warning: format '%llx' expects type 'long long unsigned int', but argument 6 has type 'u64' Signed-off-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 81b45b3e0f02..bef967ce34a6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2130,8 +2130,9 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) "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); + "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n", + (unsigned long long) bc_tsf, + (unsigned long long) 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" : "", @@ -2389,10 +2390,11 @@ ath5k_intr(int irq, void *dev_id) 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); + "SWBA nexttbtt: %x hw_tu: %x " + "TSF: %llx\n", + sc->nexttbtt, + TSF_TO_TU(tsf), + (unsigned long long) tsf); } else { ath5k_beacon_send(sc); } From 58ff70d4feae29cbb7ace410fa6585ef3afb44b6 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 18 Feb 2008 21:44:39 +0100 Subject: [PATCH 21/37] ssb: Fix serial console on new bcm47xx devices This fixes the baud settings for new devices like the Linksys WRT350n. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/driver_chipcommon.c | 42 ++++++++++++++++++----- include/linux/ssb/ssb_driver_chipcommon.h | 3 ++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 6fbf1c53b6f2..7cc03f2dd5a6 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -376,6 +376,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc, unsigned int irq; u32 baud_base, div; u32 i, n; + unsigned int ccrev = cc->dev->id.revision; plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); irq = ssb_mips_irq(cc->dev); @@ -387,14 +388,39 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc, chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); div = 1; } else { - if (cc->dev->id.revision >= 11) { - /* Fixed ALP clock */ - baud_base = 20000000; - div = 1; + if (ccrev == 20) { + /* BCM5354 uses constant 25MHz clock */ + baud_base = 25000000; + div = 48; /* Set the override bit so we don't divide it */ chipco_write32(cc, SSB_CHIPCO_CORECTL, - SSB_CHIPCO_CORECTL_UARTCLK0); - } else if (cc->dev->id.revision >= 3) { + chipco_read32(cc, SSB_CHIPCO_CORECTL) + | SSB_CHIPCO_CORECTL_UARTCLK0); + } else if ((ccrev >= 11) && (ccrev != 15)) { + /* Fixed ALP clock */ + baud_base = 20000000; + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { + /* FIXME: baud_base is different for devices with a PMU */ + SSB_WARN_ON(1); + } + div = 1; + if (ccrev >= 21) { + /* Turn off UART clock before switching clocksource. */ + chipco_write32(cc, SSB_CHIPCO_CORECTL, + chipco_read32(cc, SSB_CHIPCO_CORECTL) + & ~SSB_CHIPCO_CORECTL_UARTCLKEN); + } + /* Set the override bit so we don't divide it */ + chipco_write32(cc, SSB_CHIPCO_CORECTL, + chipco_read32(cc, SSB_CHIPCO_CORECTL) + | SSB_CHIPCO_CORECTL_UARTCLK0); + if (ccrev >= 21) { + /* Re-enable the UART clock. */ + chipco_write32(cc, SSB_CHIPCO_CORECTL, + chipco_read32(cc, SSB_CHIPCO_CORECTL) + | SSB_CHIPCO_CORECTL_UARTCLKEN); + } + } else if (ccrev >= 3) { /* Internal backplane clock */ baud_base = ssb_clockspeed(bus); div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) @@ -406,7 +432,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc, } /* Clock source depends on strapping if UartClkOverride is unset */ - if ((cc->dev->id.revision > 0) && + if ((ccrev > 0) && !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == SSB_CHIPCO_CAP_UARTCLK_INT) { @@ -428,7 +454,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc, cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; /* Offset changed at after rev 0 */ - if (cc->dev->id.revision == 0) + if (ccrev == 0) uart_regs += (i * 8); else uart_regs += (i * 256); diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 4cb995494662..35717b400cef 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -51,9 +51,12 @@ #define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */ #define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */ #define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ +#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ +#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ #define SSB_CHIPCO_CORECTL 0x0008 #define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ #define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define SSB_CHIPCO_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */ #define SSB_CHIPCO_BIST 0x000C #define SSB_CHIPCO_OTPS 0x0010 /* OTP status */ #define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000 From 42bfad4f71637c4eb4791aa8062063c4a8526522 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 19 Feb 2008 12:41:30 +0100 Subject: [PATCH 22/37] ssb: Fix watchdog access for devices without a chipcommon This fixes the SSB watchdog access for devices without a chipcommon. These devices have the watchdog on the extif. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/Kconfig | 6 ++++++ drivers/ssb/Makefile | 1 + drivers/ssb/driver_extif.c | 6 ++++++ drivers/ssb/embedded.c | 26 +++++++++++++++++++++++ include/linux/ssb/ssb_driver_chipcommon.h | 5 +++++ include/linux/ssb/ssb_driver_extif.h | 9 ++++++++ include/linux/ssb/ssb_embedded.h | 10 +++++++++ 7 files changed, 63 insertions(+) create mode 100644 drivers/ssb/embedded.c create mode 100644 include/linux/ssb/ssb_embedded.h diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index d976660cb7f0..78fd33125e02 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -105,6 +105,12 @@ config SSB_DRIVER_MIPS If unsure, say N +# Assumption: We are on embedded, if we compile the MIPS core. +config SSB_EMBEDDED + bool + depends on SSB_DRIVER_MIPS + default y + config SSB_DRIVER_EXTIF bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)" depends on SSB_DRIVER_MIPS && EXPERIMENTAL diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index 7be397595805..e235144add7c 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -1,5 +1,6 @@ # core ssb-y += main.o scan.o +ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o # host support ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index fe55eb8b038a..b1899f422a54 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -110,6 +110,12 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); } +void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, + u32 ticks) +{ + extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); +} + u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) { return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c new file mode 100644 index 000000000000..751f58ac612c --- /dev/null +++ b/drivers/ssb/embedded.c @@ -0,0 +1,26 @@ +/* + * Sonics Silicon Backplane + * Embedded systems support code + * + * Copyright 2005-2008, Broadcom Corporation + * Copyright 2006-2008, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + + +int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) +{ + if (ssb_chipco_available(&bus->chipco)) { + ssb_chipco_watchdog_timer_set(&bus->chipco, ticks); + return 0; + } + if (ssb_extif_available(&bus->extif)) { + ssb_extif_watchdog_timer_set(&bus->extif, ticks); + return 0; + } + return -ENODEV; +} diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 35717b400cef..89638153cbe1 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -360,6 +360,11 @@ struct ssb_chipcommon { u16 fast_pwrup_delay; }; +static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) +{ + return (cc->dev != NULL); +} + extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); #include diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index a9164357b5ae..0d7c9bfa965d 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -171,6 +171,9 @@ extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif, extern void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns); +extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, + u32 ticks); + u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); @@ -200,5 +203,11 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, { } +static inline +void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, + u32 ticks) +{ +} + #endif /* CONFIG_SSB_DRIVER_EXTIF */ #endif /* LINUX_SSB_EXTIFCORE_H_ */ diff --git a/include/linux/ssb/ssb_embedded.h b/include/linux/ssb/ssb_embedded.h new file mode 100644 index 000000000000..80bd58496450 --- /dev/null +++ b/include/linux/ssb/ssb_embedded.h @@ -0,0 +1,10 @@ +#ifndef LINUX_SSB_EMBEDDED_H_ +#define LINUX_SSB_EMBEDDED_H_ + +#include +#include + + +extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); + +#endif /* LINUX_SSB_EMBEDDED_H_ */ From c2bcbe65fc88d61f9a806367ff6eab76c9eabb3a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 19 Feb 2008 14:53:35 +0100 Subject: [PATCH 23/37] ssb: Fix the GPIO API This fixes the GPIO API to be usable. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/driver_chipcommon.c | 35 +++++++++++++++++++---- drivers/ssb/driver_extif.c | 24 +++++++++++++--- include/linux/ssb/ssb_driver_chipcommon.h | 10 ++++--- include/linux/ssb/ssb_driver_extif.h | 9 +++--- 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7cc03f2dd5a6..7ea0c0faa9ab 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -39,12 +39,14 @@ static inline void chipco_write32(struct ssb_chipcommon *cc, ssb_write32(cc->dev, offset, value); } -static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, - u32 mask, u32 value) +static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, + u32 mask, u32 value) { value &= mask; value |= chipco_read32(cc, offset) & ~mask; chipco_write32(cc, offset, value); + + return value; } void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, @@ -355,16 +357,37 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) { return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; } +EXPORT_SYMBOL(ssb_chipco_gpio_in); -void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) +u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) { - chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); } +EXPORT_SYMBOL(ssb_chipco_gpio_out); -void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) +u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) { - chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); } +EXPORT_SYMBOL(ssb_chipco_gpio_outen); + +u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); +} +EXPORT_SYMBOL(ssb_chipco_gpio_control); + +u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); +} +EXPORT_SYMBOL(ssb_chipco_gpio_intmask); + +u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); +} +EXPORT_SYMBOL(ssb_chipco_gpio_polarity); #ifdef CONFIG_SSB_SERIAL int ssb_chipco_serial_init(struct ssb_chipcommon *cc, diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index b1899f422a54..10c6b287f8bb 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -27,12 +27,14 @@ static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) ssb_write32(extif->dev, offset, value); } -static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset, - u32 mask, u32 value) +static inline u32 extif_write32_masked(struct ssb_extif *extif, u16 offset, + u32 mask, u32 value) { value &= mask; value |= extif_read32(extif, offset) & ~mask; extif_write32(extif, offset, value); + + return value; } #ifdef CONFIG_SSB_SERIAL @@ -120,16 +122,30 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) { return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; } +EXPORT_SYMBOL(ssb_extif_gpio_in); -void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) +u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) { return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), mask, value); } +EXPORT_SYMBOL(ssb_extif_gpio_out); -void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) +u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) { return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), mask, value); } +EXPORT_SYMBOL(ssb_extif_gpio_outen); +u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) +{ + return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); +} +EXPORT_SYMBOL(ssb_extif_gpio_polarity); + +u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) +{ + return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); +} +EXPORT_SYMBOL(ssb_extif_gpio_intmask); diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 89638153cbe1..536851b946f6 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -390,11 +390,13 @@ extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks); +/* Chipcommon GPIO pin access. */ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask); - -void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); - -void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value); +u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value); #ifdef CONFIG_SSB_SERIAL extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 0d7c9bfa965d..91161f0aa22b 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -174,11 +174,12 @@ extern void ssb_extif_timing_init(struct ssb_extif *extif, extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks); +/* Extif GPIO pin access */ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); - -void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); - -void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value); +u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value); #ifdef CONFIG_SSB_SERIAL extern int ssb_extif_serial_init(struct ssb_extif *extif, From 53521d8c90d366191b6c134f88a8ebe83de60614 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 19 Feb 2008 16:22:50 +0100 Subject: [PATCH 24/37] ssb: Make the GPIO API reentrancy safe This fixes the GPIO API to be reentrancy safe. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/driver_chipcommon.c | 6 -- drivers/ssb/driver_extif.c | 5 -- drivers/ssb/embedded.c | 106 +++++++++++++++++++++++++++++++ drivers/ssb/main.c | 3 + include/linux/ssb/ssb.h | 5 ++ include/linux/ssb/ssb_embedded.h | 8 +++ 6 files changed, 122 insertions(+), 11 deletions(-) diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7ea0c0faa9ab..e586321a473a 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -357,37 +357,31 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) { return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; } -EXPORT_SYMBOL(ssb_chipco_gpio_in); u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) { return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); } -EXPORT_SYMBOL(ssb_chipco_gpio_out); u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) { return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); } -EXPORT_SYMBOL(ssb_chipco_gpio_outen); u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) { return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); } -EXPORT_SYMBOL(ssb_chipco_gpio_control); u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) { return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); } -EXPORT_SYMBOL(ssb_chipco_gpio_intmask); u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) { return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); } -EXPORT_SYMBOL(ssb_chipco_gpio_polarity); #ifdef CONFIG_SSB_SERIAL int ssb_chipco_serial_init(struct ssb_chipcommon *cc, diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index 10c6b287f8bb..c3e1d3e6d610 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -122,30 +122,25 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) { return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; } -EXPORT_SYMBOL(ssb_extif_gpio_in); u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) { return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), mask, value); } -EXPORT_SYMBOL(ssb_extif_gpio_out); u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) { return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), mask, value); } -EXPORT_SYMBOL(ssb_extif_gpio_outen); u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) { return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); } -EXPORT_SYMBOL(ssb_extif_gpio_polarity); u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) { return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); } -EXPORT_SYMBOL(ssb_extif_gpio_intmask); diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index 751f58ac612c..d3ade821555c 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -11,6 +11,8 @@ #include #include +#include "ssb_private.h" + int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) { @@ -24,3 +26,107 @@ int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) } return -ENODEV; } + +u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask) +{ + unsigned long flags; + u32 res = 0; + + spin_lock_irqsave(&bus->gpio_lock, flags); + if (ssb_chipco_available(&bus->chipco)) + res = ssb_chipco_gpio_in(&bus->chipco, mask); + else if (ssb_extif_available(&bus->extif)) + res = ssb_extif_gpio_in(&bus->extif, mask); + else + SSB_WARN_ON(1); + spin_unlock_irqrestore(&bus->gpio_lock, flags); + + return res; +} +EXPORT_SYMBOL(ssb_gpio_in); + +u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value) +{ + unsigned long flags; + u32 res = 0; + + spin_lock_irqsave(&bus->gpio_lock, flags); + if (ssb_chipco_available(&bus->chipco)) + res = ssb_chipco_gpio_out(&bus->chipco, mask, value); + else if (ssb_extif_available(&bus->extif)) + res = ssb_extif_gpio_out(&bus->extif, mask, value); + else + SSB_WARN_ON(1); + spin_unlock_irqrestore(&bus->gpio_lock, flags); + + return res; +} +EXPORT_SYMBOL(ssb_gpio_out); + +u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value) +{ + unsigned long flags; + u32 res = 0; + + spin_lock_irqsave(&bus->gpio_lock, flags); + if (ssb_chipco_available(&bus->chipco)) + res = ssb_chipco_gpio_outen(&bus->chipco, mask, value); + else if (ssb_extif_available(&bus->extif)) + res = ssb_extif_gpio_outen(&bus->extif, mask, value); + else + SSB_WARN_ON(1); + spin_unlock_irqrestore(&bus->gpio_lock, flags); + + return res; +} +EXPORT_SYMBOL(ssb_gpio_outen); + +u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value) +{ + unsigned long flags; + u32 res = 0; + + spin_lock_irqsave(&bus->gpio_lock, flags); + if (ssb_chipco_available(&bus->chipco)) + res = ssb_chipco_gpio_control(&bus->chipco, mask, value); + spin_unlock_irqrestore(&bus->gpio_lock, flags); + + return res; +} +EXPORT_SYMBOL(ssb_gpio_control); + +u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value) +{ + unsigned long flags; + u32 res = 0; + + spin_lock_irqsave(&bus->gpio_lock, flags); + if (ssb_chipco_available(&bus->chipco)) + res = ssb_chipco_gpio_intmask(&bus->chipco, mask, value); + else if (ssb_extif_available(&bus->extif)) + res = ssb_extif_gpio_intmask(&bus->extif, mask, value); + else + SSB_WARN_ON(1); + spin_unlock_irqrestore(&bus->gpio_lock, flags); + + return res; +} +EXPORT_SYMBOL(ssb_gpio_intmask); + +u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value) +{ + unsigned long flags; + u32 res = 0; + + spin_lock_irqsave(&bus->gpio_lock, flags); + if (ssb_chipco_available(&bus->chipco)) + res = ssb_chipco_gpio_polarity(&bus->chipco, mask, value); + else if (ssb_extif_available(&bus->extif)) + res = ssb_extif_gpio_polarity(&bus->extif, mask, value); + else + SSB_WARN_ON(1); + spin_unlock_irqrestore(&bus->gpio_lock, flags); + + return res; +} +EXPORT_SYMBOL(ssb_gpio_polarity); diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 9028ed5715a1..af07ab22708f 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -569,6 +569,9 @@ static int ssb_bus_register(struct ssb_bus *bus, spin_lock_init(&bus->bar_lock); INIT_LIST_HEAD(&bus->list); +#ifdef CONFIG_SSB_EMBEDDED + spin_lock_init(&bus->gpio_lock); +#endif /* Powerup the bus */ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 9d5da8b2ccf9..d14c03685717 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -283,6 +283,11 @@ struct ssb_bus { /* Contents of the SPROM. */ struct ssb_sprom sprom; +#ifdef CONFIG_SSB_EMBEDDED + /* Lock for GPIO register access. */ + spinlock_t gpio_lock; +#endif /* EMBEDDED */ + /* Internal-only stuff follows. Do not touch. */ struct list_head list; #ifdef CONFIG_SSB_DEBUG diff --git a/include/linux/ssb/ssb_embedded.h b/include/linux/ssb/ssb_embedded.h index 80bd58496450..8d8dedff059d 100644 --- a/include/linux/ssb/ssb_embedded.h +++ b/include/linux/ssb/ssb_embedded.h @@ -7,4 +7,12 @@ extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); +/* Generic GPIO API */ +u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask); +u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value); +u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value); + #endif /* LINUX_SSB_EMBEDDED_H_ */ From 7cb4461520f307a6e3fb2bb32cb8daee45aa1fae Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 19 Feb 2008 17:46:48 +0100 Subject: [PATCH 25/37] ssb: Fix pcicore cardbus mode This fixes the pcicore driver to not die a horrible crash death when inserting a cardbus card. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/driver_pcicore.c | 28 ++++++++++++++++++++++++++-- drivers/ssb/main.c | 1 + include/linux/ssb/ssb.h | 7 +++++++ include/linux/ssb/ssb_driver_pci.h | 5 +++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 2faaa906d5d6..059452fbb168 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "ssb_private.h" @@ -27,6 +28,18 @@ void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value) ssb_write32(pc->dev, offset, value); } +static inline +u16 pcicore_read16(struct ssb_pcicore *pc, u16 offset) +{ + return ssb_read16(pc->dev, offset); +} + +static inline +void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value) +{ + ssb_write16(pc->dev, offset, value); +} + /************************************************** * Code for hostmode operation. **************************************************/ @@ -117,8 +130,10 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc, u32 addr = 0; u32 tmp; - if (unlikely(pc->cardbusmode && dev > 1)) + /* We do only have one cardbus device behind the bridge. */ + if (pc->cardbusmode && (dev >= 1)) goto out; + if (bus == 0) { /* Type 0 transaction */ if (unlikely(dev >= SSB_PCI_SLOT_MAX)) @@ -318,7 +333,16 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); udelay(1); /* Assertion time demanded by the PCI standard */ - /*TODO cardbus mode */ + if (pc->dev->bus->has_cardbus_slot) { + ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n"); + pc->cardbusmode = 1; + /* GPIO 1 resets the bridge */ + ssb_gpio_out(pc->dev->bus, 1, 1); + ssb_gpio_outen(pc->dev->bus, 1, 1); + pcicore_write16(pc, SSB_PCICORE_SPROM(0), + pcicore_read16(pc, SSB_PCICORE_SPROM(0)) + | 0x0400); + } /* 64MB I/O window */ pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index af07ab22708f..bedb2b4ee9d2 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -557,6 +557,7 @@ static int ssb_fetch_invariants(struct ssb_bus *bus, goto out; memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo)); memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom)); + bus->has_cardbus_slot = iv.has_cardbus_slot; out: return err; } diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index d14c03685717..20add65215af 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -282,6 +282,8 @@ struct ssb_bus { struct ssb_boardinfo boardinfo; /* Contents of the SPROM. */ struct ssb_sprom sprom; + /* If the board has a cardbus slot, this is set to true. */ + bool has_cardbus_slot; #ifdef CONFIG_SSB_EMBEDDED /* Lock for GPIO register access. */ @@ -299,8 +301,13 @@ struct ssb_bus { /* The initialization-invariants. */ struct ssb_init_invariants { + /* Versioning information about the PCB. */ struct ssb_boardinfo boardinfo; + /* The SPROM information. That's either stored in an + * EEPROM or NVRAM on the board. */ struct ssb_sprom sprom; + /* If the board has a cardbus slot, this is set to true. */ + bool has_cardbus_slot; }; /* Type of function to fetch the invariants. */ typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus, diff --git a/include/linux/ssb/ssb_driver_pci.h b/include/linux/ssb/ssb_driver_pci.h index 9cfffb7b1a27..5e25bac4ed31 100644 --- a/include/linux/ssb/ssb_driver_pci.h +++ b/include/linux/ssb/ssb_driver_pci.h @@ -51,6 +51,11 @@ #define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000 #define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ #define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000 +#define SSB_PCICORE_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */ +#define SSB_PCICORE_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */ +#define SSB_PCICORE_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ +#define SSB_PCICORE_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ +#define SSB_PCICORE_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ /* SBtoPCIx */ #define SSB_PCICORE_SBTOPCI_MEM 0x00000000 From 1955fd0b533d05828bff7ed290213d2a0fc0f04f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Feb 2008 12:05:59 +0100 Subject: [PATCH 26/37] rtl818x: fix sparse warnings This silences a few sparse warnings. There are two more where I can't follow the code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8180_dev.c | 4 +++- drivers/net/wireless/rtl8187_dev.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 27ebd689aa21..5e9a8ace0d81 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -135,13 +135,15 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) while (skb_queue_len(&ring->queue)) { struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; - struct ieee80211_tx_status status = { {0} }; + struct ieee80211_tx_status status; struct ieee80211_tx_control *control; u32 flags = le32_to_cpu(entry->flags); if (flags & RTL8180_TX_DESC_FLAG_OWN) return; + memset(&status, 0, sizeof(status)); + ring->idx = (ring->idx + 1) % ring->entries; skb = __skb_dequeue(&ring->queue); pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 0d71716d750d..f44505994a0e 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -113,10 +113,12 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) static void rtl8187_tx_cb(struct urb *urb) { - struct ieee80211_tx_status status = { {0} }; + struct ieee80211_tx_status status; struct sk_buff *skb = (struct sk_buff *)urb->context; struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; + memset(&status, 0, sizeof(status)); + usb_free_urb(info->urb); if (info->control) memcpy(&status.control, info->control, sizeof(status.control)); From 5078ed50712aa3df1099540b524d01075aee653f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Feb 2008 12:09:25 +0100 Subject: [PATCH 27/37] zd1211rw: fix sparse warnings This silences sparse when run on zd1211rw. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 49127e4b42c2..76ef2d83919d 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -360,11 +360,14 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; struct sk_buff *skb; - struct ieee80211_tx_status status = {{0}}; + struct ieee80211_tx_status status; skb = skb_dequeue(q); if (skb == NULL) return; + + memset(&status, 0, sizeof(status)); + tx_status(hw, skb, &status, 0); } @@ -389,7 +392,8 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) if (unlikely(error || (cb->control->flags & IEEE80211_TXCTL_NO_ACK))) { - struct ieee80211_tx_status status = {{0}}; + struct ieee80211_tx_status status; + memset(&status, 0, sizeof(status)); tx_status(hw, skb, &status, !error); } else { struct sk_buff_head *q = @@ -603,7 +607,9 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, tx_hdr = (struct ieee80211_hdr *)skb->data; if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) { - struct ieee80211_tx_status status = {{0}}; + struct ieee80211_tx_status status; + + memset(&status, 0, sizeof(status)); status.flags = IEEE80211_TX_STATUS_ACK; status.ack_signal = stats->ssi; __skb_unlink(skb, q); From fc71acc846c577473ada72a46c5ea9c935eca086 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 16 Feb 2008 18:13:36 +0100 Subject: [PATCH 28/37] ssb: Fix support for PCI devices behind a SSB->PCI bridge We must pin all resources and make sure the PCI subsystem won't relocate us, as the addresses are hardwired into hardware. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/driver_pcicore.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 059452fbb168..6d99a9880055 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -79,6 +79,7 @@ int pcibios_plat_dev_init(struct pci_dev *d) base = &ssb_pcicore_pcibus_iobase; else base = &ssb_pcicore_pcibus_membase; + res->flags |= IORESOURCE_PCI_FIXED; if (res->end) { size = res->end - res->start + 1; if (*base & (size - 1)) @@ -101,10 +102,12 @@ int pcibios_plat_dev_init(struct pci_dev *d) static void __init ssb_fixup_pcibridge(struct pci_dev *dev) { + u8 lat; + if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) return; - ssb_printk(KERN_INFO "PCI: fixing up bridge\n"); + ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); /* Enable PCI bridge bus mastering and memory space */ pci_set_master(dev); @@ -114,7 +117,10 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev) pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); /* Make sure our latency is high enough to handle the devices behind us */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); + lat = 168; + ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", + pci_name(dev), lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); } DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); @@ -294,14 +300,14 @@ static struct resource ssb_pcicore_mem_resource = { .name = "SSB PCIcore external memory", .start = SSB_PCI_DMA, .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, - .flags = IORESOURCE_MEM, + .flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED, }; static struct resource ssb_pcicore_io_resource = { .name = "SSB PCIcore external I/O", .start = 0x100, .end = 0x7FF, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED, }; static struct pci_controller ssb_pcicore_controller = { @@ -368,7 +374,8 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) /* Ok, ready to run, register it to the system. * The following needs change, if we want to port hostmode * to non-MIPS platform. */ - set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); + ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000); + set_io_port_base(ssb_pcicore_controller.io_map_base); /* Give some time to the PCI controller to configure itself with the new * values. Not waiting at this point causes crashes of the machine. */ mdelay(10); From a2724e2559a3c41ac6182da6e2446d3abf0720a5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Feb 2008 19:47:44 -0800 Subject: [PATCH 29/37] [BNX2]: More 5706S link down workaround. The previous patches to workaround the 5706S on an HP blade were not sufficient. The link state still does not change properly in some cases. This patch adds polling to make it completely reliable. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 471c7f3e8a4a..2fa258050968 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1273,14 +1273,20 @@ bnx2_set_link(struct bnx2 *bp) if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && (CHIP_NUM(bp) == CHIP_NUM_5706)) { - u32 val; + u32 val, an_dbg; if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) { bnx2_5706s_force_link_dn(bp, 0); bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN; } val = REG_RD(bp, BNX2_EMAC_STATUS); - if (val & BNX2_EMAC_STATUS_LINK) + + bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); + + if ((val & BNX2_EMAC_STATUS_LINK) && + !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC)) bmsr |= BMSR_LSTATUS; else bmsr &= ~BMSR_LSTATUS; @@ -5390,13 +5396,6 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) int check_link = 1; spin_lock(&bp->phy_lock); - if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) { - bnx2_5706s_force_link_dn(bp, 0); - bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN; - spin_unlock(&bp->phy_lock); - return; - } - if (bp->serdes_an_pending) { bp->serdes_an_pending--; check_link = 0; @@ -5420,7 +5419,6 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) { u32 phy2; - check_link = 0; bnx2_write_phy(bp, 0x17, 0x0f01); bnx2_read_phy(bp, 0x15, &phy2); if (phy2 & 0x20) { @@ -5435,17 +5433,21 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) } else bp->current_interval = bp->timer_interval; - if (bp->link_up && (bp->autoneg & AUTONEG_SPEED) && check_link) { + if (check_link) { u32 val; bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val); bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val); - if (val & MISC_SHDW_AN_DBG_NOSYNC) { - bnx2_5706s_force_link_dn(bp, 1); - bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN; - } + if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) { + if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) { + bnx2_5706s_force_link_dn(bp, 1); + bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN; + } else + bnx2_set_link(bp); + } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC)) + bnx2_set_link(bp); } spin_unlock(&bp->phy_lock); } From 38ea3686f6d1110a3787dfd7c5cf7bad1926818b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Feb 2008 19:48:57 -0800 Subject: [PATCH 30/37] [BNX2]: Disable parallel detect on an HP blade. Because of some board issues, we need to disable parallel detect on an HP blade. Without this patch, the link state can become stuck when it goes into parallel detect mode. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 14 +++++++++++++- drivers/net/bnx2.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2fa258050968..35356fba5a71 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5362,11 +5362,15 @@ bnx2_test_intr(struct bnx2 *bp) return -ENODEV; } +/* Determining link for parallel detection. */ static int bnx2_5706_serdes_has_link(struct bnx2 *bp) { u32 mode_ctl, an_dbg, exp; + if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL) + return 0; + bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL); bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl); @@ -7328,7 +7332,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->flags |= BNX2_FLAG_NO_WOL; bp->wol = 0; } - if (CHIP_NUM(bp) != CHIP_NUM_5706) { + if (CHIP_NUM(bp) == CHIP_NUM_5706) { + /* Don't do parallel detect on this board because of + * some board problems. The link will not go down + * if we do parallel detect. + */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP && + pdev->subsystem_device == 0x310c) + bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL; + } else { bp->phy_addr = 2; if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 3aa0364942e2..1eaf5bb3d9c2 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6673,6 +6673,7 @@ struct bnx2 { #define BNX2_PHY_FLAG_DIS_EARLY_DAC 0x00000400 #define BNX2_PHY_FLAG_REMOTE_PHY_CAP 0x00000800 #define BNX2_PHY_FLAG_FORCED_DOWN 0x00001000 +#define BNX2_PHY_FLAG_NO_PARALLEL 0x00002000 u32 mii_bmcr; u32 mii_bmsr; From c73b1d1f26d4c9d54b49526edf9ee958ee5b80c1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Feb 2008 19:49:48 -0800 Subject: [PATCH 31/37] [BNX2]: Update version to 1.7.4. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 35356fba5a71..15853be4680a 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.7.3" -#define DRV_MODULE_RELDATE "January 29, 2008" +#define DRV_MODULE_VERSION "1.7.4" +#define DRV_MODULE_RELDATE "February 18, 2008" #define RUN_AT(x) (jiffies + (x)) From 759afc31332aed66bde20743e7e2d1e47b08aaeb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 23 Feb 2008 19:51:59 -0800 Subject: [PATCH 32/37] tg3: ethtool phys_id default When asked to blink LEDs the tg3 driver behaves when using: ethtool -p ethX The default value for data is zero, and other drivers interpret this as blink forever (or at least a really long time). The tg3 driver interprets this as blink once. All drivers should have the same behaviour. Signed-off-by: Stephen Hemminger Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index db606b603884..26ffb67f1da2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8781,7 +8781,7 @@ static int tg3_phys_id(struct net_device *dev, u32 data) return -EAGAIN; if (data == 0) - data = 2; + data = UINT_MAX / 2; for (i = 0; i < (data * 2); i++) { if ((i % 2) == 0) From 1840bb13c22f5b8fd2e242e36c8d6ea3f312be67 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 23 Feb 2008 19:54:36 -0800 Subject: [PATCH 33/37] [RTNL]: Validate hardware and broadcast address attribute for RTM_NEWLINK RTM_NEWLINK allows for already existing links to be modified. For this purpose do_setlink() is called which expects address attributes with a payload length of at least dev->addr_len. This patch adds the necessary validation for the RTM_NEWLINK case. The address length for links to be created is not checked for now as the actual attribute length is used when copying the address to the netdevice structure. It might make sense to report an error if less than addr_len bytes are provided but enforcing this might break drivers trying to be smart with not transmitting all zero addresses. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e170179cc66f..2bd9c5f7627d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -722,6 +722,21 @@ static struct net *get_net_ns_by_pid(pid_t pid) return net; } +static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) +{ + if (dev) { + if (tb[IFLA_ADDRESS] && + nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) + return -EINVAL; + + if (tb[IFLA_BROADCAST] && + nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) + return -EINVAL; + } + + return 0; +} + static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, struct nlattr **tb, char *ifname, int modified) { @@ -894,12 +909,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) goto errout; } - if (tb[IFLA_ADDRESS] && - nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) - goto errout_dev; - - if (tb[IFLA_BROADCAST] && - nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) + if ((err = validate_linkmsg(dev, tb)) < 0) goto errout_dev; err = do_setlink(dev, ifm, tb, ifname, 0); @@ -1020,6 +1030,9 @@ replay: else dev = NULL; + if ((err = validate_linkmsg(dev, tb)) < 0) + return err; + if (tb[IFLA_LINKINFO]) { err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO], ifla_info_policy); From bc4bf5f38cf0a623e6a29f52ec80bfcc56a373c6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 23 Feb 2008 19:57:02 -0800 Subject: [PATCH 34/37] [NEIGH]: Fix race between neighbor lookup and table's hash_rnd update. The neigh_hash_grow() may update the tbl->hash_rnd value, which is used in all tbl->hash callbacks to calculate the hashval. Two lookup routines may race with this, since they call the ->hash callback without the tbl->lock held. Since the hash_rnd is changed with this lock write-locked moving the calls to ->hash under this lock read-locked closes this gap. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/neighbour.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4062b88bfc1b..2328acbd16cd 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -358,11 +358,12 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, { struct neighbour *n; int key_len = tbl->key_len; - u32 hash_val = tbl->hash(pkey, dev); + u32 hash_val; NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); + hash_val = tbl->hash(pkey, dev); for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); @@ -379,11 +380,12 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, { struct neighbour *n; int key_len = tbl->key_len; - u32 hash_val = tbl->hash(pkey, NULL); + u32 hash_val; NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); + hash_val = tbl->hash(pkey, NULL); for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len) && (net == n->dev->nd_net)) { From 55b01e8681cba392ccda4ff6184054d38968115d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 23 Feb 2008 20:09:11 -0800 Subject: [PATCH 35/37] [NET]: Restore sanity wrt. print_mac(). MAC_FMT had only one user and we tried to get rid of that, but this created more problems than it solved. As a result, this reverts three commits: 235365f3aaaa10b7056293877c0ead50425f25c7 ("net/8021q/vlan_dev.c: Use print_mac."), fea5fa875eb235dc186b1f5184eb36abc63e26cc ("[NET]: Remove MAC_FMT"), and 8f789c48448aed74fe1c07af76de8f04adacec7d ("[NET]: Elminate spurious print_mac() calls.") Signed-off-by: David S. Miller --- include/linux/if_ether.h | 3 ++- net/8021q/vlan_dev.c | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 42dc6a3571ec..e157c1399b61 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -129,7 +129,8 @@ extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len); /* * Display a 6 byte device address (MAC) in a readable format. */ -extern __pure char *print_mac(char *buf, const unsigned char *addr); +extern char *print_mac(char *buf, const unsigned char *addr); +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" #define MAC_BUF_SIZE 18 #define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] __maybe_unused diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index fc60c6d096b9..77f04e49a1a0 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -366,8 +366,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); + /* Handle non-VLAN frames if they are sent to us, for example by DHCP. * * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING @@ -405,8 +404,11 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) pr_debug("%s: about to send skb: %p to dev: %s\n", __FUNCTION__, skb, skb->dev->name); - pr_debug(" %s %s %4hx %4hx %4hx\n", - print_mac(mac, veth->h_dest), print_mac(mac2, veth->h_source), + pr_debug(" " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n", + veth->h_dest[0], veth->h_dest[1], veth->h_dest[2], + veth->h_dest[3], veth->h_dest[4], veth->h_dest[5], + veth->h_source[0], veth->h_source[1], veth->h_source[2], + veth->h_source[3], veth->h_source[4], veth->h_source[5], veth->h_vlan_proto, veth->h_vlan_TCI, veth->h_vlan_encapsulated_proto); From 34cc7ba6398203aab4056917fa1e2aa5988487aa Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 23 Feb 2008 20:19:20 -0800 Subject: [PATCH 36/37] [IP_TUNNEL]: Don't limit the number of tunnels with generic name explicitly. Use the added dev_alloc_name() call to create tunnel device name, rather than iterate in a hand-made loop with an artificial limit. Thanks Patrick for noticing this. [ The way this works is, when the device is actually registered, the generic code noticed the '%' in the name and invokes dev_alloc_name() to fully resolve the name. -DaveM ] Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/ip6_tunnel.h | 2 -- net/ipv4/ip_gre.c | 12 ++---------- net/ipv4/ipip.c | 12 ++---------- net/ipv6/ip6_tunnel.c | 15 ++++----------- net/ipv6/sit.c | 12 ++---------- 5 files changed, 10 insertions(+), 43 deletions(-) diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h index c17fa1fdc356..6512d85f11b3 100644 --- a/include/net/ip6_tunnel.h +++ b/include/net/ip6_tunnel.h @@ -14,8 +14,6 @@ /* capable of receiving packets */ #define IP6_TNL_F_CAP_RCV 0x20000 -#define IP6_TNL_MAX 128 - /* IPv6 tunnel */ struct ip6_tnl { diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 63f691719353..906cb1ada4c3 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -259,16 +259,8 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int if (parms->name[0]) strlcpy(name, parms->name, IFNAMSIZ); - else { - int i; - for (i=1; i<100; i++) { - sprintf(name, "gre%d", i); - if (__dev_get_by_name(&init_net, name) == NULL) - break; - } - if (i==100) - goto failed; - } + else + sprintf(name, "gre%%d"); dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup); if (!dev) diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index da281581692c..e77e3b855834 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -221,16 +221,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c if (parms->name[0]) strlcpy(name, parms->name, IFNAMSIZ); - else { - int i; - for (i=1; i<100; i++) { - sprintf(name, "tunl%d", i); - if (__dev_get_by_name(&init_net, name) == NULL) - break; - } - if (i==100) - goto failed; - } + else + sprintf(name, "tunl%%d"); dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup); if (dev == NULL) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index cd940647bd12..2a124e9a1b2d 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -229,18 +229,11 @@ static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) char name[IFNAMSIZ]; int err; - if (p->name[0]) { + if (p->name[0]) strlcpy(name, p->name, IFNAMSIZ); - } else { - int i; - for (i = 1; i < IP6_TNL_MAX; i++) { - sprintf(name, "ip6tnl%d", i); - if (__dev_get_by_name(&init_net, name) == NULL) - break; - } - if (i == IP6_TNL_MAX) - goto failed; - } + else + sprintf(name, "ip6tnl%%d"); + dev = alloc_netdev(sizeof (*t), name, ip6_tnl_dev_setup); if (dev == NULL) goto failed; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e77239d02bf5..dde7801abeff 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -164,16 +164,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int if (parms->name[0]) strlcpy(name, parms->name, IFNAMSIZ); - else { - int i; - for (i=1; i<100; i++) { - sprintf(name, "sit%d", i); - if (__dev_get_by_name(&init_net, name) == NULL) - break; - } - if (i==100) - goto failed; - } + else + sprintf(name, "sit%%d"); dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); if (dev == NULL) From 1b04ab4597725f75f94942da9aa40daa7b9a4bd9 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Sat, 23 Feb 2008 20:22:27 -0800 Subject: [PATCH 37/37] [NETFILTER]: fix ebtable targets return The function ebt_do_table doesn't take NF_DROP as a verdict from the targets. Signed-off-by: Joonwoo Park Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/bridge/netfilter/ebt_dnat.c | 2 +- net/bridge/netfilter/ebt_redirect.c | 2 +- net/bridge/netfilter/ebt_snat.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c index 1ec671d93dda..ca64c1cc1b47 100644 --- a/net/bridge/netfilter/ebt_dnat.c +++ b/net/bridge/netfilter/ebt_dnat.c @@ -21,7 +21,7 @@ static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr, const struct ebt_nat_info *info = data; if (!skb_make_writable(skb, 0)) - return NF_DROP; + return EBT_DROP; memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN); return info->target; diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index bfb9f74e2116..b8afe850cf1e 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -22,7 +22,7 @@ static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr, const struct ebt_redirect_info *info = data; if (!skb_make_writable(skb, 0)) - return NF_DROP; + return EBT_DROP; if (hooknr != NF_BR_BROUTING) memcpy(eth_hdr(skb)->h_dest, diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index 204f9965fb9e..5425333dda03 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -23,7 +23,7 @@ static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr, const struct ebt_nat_info *info = data; if (!skb_make_writable(skb, 0)) - return NF_DROP; + return EBT_DROP; memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN); if (!(info->target & NAT_ARP_BIT) &&