From 7c8081eb8f20aa83deb5f1e95adc8a98902555a9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Jun 2007 18:30:19 +0200 Subject: [PATCH 01/25] [PATCH] mac80211: use debugfs_rename Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index a3e01d76d503..799a9208c4b4 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -397,6 +397,8 @@ static int netdev_notify(struct notifier_block * nb, void *ndev) { struct net_device *dev = ndev; + struct dentry *dir; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); char buf[10+IFNAMSIZ]; if (state != NETDEV_CHANGENAME) @@ -408,10 +410,11 @@ static int netdev_notify(struct notifier_block * nb, if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) return 0; - /* TODO sprintf(buf, "netdev:%s", dev->name); - debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf); - */ + dir = sdata->debugfsdir; + if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) + printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " + "dir to %s\n", buf); return 0; } From fd8bacc98027aa077ffbf2ecb0c3e930325b01a4 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sat, 9 Jun 2007 19:07:14 +0100 Subject: [PATCH 02/25] [PATCH] mac80211: regulatory domain cleanup Currently, a function misnamed ieee80211_init_client() is used to handle regulatory domain control. It is called from ieee80211_register_hwmode(), which typically runs 2 or 3 times (802.11a/b/g), but each time it iterates over all the modes. This patch cleans this up and removes the confusion: ieee80211_init_client was effectively renamed to ieee80211_set_default_regdomain and is now run on a per-mode basis (doesn't have to deal with netdevs). I also moved the regdomain handling code into its own file and added some documentation. Signed-off-by: Daniel Drake Acked-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/Makefile | 1 + net/mac80211/ieee80211.c | 3 +- net/mac80211/ieee80211_i.h | 5 +- net/mac80211/ieee80211_ioctl.c | 133 ---------------------------- net/mac80211/regdomain.c | 157 +++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+), 135 deletions(-) create mode 100644 net/mac80211/regdomain.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index e9738dad2d7c..a9c2d0787d4a 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -13,6 +13,7 @@ mac80211-objs := \ ieee80211_iface.o \ ieee80211_rate.o \ michael.o \ + regdomain.o \ tkip.o \ aes_ccm.o \ wme.o \ diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 2ddf4ef4065e..6c63dcf9f1ec 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -5095,7 +5095,7 @@ int ieee80211_register_hwmode(struct ieee80211_hw *hw, } if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED)) - ieee80211_init_client(local->mdev); + ieee80211_set_default_regdomain(mode); return 0; } @@ -5246,6 +5246,7 @@ static int __init ieee80211_init(void) } ieee80211_debugfs_netdev_init(); + ieee80211_regdomain_init(); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 055a2a912185..6f7bae7ef9c0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -759,7 +759,6 @@ void ieee80211_update_default_wep_only(struct ieee80211_local *local); /* ieee80211_ioctl.c */ int ieee80211_set_compression(struct ieee80211_local *local, struct net_device *dev, struct sta_info *sta); -int ieee80211_init_client(struct net_device *dev); int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq); /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); @@ -798,6 +797,10 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); int ieee80211_if_add_mgmt(struct ieee80211_local *local); void ieee80211_if_del_mgmt(struct ieee80211_local *local); +/* regdomain.c */ +void ieee80211_regdomain_init(void); +void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); + /* for wiphy privid */ extern void *mac80211_wiphy_privid; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5918dd079e12..d0e1ab5589db 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -27,20 +27,6 @@ #include "aes_ccm.h" #include "debugfs_key.h" -static int ieee80211_regdom = 0x10; /* FCC */ -module_param(ieee80211_regdom, int, 0444); -MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK"); - -/* - * If firmware is upgraded by the vendor, additional channels can be used based - * on the new Japanese regulatory rules. This is indicated by setting - * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel - * module. - */ -static int ieee80211_japan_5ghz /* = 0 */; -module_param(ieee80211_japan_5ghz, int, 0444); -MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz"); - static void ieee80211_set_hw_encryption(struct net_device *dev, struct sta_info *sta, u8 addr[ETH_ALEN], struct ieee80211_key *key) @@ -412,125 +398,6 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, } -struct ieee80211_channel_range { - short start_freq; - short end_freq; - unsigned char power_level; - unsigned char antenna_max; -}; - -static const struct ieee80211_channel_range ieee80211_fcc_channels[] = { - { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */, - { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */, - { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */, - { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */, - { 0 } -}; - -static const struct ieee80211_channel_range ieee80211_mkk_channels[] = { - { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */, - { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */, - { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */, - { 0 } -}; - - -static const struct ieee80211_channel_range *channel_range = - ieee80211_fcc_channels; - - -static void ieee80211_unmask_channel(struct net_device *dev, int mode, - struct ieee80211_channel *chan) -{ - int i; - - chan->flag = 0; - - if (ieee80211_regdom == 64 && - (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) { - /* Do not allow Turbo modes in Japan. */ - return; - } - - for (i = 0; channel_range[i].start_freq; i++) { - const struct ieee80211_channel_range *r = &channel_range[i]; - if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { - if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz && - chan->freq >= 5260 && chan->freq <= 5320) { - /* - * Skip new channels in Japan since the - * firmware was not marked having been upgraded - * by the vendor. - */ - continue; - } - - if (ieee80211_regdom == 0x10 && - (chan->freq == 5190 || chan->freq == 5210 || - chan->freq == 5230)) { - /* Skip MKK channels when in FCC domain. */ - continue; - } - - chan->flag |= IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; - chan->power_level = r->power_level; - chan->antenna_max = r->antenna_max; - - if (ieee80211_regdom == 64 && - (chan->freq == 5170 || chan->freq == 5190 || - chan->freq == 5210 || chan->freq == 5230)) { - /* - * New regulatory rules in Japan have backwards - * compatibility with old channels in 5.15-5.25 - * GHz band, but the station is not allowed to - * use active scan on these old channels. - */ - chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN; - } - - if (ieee80211_regdom == 64 && - (chan->freq == 5260 || chan->freq == 5280 || - chan->freq == 5300 || chan->freq == 5320)) { - /* - * IBSS is not allowed on 5.25-5.35 GHz band - * due to radar detection requirements. - */ - chan->flag &= ~IEEE80211_CHAN_W_IBSS; - } - - break; - } - } -} - - -static int ieee80211_unmask_channels(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; - int c; - - list_for_each_entry(mode, &local->modes_list, list) { - for (c = 0; c < mode->num_channels; c++) { - ieee80211_unmask_channel(dev, mode->mode, - &mode->channels[c]); - } - } - return 0; -} - - -int ieee80211_init_client(struct net_device *dev) -{ - if (ieee80211_regdom == 0x40) - channel_range = ieee80211_mkk_channels; - ieee80211_unmask_channels(dev); - return 0; -} - - static int ieee80211_ioctl_siwmode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c new file mode 100644 index 000000000000..32e5dca6b6b9 --- /dev/null +++ b/net/mac80211/regdomain.c @@ -0,0 +1,157 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This regulatory domain control implementation is known to be incomplete + * and confusing. mac80211 regulatory domain control will be significantly + * reworked in the not-too-distant future. + * + * For now, drivers wishing to control which channels are and aren't available + * are advised as follows: + * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag + * - continue to include *ALL* possible channels in the modes registered + * through ieee80211_register_hwmode() + * - for each allowable ieee80211_channel structure registered in the above + * call, set the flag member to some meaningful value such as + * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | + * IEEE80211_CHAN_W_IBSS. + * - leave flag as 0 for non-allowable channels + * + * The usual implementation is for a driver to read a device EEPROM to + * determine which regulatory domain it should be operating under, then + * looking up the allowable channels in a driver-local table, then performing + * the above. + */ + +#include +#include +#include + +static int ieee80211_regdom = 0x10; /* FCC */ +module_param(ieee80211_regdom, int, 0444); +MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK"); + +/* + * If firmware is upgraded by the vendor, additional channels can be used based + * on the new Japanese regulatory rules. This is indicated by setting + * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel + * module. + */ +static int ieee80211_japan_5ghz /* = 0 */; +module_param(ieee80211_japan_5ghz, int, 0444); +MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz"); + + +struct ieee80211_channel_range { + short start_freq; + short end_freq; + unsigned char power_level; + unsigned char antenna_max; +}; + +static const struct ieee80211_channel_range ieee80211_fcc_channels[] = { + { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */, + { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */, + { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */, + { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */, + { 0 } +}; + +static const struct ieee80211_channel_range ieee80211_mkk_channels[] = { + { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */, + { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */, + { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */, + { 0 } +}; + + +static const struct ieee80211_channel_range *channel_range = + ieee80211_fcc_channels; + + +static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) +{ + int i; + + chan->flag = 0; + + if (ieee80211_regdom == 64 && + (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) { + /* Do not allow Turbo modes in Japan. */ + return; + } + + for (i = 0; channel_range[i].start_freq; i++) { + const struct ieee80211_channel_range *r = &channel_range[i]; + if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { + if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz && + chan->freq >= 5260 && chan->freq <= 5320) { + /* + * Skip new channels in Japan since the + * firmware was not marked having been upgraded + * by the vendor. + */ + continue; + } + + if (ieee80211_regdom == 0x10 && + (chan->freq == 5190 || chan->freq == 5210 || + chan->freq == 5230)) { + /* Skip MKK channels when in FCC domain. */ + continue; + } + + chan->flag |= IEEE80211_CHAN_W_SCAN | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_IBSS; + chan->power_level = r->power_level; + chan->antenna_max = r->antenna_max; + + if (ieee80211_regdom == 64 && + (chan->freq == 5170 || chan->freq == 5190 || + chan->freq == 5210 || chan->freq == 5230)) { + /* + * New regulatory rules in Japan have backwards + * compatibility with old channels in 5.15-5.25 + * GHz band, but the station is not allowed to + * use active scan on these old channels. + */ + chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN; + } + + if (ieee80211_regdom == 64 && + (chan->freq == 5260 || chan->freq == 5280 || + chan->freq == 5300 || chan->freq == 5320)) { + /* + * IBSS is not allowed on 5.25-5.35 GHz band + * due to radar detection requirements. + */ + chan->flag &= ~IEEE80211_CHAN_W_IBSS; + } + + break; + } + } +} + + +void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode) +{ + int c; + for (c = 0; c < mode->num_channels; c++) + ieee80211_unmask_channel(mode->mode, &mode->channels[c]); +} + + +void ieee80211_regdomain_init(void) +{ + if (ieee80211_regdom == 0x40) + channel_range = ieee80211_mkk_channels; +} + From 8b8857a3bb93a94230fd205be784b01fa1932c47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Jun 2007 00:16:14 +0200 Subject: [PATCH 03/25] [PATCH] mac80211: regdomain.c needs to include ieee80211_i.h Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/regdomain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c index 32e5dca6b6b9..b697a2afbb4b 100644 --- a/net/mac80211/regdomain.c +++ b/net/mac80211/regdomain.c @@ -32,6 +32,7 @@ #include #include #include +#include "ieee80211_i.h" static int ieee80211_regdom = 0x10; /* FCC */ module_param(ieee80211_regdom, int, 0444); From c81de6addb913423acef6e692fd70688180ab5dd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 18 Jul 2007 15:38:03 -0700 Subject: [PATCH 04/25] [RFKILL]: Make state sysfs writable The rfkill state Sysfs attribute should be made writable, we already pass the argument for the store handler, so we only need to update the permissions flag. Signed-off-by: Ivo van Doorn Signed-off-by: David S. Miller --- net/rfkill/rfkill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index f3986d498b40..db3395bfbcfa 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -187,7 +187,7 @@ static ssize_t rfkill_claim_store(struct device *dev, static struct device_attribute rfkill_dev_attrs[] = { __ATTR(name, S_IRUGO, rfkill_name_show, NULL), __ATTR(type, S_IRUGO, rfkill_type_show, NULL), - __ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store), + __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), __ATTR_NULL }; From b4ff4f0419ae5db83553fab79d03a89c10d540a8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2007 15:46:06 -0700 Subject: [PATCH 05/25] [NETLINK]: allocate group bitmaps dynamically Allow changing the number of groups for a netlink family after it has been created, use RCU to protect the listeners bitmap keeping netlink_has_listeners() lock-free. Signed-off-by: Johannes Berg Acked-by: Patrick McHardy Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + net/netlink/af_netlink.c | 106 ++++++++++++++++++++++++++++++--------- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 2e23353c28a5..b971ddd24090 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -161,6 +161,7 @@ extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct mutex *cb_mutex, struct module *module); +extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); extern int netlink_has_listeners(struct sock *sk, unsigned int group); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 641cfbc278d8..c386eaf6ad5b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -62,6 +62,7 @@ #include #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) +#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long)) struct netlink_sock { /* struct sock has to be the first member of netlink_sock */ @@ -314,10 +315,12 @@ netlink_update_listeners(struct sock *sk) unsigned long mask; unsigned int i; - for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) { + for (i = 0; i < NLGRPLONGS(tbl->groups); i++) { mask = 0; - sk_for_each_bound(sk, node, &tbl->mc_list) - mask |= nlk_sk(sk)->groups[i]; + sk_for_each_bound(sk, node, &tbl->mc_list) { + if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) + mask |= nlk_sk(sk)->groups[i]; + } tbl->listeners[i] = mask; } /* this function is only called with the netlink table "grabbed", which @@ -555,26 +558,37 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) nlk->subscriptions = subscriptions; } -static int netlink_alloc_groups(struct sock *sk) +static int netlink_realloc_groups(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); unsigned int groups; + unsigned long *new_groups; int err = 0; - netlink_lock_table(); + netlink_table_grab(); + groups = nl_table[sk->sk_protocol].groups; - if (!nl_table[sk->sk_protocol].registered) + if (!nl_table[sk->sk_protocol].registered) { err = -ENOENT; - netlink_unlock_table(); + goto out_unlock; + } - if (err) - return err; + if (nlk->ngroups >= groups) + goto out_unlock; - nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL); - if (nlk->groups == NULL) - return -ENOMEM; + new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC); + if (new_groups == NULL) { + err = -ENOMEM; + goto out_unlock; + } + memset((char*)new_groups + NLGRPSZ(nlk->ngroups), 0, + NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups)); + + nlk->groups = new_groups; nlk->ngroups = groups; - return 0; + out_unlock: + netlink_table_ungrab(); + return err; } static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) @@ -591,11 +605,9 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len if (nladdr->nl_groups) { if (!netlink_capable(sock, NL_NONROOT_RECV)) return -EPERM; - if (nlk->groups == NULL) { - err = netlink_alloc_groups(sk); - if (err) - return err; - } + err = netlink_realloc_groups(sk); + if (err) + return err; } if (nlk->pid) { @@ -839,10 +851,18 @@ retry: int netlink_has_listeners(struct sock *sk, unsigned int group) { int res = 0; + unsigned long *listeners; BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET)); + + rcu_read_lock(); + listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); + if (group - 1 < nl_table[sk->sk_protocol].groups) - res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners); + res = test_bit(group - 1, listeners); + + rcu_read_unlock(); + return res; } EXPORT_SYMBOL_GPL(netlink_has_listeners); @@ -1037,11 +1057,9 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, if (!netlink_capable(sock, NL_NONROOT_RECV)) return -EPERM; - if (nlk->groups == NULL) { - err = netlink_alloc_groups(sk); - if (err) - return err; - } + err = netlink_realloc_groups(sk); + if (err) + return err; if (!val || val - 1 >= nlk->ngroups) return -EINVAL; netlink_table_grab(); @@ -1328,6 +1346,46 @@ out_sock_release: return NULL; } +/** + * netlink_change_ngroups - change number of multicast groups + * + * This changes the number of multicast groups that are available + * on a certain netlink family. Note that it is not possible to + * change the number of groups to below 32. + * + * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). + * @groups: The new number of groups. + */ +int netlink_change_ngroups(struct sock *sk, unsigned int groups) +{ + unsigned long *listeners, *old = NULL; + struct netlink_table *tbl = &nl_table[sk->sk_protocol]; + int err = 0; + + if (groups < 32) + groups = 32; + + netlink_table_grab(); + if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { + listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC); + if (!listeners) { + err = -ENOMEM; + goto out_ungrab; + } + old = tbl->listeners; + memcpy(listeners, old, NLGRPSZ(tbl->groups)); + rcu_assign_pointer(tbl->listeners, listeners); + } + tbl->groups = groups; + + out_ungrab: + netlink_table_ungrab(); + synchronize_rcu(); + kfree(old); + return err; +} +EXPORT_SYMBOL(netlink_change_ngroups); + void netlink_set_nonroot(int protocol, unsigned int flags) { if ((unsigned int)protocol < MAX_LINKS) From 84659eb529b33572bb3f8c94e0978bd5d084bc7e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2007 15:47:05 -0700 Subject: [PATCH 06/25] [NETLIKN]: Allow removing multicast groups. Allow kicking listeners out of a multicast group when necessary (for example if that group is going to be removed.) Signed-off-by: Johannes Berg Acked-by: Patrick McHardy Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + net/netlink/af_netlink.c | 57 +++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index b971ddd24090..83d8239f0cce 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -162,6 +162,7 @@ extern struct sock *netlink_kernel_create(int unit, unsigned int groups, struct mutex *cb_mutex, struct module *module); extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); +extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); extern int netlink_has_listeners(struct sock *sk, unsigned int group); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c386eaf6ad5b..5681ce3aebca 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1027,6 +1027,23 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) read_unlock(&nl_table_lock); } +/* must be called with netlink table grabbed */ +static void netlink_update_socket_mc(struct netlink_sock *nlk, + unsigned int group, + int is_new) +{ + int old, new = !!is_new, subscriptions; + + old = test_bit(group - 1, nlk->groups); + subscriptions = nlk->subscriptions - old + new; + if (new) + __set_bit(group - 1, nlk->groups); + else + __clear_bit(group - 1, nlk->groups); + netlink_update_subscriptions(&nlk->sk, subscriptions); + netlink_update_listeners(&nlk->sk); +} + static int netlink_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { @@ -1052,9 +1069,6 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, break; case NETLINK_ADD_MEMBERSHIP: case NETLINK_DROP_MEMBERSHIP: { - unsigned int subscriptions; - int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0; - if (!netlink_capable(sock, NL_NONROOT_RECV)) return -EPERM; err = netlink_realloc_groups(sk); @@ -1063,14 +1077,8 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, if (!val || val - 1 >= nlk->ngroups) return -EINVAL; netlink_table_grab(); - old = test_bit(val - 1, nlk->groups); - subscriptions = nlk->subscriptions - old + new; - if (new) - __set_bit(val - 1, nlk->groups); - else - __clear_bit(val - 1, nlk->groups); - netlink_update_subscriptions(sk, subscriptions); - netlink_update_listeners(sk); + netlink_update_socket_mc(nlk, val, + optname == NETLINK_ADD_MEMBERSHIP); netlink_table_ungrab(); err = 0; break; @@ -1351,7 +1359,9 @@ out_sock_release: * * This changes the number of multicast groups that are available * on a certain netlink family. Note that it is not possible to - * change the number of groups to below 32. + * change the number of groups to below 32. Also note that it does + * not implicitly call netlink_clear_multicast_users() when the + * number of groups is reduced. * * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). * @groups: The new number of groups. @@ -1386,6 +1396,29 @@ int netlink_change_ngroups(struct sock *sk, unsigned int groups) } EXPORT_SYMBOL(netlink_change_ngroups); +/** + * netlink_clear_multicast_users - kick off multicast listeners + * + * This function removes all listeners from the given group. + * @ksk: The kernel netlink socket, as returned by + * netlink_kernel_create(). + * @group: The multicast group to clear. + */ +void netlink_clear_multicast_users(struct sock *ksk, unsigned int group) +{ + struct sock *sk; + struct hlist_node *node; + struct netlink_table *tbl = &nl_table[ksk->sk_protocol]; + + netlink_table_grab(); + + sk_for_each_bound(sk, node, &tbl->mc_list) + netlink_update_socket_mc(nlk_sk(sk), group, 0); + + netlink_table_ungrab(); +} +EXPORT_SYMBOL(netlink_clear_multicast_users); + void netlink_set_nonroot(int protocol, unsigned int flags) { if ((unsigned int)protocol < MAX_LINKS) From 2dbba6f773d1e1e4c78f03b0dbf19790d9017693 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Jul 2007 15:47:52 -0700 Subject: [PATCH 07/25] [GENETLINK]: Dynamic multicast groups. Introduce API to dynamically register and unregister multicast groups. Signed-off-by: Johannes Berg Acked-by: Patrick McHardy Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/genetlink.h | 13 +++ include/net/genetlink.h | 22 ++++ net/netlink/genetlink.c | 235 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 263 insertions(+), 7 deletions(-) diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h index f7a93770e1be..7da02c93002b 100644 --- a/include/linux/genetlink.h +++ b/include/linux/genetlink.h @@ -39,6 +39,9 @@ enum { CTRL_CMD_NEWOPS, CTRL_CMD_DELOPS, CTRL_CMD_GETOPS, + CTRL_CMD_NEWMCAST_GRP, + CTRL_CMD_DELMCAST_GRP, + CTRL_CMD_GETMCAST_GRP, /* unused */ __CTRL_CMD_MAX, }; @@ -52,6 +55,7 @@ enum { CTRL_ATTR_HDRSIZE, CTRL_ATTR_MAXATTR, CTRL_ATTR_OPS, + CTRL_ATTR_MCAST_GROUPS, __CTRL_ATTR_MAX, }; @@ -66,4 +70,13 @@ enum { #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) +enum { + CTRL_ATTR_MCAST_GRP_UNSPEC, + CTRL_ATTR_MCAST_GRP_NAME, + CTRL_ATTR_MCAST_GRP_ID, + __CTRL_ATTR_MCAST_GRP_MAX, +}; + +#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) + #endif /* __LINUX_GENERIC_NETLINK_H */ diff --git a/include/net/genetlink.h b/include/net/genetlink.h index b6eaca122db8..decdda546829 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -4,6 +4,22 @@ #include #include +/** + * struct genl_multicast_group - generic netlink multicast group + * @name: name of the multicast group, names are per-family + * @id: multicast group ID, assigned by the core, to use with + * genlmsg_multicast(). + * @list: list entry for linking + * @family: pointer to family, need not be set before registering + */ +struct genl_multicast_group +{ + struct genl_family *family; /* private */ + struct list_head list; /* private */ + char name[GENL_NAMSIZ]; + u32 id; +}; + /** * struct genl_family - generic netlink family * @id: protocol family idenfitier @@ -14,6 +30,7 @@ * @attrbuf: buffer to store parsed attributes * @ops_list: list of all assigned operations * @family_list: family list + * @mcast_groups: multicast groups list */ struct genl_family { @@ -25,6 +42,7 @@ struct genl_family struct nlattr ** attrbuf; /* private */ struct list_head ops_list; /* private */ struct list_head family_list; /* private */ + struct list_head mcast_groups; /* private */ }; /** @@ -73,6 +91,10 @@ extern int genl_register_family(struct genl_family *family); extern int genl_unregister_family(struct genl_family *family); extern int genl_register_ops(struct genl_family *, struct genl_ops *ops); extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); +extern int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp); +extern void genl_unregister_mc_group(struct genl_family *family, + struct genl_multicast_group *grp); extern struct sock *genl_sock; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index b9ab62f938d0..e146531faf1d 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -3,6 +3,7 @@ * * Authors: Jamal Hadi Salim * Thomas Graf + * Johannes Berg */ #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include @@ -42,6 +44,16 @@ static void genl_unlock(void) #define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1) static struct list_head family_ht[GENL_FAM_TAB_SIZE]; +/* + * Bitmap of multicast groups that are currently in use. + * + * To avoid an allocation at boot of just one unsigned long, + * declare it global instead. + * Bit 0 is marked as already used since group 0 is invalid. + */ +static unsigned long mc_group_start = 0x1; +static unsigned long *mc_groups = &mc_group_start; +static unsigned long mc_groups_longs = 1; static int genl_ctrl_event(int event, void *data); @@ -116,6 +128,114 @@ static inline u16 genl_generate_id(void) return id_gen_idx; } +static struct genl_multicast_group notify_grp; + +/** + * genl_register_mc_group - register a multicast group + * + * Registers the specified multicast group and notifies userspace + * about the new group. + * + * Returns 0 on success or a negative error code. + * + * @family: The generic netlink family the group shall be registered for. + * @grp: The group to register, must have a name. + */ +int genl_register_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + int id; + unsigned long *new_groups; + int err; + + BUG_ON(grp->name[0] == '\0'); + + genl_lock(); + + /* special-case our own group */ + if (grp == ¬ify_grp) + id = GENL_ID_CTRL; + else + id = find_first_zero_bit(mc_groups, + mc_groups_longs * BITS_PER_LONG); + + + if (id >= mc_groups_longs * BITS_PER_LONG) { + size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long); + + if (mc_groups == &mc_group_start) { + new_groups = kzalloc(nlen, GFP_KERNEL); + if (!new_groups) { + err = -ENOMEM; + goto out; + } + mc_groups = new_groups; + *mc_groups = mc_group_start; + } else { + new_groups = krealloc(mc_groups, nlen, GFP_KERNEL); + if (!new_groups) { + err = -ENOMEM; + goto out; + } + mc_groups = new_groups; + mc_groups[mc_groups_longs] = 0; + } + mc_groups_longs++; + } + + err = netlink_change_ngroups(genl_sock, + sizeof(unsigned long) * NETLINK_GENERIC); + if (err) + goto out; + + grp->id = id; + set_bit(id, mc_groups); + list_add_tail(&grp->list, &family->mcast_groups); + grp->family = family; + + genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp); + out: + genl_unlock(); + return 0; +} +EXPORT_SYMBOL(genl_register_mc_group); + +/** + * genl_unregister_mc_group - unregister a multicast group + * + * Unregisters the specified multicast group and notifies userspace + * about it. All current listeners on the group are removed. + * + * Note: It is not necessary to unregister all multicast groups before + * unregistering the family, unregistering the family will cause + * all assigned multicast groups to be unregistered automatically. + * + * @family: Generic netlink family the group belongs to. + * @grp: The group to unregister, must have been registered successfully + * previously. + */ +void genl_unregister_mc_group(struct genl_family *family, + struct genl_multicast_group *grp) +{ + BUG_ON(grp->family != family); + genl_lock(); + netlink_clear_multicast_users(genl_sock, grp->id); + clear_bit(grp->id, mc_groups); + list_del(&grp->list); + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); + grp->id = 0; + grp->family = NULL; + genl_unlock(); +} + +static void genl_unregister_mc_groups(struct genl_family *family) +{ + struct genl_multicast_group *grp, *tmp; + + list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) + genl_unregister_mc_group(family, grp); +} + /** * genl_register_ops - register generic netlink operations * @family: generic netlink family @@ -216,6 +336,7 @@ int genl_register_family(struct genl_family *family) goto errout; INIT_LIST_HEAD(&family->ops_list); + INIT_LIST_HEAD(&family->mcast_groups); genl_lock(); @@ -275,6 +396,8 @@ int genl_unregister_family(struct genl_family *family) { struct genl_family *rc; + genl_unregister_mc_groups(family); + genl_lock(); list_for_each_entry(rc, genl_family_chain(family->id), family_list) { @@ -410,6 +533,67 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, nla_nest_end(skb, nla_ops); } + if (!list_empty(&family->mcast_groups)) { + struct genl_multicast_group *grp; + struct nlattr *nla_grps; + int idx = 1; + + nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); + if (nla_grps == NULL) + goto nla_put_failure; + + list_for_each_entry(grp, &family->mcast_groups, list) { + struct nlattr *nest; + + nest = nla_nest_start(skb, idx++); + if (nest == NULL) + goto nla_put_failure; + + NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id); + NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME, + grp->name); + + nla_nest_end(skb, nest); + } + nla_nest_end(skb, nla_grps); + } + + return genlmsg_end(skb, hdr); + +nla_put_failure: + return genlmsg_cancel(skb, hdr); +} + +static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid, + u32 seq, u32 flags, struct sk_buff *skb, + u8 cmd) +{ + void *hdr; + struct nlattr *nla_grps; + struct nlattr *nest; + + hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd); + if (hdr == NULL) + return -1; + + NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name); + NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id); + + nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); + if (nla_grps == NULL) + goto nla_put_failure; + + nest = nla_nest_start(skb, 1); + if (nest == NULL) + goto nla_put_failure; + + NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id); + NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME, + grp->name); + + nla_nest_end(skb, nest); + nla_nest_end(skb, nla_grps); + return genlmsg_end(skb, hdr); nla_put_failure: @@ -453,8 +637,8 @@ errout: return skb->len; } -static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, - int seq, u8 cmd) +static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, + u32 pid, int seq, u8 cmd) { struct sk_buff *skb; int err; @@ -472,6 +656,25 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, return skb; } +static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp, + u32 pid, int seq, u8 cmd) +{ + struct sk_buff *skb; + int err; + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb == NULL) + return ERR_PTR(-ENOBUFS); + + err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd); + if (err < 0) { + nlmsg_free(skb); + return ERR_PTR(err); + } + + return skb; +} + static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING, @@ -501,8 +704,8 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) goto errout; } - msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq, - CTRL_CMD_NEWFAMILY); + msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq, + CTRL_CMD_NEWFAMILY); if (IS_ERR(msg)) { err = PTR_ERR(msg); goto errout; @@ -523,7 +726,15 @@ static int genl_ctrl_event(int event, void *data) switch (event) { case CTRL_CMD_NEWFAMILY: case CTRL_CMD_DELFAMILY: - msg = ctrl_build_msg(data, 0, 0, event); + msg = ctrl_build_family_msg(data, 0, 0, event); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); + break; + case CTRL_CMD_NEWMCAST_GRP: + case CTRL_CMD_DELMCAST_GRP: + msg = ctrl_build_mcgrp_msg(data, 0, 0, event); if (IS_ERR(msg)) return PTR_ERR(msg); @@ -541,6 +752,10 @@ static struct genl_ops genl_ctrl_ops = { .policy = ctrl_policy, }; +static struct genl_multicast_group notify_grp = { + .name = "notify", +}; + static int __init genl_init(void) { int i, err; @@ -557,11 +772,17 @@ static int __init genl_init(void) goto errout_register; netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); - genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID, - genl_rcv, NULL, THIS_MODULE); + + /* we'll bump the group number right afterwards */ + genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv, + NULL, THIS_MODULE); if (genl_sock == NULL) panic("GENL: Cannot initialize generic netlink\n"); + err = genl_register_mc_group(&genl_ctrl, ¬ify_grp); + if (err < 0) + goto errout_register; + return 0; errout_register: From 33ccad35a21df51c0d23f3e3e88688524e7b51ed Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 18 Jul 2007 17:10:44 +0200 Subject: [PATCH 08/25] [PATCH] mac80211: fix GCC warning on 64bit platforms net/mac80211/ieee80211.c: In function ieee80211_register_hw: net/mac80211/ieee80211.c:4989: warning: comparison of distinct pointer types lacks a cast Size of ieee80211_tx_status_rtap_hdr structure will never be greater than unsigned int. Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 6c63dcf9f1ec..c944b17d0fc0 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -4986,8 +4986,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time. */ - local->tx_headroom = max(local->hw.extra_tx_headroom, - sizeof(struct ieee80211_tx_status_rtap_hdr)); + local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, + sizeof(struct ieee80211_tx_status_rtap_hdr)); debugfs_hw_add(local); From cfb7267aaba2b59374d7bc765f038698711b09d8 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 28 Jun 2007 23:14:35 -0700 Subject: [PATCH 09/25] [PATCH] mac80211: remove rtnl locking in ieee80211_sta.c The rtnl is held in ieee80211_sta.c to prevent some potential configuration races with userspace. Unfortunately, it also has the potential for deadlocks on interface down. This patch removes the rtnl locking to eliminate the deadlocks. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index ba2bf8f0a347..952d8dd0676c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -2107,12 +2106,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_sta_bss *bss, *selected = NULL; int top_rssi = 0, freq; - rtnl_lock(); - if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel && !ifsta->auto_ssid_sel) { ifsta->state = IEEE80211_AUTHENTICATE; - rtnl_unlock(); ieee80211_sta_reset_auth(dev, ifsta); return 0; } @@ -2155,7 +2151,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev, ieee80211_sta_set_bssid(dev, selected->bssid); ieee80211_rx_bss_put(dev, selected); ifsta->state = IEEE80211_AUTHENTICATE; - rtnl_unlock(); ieee80211_sta_reset_auth(dev, ifsta); return 0; } else { @@ -2166,7 +2161,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev, } else ifsta->state = IEEE80211_DISABLED; } - rtnl_unlock(); return -1; } From bd3b071b91a8acfe93b01567f556c879db049f99 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:43:13 +0900 Subject: [PATCH 10/25] [NET] AX25: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/ax25/af_ax25.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index c83cf8432970..dae2a42d3d86 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1262,7 +1262,7 @@ static int __must_check ax25_connect(struct socket *sock, for (;;) { prepare_to_wait(sk->sk_sleep, &wait, - TASK_INTERRUPTIBLE); + TASK_INTERRUPTIBLE); if (sk->sk_state != TCP_SYN_SENT) break; if (!signal_pending(current)) { From 00ae02f31519e8d6e374424bbdf0c7381489e416 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:43:16 +0900 Subject: [PATCH 11/25] [NET] BLUETOOTH: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f6d867e0179f..63caa414945d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -982,7 +982,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) skb->dev = (void *) hdev; bt_cb(skb)->pkt_type = type; - + __reassembly(hdev, type) = skb; scb = (void *) skb->cb; From 40b77c943468236c6dfad3e7b94348fe70c70331 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:43:23 +0900 Subject: [PATCH 12/25] [NET] CORE: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/core/dev.c | 2 +- net/core/rtnetlink.c | 2 +- net/core/sock.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 6357f54c8ff7..38212c3f9971 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2629,7 +2629,7 @@ void __dev_set_rx_mode(struct net_device *dev) return; if (!netif_device_present(dev)) - return; + return; if (dev->set_rx_mode) dev->set_rx_mode(dev); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 864cbdf31ed7..06eccca8cb5d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -98,7 +98,7 @@ int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) } int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr, - struct rtattr *rta, int len) + struct rtattr *rta, int len) { if (RTA_PAYLOAD(rta) < len) return -1; diff --git a/net/core/sock.c b/net/core/sock.c index 091032a250c7..1d55fbd22dfa 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -217,7 +217,7 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) warned++; printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) " "tries to set negative timeout\n", - current->comm, current->pid); + current->comm, current->pid); return 0; } *timeo_p = MAX_SCHEDULE_TIMEOUT; From 23248005fbe5fa32a3f6d00cdec1ecfb115d28eb Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:43:28 +0900 Subject: [PATCH 13/25] [NET] DCCP: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/dccp/ccids/lib/loss_interval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 515225f3a464..dd0fc992b042 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c @@ -227,7 +227,7 @@ void dccp_li_update_li(struct sock *sk, struct list_head *li_hist_list, struct list_head *hist_list, struct timeval *last_feedback, u16 s, u32 bytes_recv, - u32 previous_x_recv, u64 seq_loss, u8 win_loss) + u32 previous_x_recv, u64 seq_loss, u8 win_loss) { struct dccp_li_hist_entry *head; u64 seq_temp; From 9c681b43fae1e402e39d157feaa5df454b9e4f1f Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:43:47 +0900 Subject: [PATCH 14/25] [NET] IPV4: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv4/fib_frontend.c | 2 +- net/ipv4/ip_forward.c | 2 +- net/ipv4/tcp_output.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 2eb909be8041..eff6bce453ee 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -817,7 +817,7 @@ static void nl_fib_input(struct sock *sk, int len) static void nl_fib_lookup_init(void) { netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL, - THIS_MODULE); + THIS_MODULE); } static void fib_disable_ip(struct net_device *dev, int force) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 9cb04df0054b..8c95cf09f87a 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -86,7 +86,7 @@ int ip_forward(struct sk_buff *skb) goto sr_failed; if (unlikely(skb->len > dst_mtu(&rt->u.dst) && - (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { + (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { IP_INC_STATS(IPSTATS_MIB_FRAGFAILS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(dst_mtu(&rt->u.dst))); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 20aea1595c4d..666d8a58d14a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1615,7 +1615,7 @@ u32 __tcp_select_window(struct sock *sk) if (window <= free_space - mss || window > free_space) window = (free_space/mss)*mss; else if (mss == full_space && - free_space > window + full_space/2) + free_space > window + full_space/2) window = free_space; } From a5d292646ebf2ee51086f59899a377c85e5d50b2 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:21 +0900 Subject: [PATCH 15/25] [NET] NETFILTER: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/netfilter/nf_conntrack_standalone.c | 2 +- net/netfilter/nf_log.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index ffb6ff8c3528..f752293940f9 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -181,7 +181,7 @@ static int ct_seq_show(struct seq_file *s, void *v) if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) return -ENOSPC; - + return 0; } diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 94985792b79a..d67c4fbf6031 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -9,7 +9,7 @@ #include "nf_internals.h" -/* Internal logging interface, which relies on the real +/* Internal logging interface, which relies on the real LOG target modules */ #define NF_LOG_PREFIXLEN 128 From 639fc4c381456df0564b23540e0f60b0af83093b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:32 +0900 Subject: [PATCH 16/25] [NET] NETROM: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/netrom/af_netrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 5d66490dd290..dc9273295a38 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -720,7 +720,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, for (;;) { prepare_to_wait(sk->sk_sleep, &wait, - TASK_INTERRUPTIBLE); + TASK_INTERRUPTIBLE); if (sk->sk_state != TCP_SYN_SENT) break; if (!signal_pending(current)) { From db0c58f998eeb552fb47b82915005259a83613ae Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:35 +0900 Subject: [PATCH 17/25] [NET] PACKET: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/packet/af_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 7c27bd389b7e..1322d62b5d97 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -108,7 +108,7 @@ Outgoing, dev->hard_header!=NULL Incoming, dev->hard_header==NULL mac_header -> UNKNOWN position. It is very likely, that it points to ll header. PPP makes it, that is wrong, because introduce - assymetry between rx and tx paths. + assymetry between rx and tx paths. data -> data Outgoing, dev->hard_header==NULL From 2b81bff416c4413333b19af627e11fddc620bd84 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:38 +0900 Subject: [PATCH 18/25] [NET] RFKILL: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/rfkill/rfkill-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index 230e35c59786..9f746be58854 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c @@ -83,7 +83,7 @@ static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); static void rfkill_event(struct input_handle *handle, unsigned int type, - unsigned int code, int down) + unsigned int code, int down) { if (type == EV_KEY && down == 1) { switch (code) { From 6140efb536e7758cd300461981634ebfd4f51efa Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:40 +0900 Subject: [PATCH 19/25] [NET] ROSE: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/rose/af_rose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index f4d3aba00800..976c3cc86a29 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -816,7 +816,7 @@ rose_try_next_neigh: for (;;) { prepare_to_wait(sk->sk_sleep, &wait, - TASK_INTERRUPTIBLE); + TASK_INTERRUPTIBLE); if (sk->sk_state != TCP_SYN_SENT) break; if (!signal_pending(current)) { From 1c899641acd18b8d9d8a61dcb5dd8826fc6c87ea Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:44 +0900 Subject: [PATCH 20/25] [NET] RXRPC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/rxrpc/af_rxrpc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 2c57df9c131b..46f6d572ad2d 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -805,26 +805,26 @@ static int __init af_rxrpc_init(void) } ret = proto_register(&rxrpc_proto, 1); - if (ret < 0) { - printk(KERN_CRIT "RxRPC: Cannot register protocol\n"); + if (ret < 0) { + printk(KERN_CRIT "RxRPC: Cannot register protocol\n"); goto error_proto; } ret = sock_register(&rxrpc_family_ops); if (ret < 0) { - printk(KERN_CRIT "RxRPC: Cannot register socket family\n"); + printk(KERN_CRIT "RxRPC: Cannot register socket family\n"); goto error_sock; } ret = register_key_type(&key_type_rxrpc); if (ret < 0) { - printk(KERN_CRIT "RxRPC: Cannot register client key type\n"); + printk(KERN_CRIT "RxRPC: Cannot register client key type\n"); goto error_key_type; } ret = register_key_type(&key_type_rxrpc_s); if (ret < 0) { - printk(KERN_CRIT "RxRPC: Cannot register server key type\n"); + printk(KERN_CRIT "RxRPC: Cannot register server key type\n"); goto error_key_type_s; } From 9cbcbf4e010ec253df686257f99c819da9b895da Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:50 +0900 Subject: [PATCH 21/25] [NET] SCTP: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/sctp/sm_statefuns.c | 2 +- net/sctp/socket.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index f02ce3dddb7b..fd2dfdd7d7fd 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1779,7 +1779,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, SCTP_COMM_UP, 0, asoc->c.sinit_num_ostreams, asoc->c.sinit_max_instreams, - NULL, GFP_ATOMIC); + NULL, GFP_ATOMIC); if (!ev) goto nomem; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b1917f68723c..ee88f2ea5101 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4803,7 +4803,7 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len, char __user *optval, int __user *optlen) { - u32 val; + u32 val; if (len < sizeof(u32)) return -EINVAL; @@ -4827,7 +4827,7 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len, char __user *optval, int __user *optlen) { - int val; + int val; if (len < sizeof(int)) return -EINVAL; From fb1416a59b070d2dea280bfac3313bf3b8a17cd2 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:53 +0900 Subject: [PATCH 22/25] [NET] SUNRPC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/sunrpc/auth_gss/gss_krb5_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index f441aa0b26dc..bfb6a29633dd 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -67,7 +67,7 @@ krb5_encrypt( if (crypto_blkcipher_ivsize(tfm) > 16) { dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n", - crypto_blkcipher_ivsize(tfm)); + crypto_blkcipher_ivsize(tfm)); goto out; } From 8238745a39606738c1d8d39f2052959b3e594b04 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:44:56 +0900 Subject: [PATCH 23/25] [NET] TIPC: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/tipc/socket.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 4a8f37f48764..84110172031e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1629,8 +1629,8 @@ static struct proto_ops msg_ops = { .getsockopt = getsockopt, .sendmsg = send_msg, .recvmsg = recv_msg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage }; static struct proto_ops packet_ops = { @@ -1650,8 +1650,8 @@ static struct proto_ops packet_ops = { .getsockopt = getsockopt, .sendmsg = send_packet, .recvmsg = recv_msg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage }; static struct proto_ops stream_ops = { @@ -1671,8 +1671,8 @@ static struct proto_ops stream_ops = { .getsockopt = getsockopt, .sendmsg = send_stream, .recvmsg = recv_stream, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage }; static struct net_proto_family tipc_family_ops = { From 7dc12d6dd6cc1aa489c6f3e34a75e8023c945da8 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 19 Jul 2007 10:45:15 +0900 Subject: [PATCH 24/25] [NET] XFRM: Fix whitespace errors. Signed-off-by: YOSHIFUJI Hideaki --- net/xfrm/xfrm_policy.c | 2 +- net/xfrm/xfrm_state.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b48f06fc9fd9..cfaf17c8851e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -857,7 +857,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) pol, NULL); return err; } - } + } for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { hlist_for_each_entry(pol, entry, xfrm_policy_bydst[dir].table + i, diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index e070c3f938fb..38f90ca75b1e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -407,7 +407,7 @@ xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) xfrm_audit_log(audit_info->loginuid, audit_info->secid, AUDIT_MAC_IPSEC_DELSA, - 0, NULL, x); + 0, NULL, x); return err; } From ee6a99b539a50b4e9398938a0a6d37f8bf911550 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 18 Jul 2007 21:49:10 -0700 Subject: [PATCH 25/25] [TG3]: Fix msi issue with kexec/kdump. Tina Yang discovered an MSI related problem when doing kdump. The problem is that the kexec kernel is booted without going through system reset, and as a result, MSI may already be enabled when tg3_init_one() is called. tg3_init_one() calls pci_save_state() which will save the stale MSI state. Later on in tg3_open(), we call pci_enable_msi() to reconfigure MSI on the chip before we reset the chip. After chip reset, we call pci_restore_state() which will put the stale MSI address/data back onto the chip. This is no longer a problem in the latest kernel because pci_restore_state() has been changed to restore MSI state from internal data structures which will guarantee restoring the proper MSI state. But I think we should still fix it. Our save and restore sequence can still cause very subtle problems down the road. The fix is to have our own functions save and restore precisely what we need. We also change it to save and restore state inside tg3_chip_reset() in a more straight forward way. Thanks to Tina for helping to test and debug the problem. [ Bump driver version and release date. -DaveM ] Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 114 ++++++++++++++++++++++++++-------------------- drivers/net/tg3.h | 1 + 2 files changed, 66 insertions(+), 49 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5ee14764fd74..887b9a5cfe48 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.78" -#define DRV_MODULE_RELDATE "July 11, 2007" +#define DRV_MODULE_VERSION "3.79" +#define DRV_MODULE_RELDATE "July 18, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -4847,6 +4847,59 @@ static int tg3_poll_fw(struct tg3 *tp) return 0; } +/* Save PCI command register before chip reset */ +static void tg3_save_pci_state(struct tg3 *tp) +{ + u32 val; + + pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val); + tp->pci_cmd = val; +} + +/* Restore PCI state after chip reset */ +static void tg3_restore_pci_state(struct tg3 *tp) +{ + u32 val; + + /* Re-enable indirect register accesses. */ + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + + /* Set MAX PCI retry to zero. */ + val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE); + if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && + (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) + val |= PCISTATE_RETRY_SAME_DMA; + pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val); + + pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd); + + /* Make sure PCI-X relaxed ordering bit is clear. */ + pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); + val &= ~PCIX_CAPS_RELAXED_ORDERING; + pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); + + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + u32 val; + + /* Chip reset on 5780 will reset MSI enable bit, + * so need to restore it. + */ + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + u16 ctrl; + + pci_read_config_word(tp->pdev, + tp->msi_cap + PCI_MSI_FLAGS, + &ctrl); + pci_write_config_word(tp->pdev, + tp->msi_cap + PCI_MSI_FLAGS, + ctrl | PCI_MSI_FLAGS_ENABLE); + val = tr32(MSGINT_MODE); + tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE); + } + } +} + static void tg3_stop_fw(struct tg3 *); /* tp->lock is held. */ @@ -4863,6 +4916,12 @@ static int tg3_chip_reset(struct tg3 *tp) */ tp->nvram_lock_cnt = 0; + /* GRC_MISC_CFG core clock reset will clear the memory + * enable bit in PCI register 4 and the MSI enable bit + * on some chips, so we save relevant registers here. + */ + tg3_save_pci_state(tp); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) @@ -4961,50 +5020,14 @@ static int tg3_chip_reset(struct tg3 *tp) pci_write_config_dword(tp->pdev, 0xd8, 0xf5000); } - /* Re-enable indirect register accesses. */ - pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, - tp->misc_host_ctrl); - - /* Set MAX PCI retry to zero. */ - val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE); - if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) - val |= PCISTATE_RETRY_SAME_DMA; - pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val); - - pci_restore_state(tp->pdev); + tg3_restore_pci_state(tp); tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING; - /* Make sure PCI-X relaxed ordering bit is clear. */ - pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); - val &= ~PCIX_CAPS_RELAXED_ORDERING; - pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); - - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { - u32 val; - - /* Chip reset on 5780 will reset MSI enable bit, - * so need to restore it. - */ - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { - u16 ctrl; - - pci_read_config_word(tp->pdev, - tp->msi_cap + PCI_MSI_FLAGS, - &ctrl); - pci_write_config_word(tp->pdev, - tp->msi_cap + PCI_MSI_FLAGS, - ctrl | PCI_MSI_FLAGS_ENABLE); - val = tr32(MSGINT_MODE); - tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE); - } - + val = 0; + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) val = tr32(MEMARB_MODE); - tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); - - } else - tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) { tg3_stop_fw(tp); @@ -11978,7 +12001,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, */ if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - pci_save_state(tp->pdev); tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); } @@ -12007,12 +12029,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_coal(tp); - /* Now that we have fully setup the chip, save away a snapshot - * of the PCI config space. We need to restore this after - * GRC_MISC_CFG core clock resets and some resume events. - */ - pci_save_state(tp->pdev); - pci_set_drvdata(pdev, dev); err = register_netdev(dev); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d84e75e7365d..5c21f49026c9 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2345,6 +2345,7 @@ struct tg3 { #define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */ u32 led_ctrl; + u32 pci_cmd; char board_part_number[24]; char fw_ver[16];