From 5edd0b946a0afeb1d0364a3654328b046fb818a2 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Nov 2012 16:31:25 +0200 Subject: iwlwifi: fix the basic CCK rates calculation Fix a copy paste error in iwl_calc_basic_rates which leads to a wrong calculation of CCK basic rates. Cc: stable@vger.kernel.org Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 1089639..2830ea2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1012,12 +1012,12 @@ static void iwl_calc_basic_rates(struct iwl_priv *priv, * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap. */ - if (IWL_RATE_11M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; - if (IWL_RATE_5M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; - if (IWL_RATE_2M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_11M_INDEX < lowest_present_cck) + cck |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_5M_INDEX < lowest_present_cck) + cck |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_2M_INDEX < lowest_present_cck) + cck |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; /* 1M already there or needed so always add */ cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE; -- cgit v0.10.2 From 6bdd253f635f7b2ef027d116933a6c9ec148b87f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 24 Nov 2012 00:32:19 +0100 Subject: mac80211: fix remain-on-channel (non-)cancelling Felix Liao reported that when an interface is set DOWN while another interface is executing a ROC, the warning in ieee80211_start_next_roc() (about the first item on the list having started already) triggers. This is because ieee80211_roc_purge() calls it even if it never actually changed the list of ROC items. To fix this, simply remove the function call. If it is needed then it will be done by the ieee80211_sw_roc_work() function when the ROC item that is being removed while active is cleaned up. Cc: stable@vger.kernel.org Reported-by: Felix Liao Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 83608ac..2c84185 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -458,8 +458,6 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata) list_move_tail(&roc->list, &tmp_list); roc->abort = true; } - - ieee80211_start_next_roc(local); mutex_unlock(&local->mtx); list_for_each_entry_safe(roc, tmp, &tmp_list, list) { -- cgit v0.10.2 From 9f5e8f6efc7c2601136b27d9c7325c245f8fd19a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Nov 2012 16:59:45 +0100 Subject: cfg80211: rework chandef checking and export it Some of the chandef checking that we do in cfg80211 to check if a channel is supported or not is also needed in mac80211, so rework that a bit and export the functions that are needed. Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e78db2c..a238f41 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -58,6 +58,8 @@ * structures here describe these capabilities in detail. */ +struct wiphy; + /* * wireless hardware capability structures */ @@ -388,6 +390,22 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, const struct cfg80211_chan_def *chandef2); /** + * cfg80211_chandef_valid - check if a channel definition is valid + * @chandef: the channel definition to check + */ +bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef); + +/** + * cfg80211_chandef_usable - check if secondary channels can be used + * @wiphy: the wiphy to validate against + * @chandef: the channel definition to check + * @prohibited_flags: the regulatory chanenl flags that must not be set + */ +bool cfg80211_chandef_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + u32 prohibited_flags); + +/** * enum survey_info_flags - survey information flags * * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in @@ -1045,9 +1063,6 @@ struct ieee80211_txq_params { u8 aifs; }; -/* from net/wireless.h */ -struct wiphy; - /** * DOC: Scanning and BSS list handling * diff --git a/net/wireless/chan.c b/net/wireless/chan.c index bf2dfd5..b5f6983 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -44,7 +44,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, } EXPORT_SYMBOL(cfg80211_chandef_create); -bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) +bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) { u32 control_freq; @@ -105,6 +105,7 @@ bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) return true; } +EXPORT_SYMBOL(cfg80211_chandef_valid); static void chandef_primary_freqs(const struct cfg80211_chan_def *c, int *pri40, int *pri80) @@ -187,9 +188,9 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, } EXPORT_SYMBOL(cfg80211_chandef_compatible); -bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, - u32 center_freq, u32 bandwidth, - u32 prohibited_flags) +static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, + u32 center_freq, u32 bandwidth, + u32 prohibited_flags) { struct ieee80211_channel *c; u32 freq; @@ -205,55 +206,88 @@ bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, return true; } -static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, - u32 center_freq, u32 bw) +bool cfg80211_chandef_usable(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef, + u32 prohibited_flags) { - return cfg80211_secondary_chans_ok(wiphy, center_freq, bw, - IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_PASSIVE_SCAN | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_RADAR); -} + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + u32 width, control_freq; -bool cfg80211_reg_can_beacon(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef) -{ - u32 width; - bool res; + if (WARN_ON(!cfg80211_chandef_valid(chandef))) + return false; - trace_cfg80211_reg_can_beacon(wiphy, chandef); + ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap; + vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap; - if (WARN_ON(!cfg80211_chan_def_valid(chandef))) { - trace_cfg80211_return_bool(false); - return false; - } + control_freq = chandef->chan->center_freq; switch (chandef->width) { - case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20: + if (!ht_cap->ht_supported) + return false; + case NL80211_CHAN_WIDTH_20_NOHT: width = 20; break; case NL80211_CHAN_WIDTH_40: width = 40; + if (!ht_cap->ht_supported) + return false; + if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || + ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) + return false; + if (chandef->center_freq1 < control_freq && + chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) + return false; + if (chandef->center_freq1 > control_freq && + chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) + return false; break; - case NL80211_CHAN_WIDTH_80: case NL80211_CHAN_WIDTH_80P80: + if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) + return false; + case NL80211_CHAN_WIDTH_80: + if (!vht_cap->vht_supported) + return false; width = 80; break; case NL80211_CHAN_WIDTH_160: + if (!vht_cap->vht_supported) + return false; + if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) + return false; width = 160; break; default: WARN_ON_ONCE(1); - trace_cfg80211_return_bool(false); return false; } - res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width); + /* TODO: missing regulatory check on 80/160 bandwidth */ + + if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1, + width, prohibited_flags)) + return false; + + if (!chandef->center_freq2) + return true; + return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2, + width, prohibited_flags); +} +EXPORT_SYMBOL(cfg80211_chandef_usable); + +bool cfg80211_reg_can_beacon(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + bool res; + + trace_cfg80211_reg_can_beacon(wiphy, chandef); - if (res && chandef->center_freq2) - res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2, - width); + res = cfg80211_chandef_usable(wiphy, chandef, + IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR); trace_cfg80211_return_bool(res); return res; diff --git a/net/wireless/core.h b/net/wireless/core.h index a0c8dec..6183a0d 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -483,12 +483,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype, int num); -bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef); - -bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, - u32 center_freq, u32 bandwidth, - u32 prohibited_flags); - #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d038fa4..eb0aa71 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1420,63 +1420,33 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; - if (!cfg80211_chan_def_valid(chandef)) + if (!cfg80211_chandef_valid(chandef)) return -EINVAL; switch (chandef->width) { case NL80211_CHAN_WIDTH_20: - if (!ht_cap->ht_supported) - return -EINVAL; case NL80211_CHAN_WIDTH_20_NOHT: width = 20; break; case NL80211_CHAN_WIDTH_40: width = 40; - /* quick early regulatory check */ - if (chandef->center_freq1 < control_freq && - chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) - return -EINVAL; - if (chandef->center_freq1 > control_freq && - chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) - return -EINVAL; - if (!ht_cap->ht_supported) - return -EINVAL; - if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || - ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) - return -EINVAL; break; case NL80211_CHAN_WIDTH_80: width = 80; - if (!vht_cap->vht_supported) - return -EINVAL; break; case NL80211_CHAN_WIDTH_80P80: width = 80; - if (!vht_cap->vht_supported) - return -EINVAL; - if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) - return -EINVAL; break; case NL80211_CHAN_WIDTH_160: width = 160; - if (!vht_cap->vht_supported) - return -EINVAL; - if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) - return -EINVAL; break; default: return -EINVAL; } - if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1, - width, IEEE80211_CHAN_DISABLED)) + if (!cfg80211_chandef_usable(&rdev->wiphy, chandef, + IEEE80211_CHAN_DISABLED)) return -EINVAL; - if (chandef->center_freq2 && - !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2, - width, IEEE80211_CHAN_DISABLED)) - return -EINVAL; - - /* TODO: missing regulatory check on bandwidth */ return 0; } @@ -1841,7 +1811,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) static int nl80211_send_chandef(struct sk_buff *msg, struct cfg80211_chan_def *chandef) { - WARN_ON(!cfg80211_chan_def_valid(chandef)); + WARN_ON(!cfg80211_chandef_valid(chandef)); if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chandef->chan->center_freq)) -- cgit v0.10.2 From f2d9d270c15ae0139b54a7e7466d738327e97e03 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Nov 2012 14:11:39 +0100 Subject: mac80211: support VHT association Determine the VHT channel from the AP's VHT operation IE (if present) and configure the hardware to that channel if it is supported. If channel contexts cause a channel to not be usable, try a smaller bandwidth. Signed-off-by: Johannes Berg diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index f9c5a78..8f690e5 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1213,6 +1213,21 @@ struct ieee80211_vht_cap { } __packed; /** + * enum ieee80211_vht_chanwidth - VHT channel width + * @IEEE80211_VHT_CHANWIDTH_USE_HT: use the HT operation IE to + * determine the channel width (20 or 40 MHz) + * @IEEE80211_VHT_CHANWIDTH_80MHZ: 80 MHz bandwidth + * @IEEE80211_VHT_CHANWIDTH_160MHZ: 160 MHz bandwidth + * @IEEE80211_VHT_CHANWIDTH_80P80MHZ: 80+80 MHz bandwidth + */ +enum ieee80211_vht_chanwidth { + IEEE80211_VHT_CHANWIDTH_USE_HT = 0, + IEEE80211_VHT_CHANWIDTH_80MHZ = 1, + IEEE80211_VHT_CHANWIDTH_160MHZ = 2, + IEEE80211_VHT_CHANWIDTH_80P80MHZ = 3, +}; + +/** * struct ieee80211_vht_operation - VHT operation IE * * This structure is the "VHT operation element" as diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0a8f83d..8d8bf71 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -371,6 +371,8 @@ enum ieee80211_sta_flags { IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), IEEE80211_STA_DISABLE_40MHZ = BIT(10), IEEE80211_STA_DISABLE_VHT = BIT(11), + IEEE80211_STA_DISABLE_80P80MHZ = BIT(12), + IEEE80211_STA_DISABLE_160MHZ = BIT(13), }; struct ieee80211_mgd_auth_data { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d2a4f78..35d8cff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -354,6 +354,16 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, /* determine capability flags */ cap = vht_cap.cap; + if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) { + cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + } + + if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) { + cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; + cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + } + /* reserve and fill IE */ pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); @@ -543,6 +553,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) offset = noffset; } + if (WARN_ON_ONCE((ifmgd->flags & IEEE80211_STA_DISABLE_HT) && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))) + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, sband, chan, sdata->smps_mode); @@ -3183,23 +3197,270 @@ int ieee80211_max_network_latency(struct notifier_block *nb, return 0; } +static u32 chandef_downgrade(struct cfg80211_chan_def *c) +{ + u32 ret; + int tmp; + + switch (c->width) { + case NL80211_CHAN_WIDTH_20: + c->width = NL80211_CHAN_WIDTH_20_NOHT; + ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; + break; + case NL80211_CHAN_WIDTH_40: + c->width = NL80211_CHAN_WIDTH_20; + c->center_freq1 = c->chan->center_freq; + ret = IEEE80211_STA_DISABLE_40MHZ | + IEEE80211_STA_DISABLE_VHT; + break; + case NL80211_CHAN_WIDTH_80: + tmp = (30 + c->chan->center_freq - c->center_freq1)/20; + /* n_P40 */ + tmp /= 2; + /* freq_P40 */ + c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; + c->width = NL80211_CHAN_WIDTH_40; + ret = IEEE80211_STA_DISABLE_VHT; + break; + case NL80211_CHAN_WIDTH_80P80: + c->center_freq2 = 0; + c->width = NL80211_CHAN_WIDTH_80; + ret = IEEE80211_STA_DISABLE_80P80MHZ | + IEEE80211_STA_DISABLE_160MHZ; + break; + case NL80211_CHAN_WIDTH_160: + /* n_P20 */ + tmp = (70 + c->chan->center_freq - c->center_freq1)/20; + /* n_P80 */ + tmp /= 4; + c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; + c->width = NL80211_CHAN_WIDTH_80; + ret = IEEE80211_STA_DISABLE_80P80MHZ | + IEEE80211_STA_DISABLE_160MHZ; + break; + default: + case NL80211_CHAN_WIDTH_20_NOHT: + WARN_ON_ONCE(1); + c->width = NL80211_CHAN_WIDTH_20_NOHT; + ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; + break; + } + + WARN_ON_ONCE(!cfg80211_chandef_valid(c)); + + return ret; +} + +static u32 +ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + struct ieee80211_channel *channel, + const struct ieee80211_ht_operation *ht_oper, + const struct ieee80211_vht_operation *vht_oper, + struct cfg80211_chan_def *chandef) +{ + struct cfg80211_chan_def vht_chandef; + u32 ht_cfreq, ret; + + chandef->chan = channel; + chandef->width = NL80211_CHAN_WIDTH_20_NOHT; + chandef->center_freq1 = channel->center_freq; + chandef->center_freq2 = 0; + + if (!ht_oper || !sband->ht_cap.ht_supported) { + ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; + goto out; + } + + chandef->width = NL80211_CHAN_WIDTH_20; + + ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, + channel->band); + /* check that channel matches the right operating channel */ + if (channel->center_freq != ht_cfreq) { + /* + * It's possible that some APs are confused here; + * Netgear WNDR3700 sometimes reports 4 higher than + * the actual channel in association responses, but + * since we look at probe response/beacon data here + * it should be OK. + */ + sdata_info(sdata, + "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", + channel->center_freq, ht_cfreq, + ht_oper->primary_chan, channel->band); + ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; + goto out; + } + + /* check 40 MHz support, if we have it */ + if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + chandef->width = NL80211_CHAN_WIDTH_40; + chandef->center_freq1 += 10; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + chandef->width = NL80211_CHAN_WIDTH_40; + chandef->center_freq1 -= 10; + break; + } + } else { + /* 40 MHz (and 80 MHz) must be supported for VHT */ + ret = IEEE80211_STA_DISABLE_VHT; + goto out; + } + + if (!vht_oper || !sband->vht_cap.vht_supported) { + ret = IEEE80211_STA_DISABLE_VHT; + goto out; + } + + vht_chandef.chan = channel; + vht_chandef.center_freq1 = + ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, + channel->band); + vht_chandef.center_freq2 = 0; + + if (vht_oper->center_freq_seg2_idx) + vht_chandef.center_freq2 = + ieee80211_channel_to_frequency( + vht_oper->center_freq_seg2_idx, + channel->band); + + switch (vht_oper->chan_width) { + case IEEE80211_VHT_CHANWIDTH_USE_HT: + vht_chandef.width = chandef->width; + break; + case IEEE80211_VHT_CHANWIDTH_80MHZ: + vht_chandef.width = NL80211_CHAN_WIDTH_80; + break; + case IEEE80211_VHT_CHANWIDTH_160MHZ: + vht_chandef.width = NL80211_CHAN_WIDTH_160; + break; + case IEEE80211_VHT_CHANWIDTH_80P80MHZ: + vht_chandef.width = NL80211_CHAN_WIDTH_80P80; + break; + default: + sdata_info(sdata, + "AP VHT operation IE has invalid channel width (%d), disable VHT\n", + vht_oper->chan_width); + ret = IEEE80211_STA_DISABLE_VHT; + goto out; + } + + if (!cfg80211_chandef_valid(&vht_chandef)) { + sdata_info(sdata, + "AP VHT information is invalid, disable VHT\n"); + ret = IEEE80211_STA_DISABLE_VHT; + goto out; + } + + if (cfg80211_chandef_identical(chandef, &vht_chandef)) { + ret = 0; + goto out; + } + + if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { + sdata_info(sdata, + "AP VHT information doesn't match HT, disable VHT\n"); + ret = IEEE80211_STA_DISABLE_VHT; + goto out; + } + + *chandef = vht_chandef; + + ret = 0; + + while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, + IEEE80211_CHAN_DISABLED)) { + if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { + ret = IEEE80211_STA_DISABLE_HT | + IEEE80211_STA_DISABLE_VHT; + goto out; + } + + ret = chandef_downgrade(chandef); + } + + if (chandef->width != vht_chandef.width) + sdata_info(sdata, + "local regulatory prevented using AP HT/VHT configuration, downgraded\n"); + +out: + WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); + return ret; +} + +static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, + struct cfg80211_bss *cbss) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ht_cap_ie, *vht_cap_ie; + const struct ieee80211_ht_cap *ht_cap; + const struct ieee80211_vht_cap *vht_cap; + u8 chains = 1; + + if (ifmgd->flags & IEEE80211_STA_DISABLE_HT) + return chains; + + ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, + cbss->information_elements, + cbss->len_information_elements); + if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { + ht_cap = (void *)(ht_cap_ie + 2); + chains = ieee80211_mcs_to_chains(&ht_cap->mcs); + /* + * TODO: use "Tx Maximum Number Spatial Streams Supported" and + * "Tx Unequal Modulation Supported" fields. + */ + } + + if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) + return chains; + + vht_cap_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, + cbss->information_elements, + cbss->len_information_elements); + if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) { + u8 nss; + u16 tx_mcs_map; + + vht_cap = (void *)(vht_cap_ie + 2); + tx_mcs_map = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map); + for (nss = 8; nss > 0; nss--) { + if (((tx_mcs_map >> (2 * (nss - 1))) & 3) != + IEEE80211_VHT_MCS_NOT_SUPPORTED) + break; + } + /* TODO: use "Tx Highest Supported Long GI Data Rate" field? */ + chains = max(chains, nss); + } + + return chains; +} + static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, struct cfg80211_bss *cbss) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - int ht_cfreq; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - const u8 *ht_oper_ie; const struct ieee80211_ht_operation *ht_oper = NULL; + const struct ieee80211_vht_operation *vht_oper = NULL; struct ieee80211_supported_band *sband; struct cfg80211_chan_def chandef; + int ret; sband = local->hw.wiphy->bands[cbss->channel->band]; - ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; + ifmgd->flags &= ~(IEEE80211_STA_DISABLE_40MHZ | + IEEE80211_STA_DISABLE_80P80MHZ | + IEEE80211_STA_DISABLE_160MHZ); + + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && + sband->ht_cap.ht_supported) { + const u8 *ht_oper_ie; - if (sband->ht_cap.ht_supported) { ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, cbss->information_elements, cbss->len_information_elements); @@ -3207,82 +3468,45 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, ht_oper = (void *)(ht_oper_ie + 2); } - if (ht_oper) { - ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, - cbss->channel->band); - /* check that channel matches the right operating channel */ - if (cbss->channel->center_freq != ht_cfreq) { - /* - * It's possible that some APs are confused here; - * Netgear WNDR3700 sometimes reports 4 higher than - * the actual channel in association responses, but - * since we look at probe response/beacon data here - * it should be OK. - */ + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && + sband->vht_cap.vht_supported) { + const u8 *vht_oper_ie; + + vht_oper_ie = cfg80211_find_ie(WLAN_EID_VHT_OPERATION, + cbss->information_elements, + cbss->len_information_elements); + if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper)) + vht_oper = (void *)(vht_oper_ie + 2); + if (vht_oper && !ht_oper) { + vht_oper = NULL; sdata_info(sdata, - "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", - cbss->channel->center_freq, - ht_cfreq, ht_oper->primary_chan, - cbss->channel->band); - ht_oper = NULL; + "AP advertised VHT without HT, disabling both\n"); + sdata->flags |= IEEE80211_STA_DISABLE_HT; + sdata->flags |= IEEE80211_STA_DISABLE_VHT; } } - if (ht_oper) { - /* - * cfg80211 already verified that the channel itself can - * be used, but it didn't check that we can do the right - * HT type, so do that here as well. If HT40 isn't allowed - * on this channel, disable 40 MHz operation. - */ - const u8 *ht_cap_ie; - const struct ieee80211_ht_cap *ht_cap; - u8 chains = 1; - - channel_type = NL80211_CHAN_HT20; - - if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - switch (ht_oper->ht_param & - IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (cbss->channel->flags & - IEEE80211_CHAN_NO_HT40PLUS) - ifmgd->flags |= - IEEE80211_STA_DISABLE_40MHZ; - else - channel_type = NL80211_CHAN_HT40PLUS; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (cbss->channel->flags & - IEEE80211_CHAN_NO_HT40MINUS) - ifmgd->flags |= - IEEE80211_STA_DISABLE_40MHZ; - else - channel_type = NL80211_CHAN_HT40MINUS; - break; - } - } + ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, + cbss->channel, + ht_oper, vht_oper, + &chandef); - ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, - cbss->information_elements, - cbss->len_information_elements); - if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { - ht_cap = (void *)(ht_cap_ie + 2); - chains = ieee80211_mcs_to_chains(&ht_cap->mcs); - } - sdata->needed_rx_chains = min(chains, local->rx_chains); - } else { - sdata->needed_rx_chains = 1; - sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_HT; - } + sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), + local->rx_chains); /* will change later if needed */ sdata->smps_mode = IEEE80211_SMPS_OFF; - ieee80211_vif_release_channel(sdata); - cfg80211_chandef_create(&chandef, cbss->channel, channel_type); - return ieee80211_vif_use_channel(sdata, &chandef, - IEEE80211_CHANCTX_SHARED); + /* + * If this fails (possibly due to channel context sharing + * on incompatible channels, e.g. 80+80 and 160 sharing the + * same control channel) try to use a smaller bandwidth. + */ + ret = ieee80211_vif_use_channel(sdata, &chandef, + IEEE80211_CHANCTX_SHARED); + while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) + ifmgd->flags |= chandef_downgrade(&chandef); + return ret; } static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, -- cgit v0.10.2 From 5164892184d1b9ce19e45e97e9ca405ea8b9ceb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Nov 2012 23:00:18 +0100 Subject: mac80211: support (partial) VHT radiotap information Add some information that we have about VHT to radiotap. This at least lets one see the MCS and NSS information. Signed-off-by: Johannes Berg diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 7f0df13..c399963 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -186,6 +186,10 @@ struct ieee80211_radiotap_header { * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitless * * Contains the AMPDU information for the subframe. + * + * IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16 + * + * Contains VHT information about this frame. */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, @@ -209,6 +213,7 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_MCS = 19, IEEE80211_RADIOTAP_AMPDU_STATUS = 20, + IEEE80211_RADIOTAP_VHT = 21, /* valid in every it_present bitmap, even vendor namespaces */ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, @@ -282,6 +287,25 @@ enum ieee80211_radiotap_type { #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 +/* For IEEE80211_RADIOTAP_VHT */ +#define IEEE80211_RADIOTAP_VHT_KNOWN_STBC 0x0001 +#define IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA 0x0002 +#define IEEE80211_RADIOTAP_VHT_KNOWN_GI 0x0004 +#define IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS 0x0008 +#define IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM 0x0010 +#define IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED 0x0020 +#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH 0x0040 +#define IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID 0x0080 +#define IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID 0x0100 + +#define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01 +#define IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA 0x02 +#define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04 +#define IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 0x08 +#define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM 0x10 +#define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED 0x20 + + /* helpers */ static inline int ieee80211_get_radiotap_len(unsigned char *data) { diff --git a/include/net/mac80211.h b/include/net/mac80211.h index db7680a..e806f1d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1473,6 +1473,10 @@ enum ieee80211_hw_flags { * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only * adding _BW is supported today. * + * @radiotap_vht_details: lists which VHT MCS information the HW reports, + * the default is _GI | _BANDWIDTH. + * Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values. + * * @netdev_features: netdev features to be set in each netdev created * from this HW. Note only HW checksum features are currently * compatible with mac80211. Other feature bits will be rejected. @@ -1499,6 +1503,7 @@ struct ieee80211_hw { u8 max_tx_aggregation_subframes; u8 offchannel_tx_hw_queue; u8 radiotap_mcs_details; + u16 radiotap_vht_details; netdev_features_t netdev_features; }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6e93340..c4ed83b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -638,6 +638,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | IEEE80211_RADIOTAP_MCS_HAVE_GI | IEEE80211_RADIOTAP_MCS_HAVE_BW; + local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | + IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 825f33c..9b13b8b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -111,6 +111,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, len += 8; } + if (status->flag & RX_FLAG_VHT) { + len = ALIGN(len, 2); + len += 12; + } + if (status->vendor_radiotap_len) { if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) status->vendor_radiotap_align = 1; @@ -297,6 +302,41 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos++ = 0; } + if (status->flag & RX_FLAG_VHT) { + u16 known = local->hw.radiotap_vht_details; + + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); + /* known field - how to handle 80+80? */ + if (status->flag & RX_FLAG_80P80MHZ) + known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; + put_unaligned_le16(known, pos); + pos += 2; + /* flags */ + if (status->flag & RX_FLAG_SHORT_GI) + *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; + pos++; + /* bandwidth */ + if (status->flag & RX_FLAG_80MHZ) + *pos++ = 4; + else if (status->flag & RX_FLAG_80P80MHZ) + *pos++ = 0; /* marked not known above */ + else if (status->flag & RX_FLAG_160MHZ) + *pos++ = 11; + else if (status->flag & RX_FLAG_40MHZ) + *pos++ = 1; + else /* 20 MHz */ + *pos++ = 0; + /* MCS/NSS */ + *pos = (status->rate_idx << 4) | status->vht_nss; + pos += 4; + /* coding field */ + pos++; + /* group ID */ + pos++; + /* partial_aid */ + pos += 2; + } + if (status->vendor_radiotap_len) { /* ensure 2 byte alignment for the vendor field as required */ if ((pos - (u8 *)rthdr) & 1) -- cgit v0.10.2 From 53cabad70ecf0c245b41285de64a74a6c3ee9933 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Nov 2012 15:17:28 +0100 Subject: nl80211: support P2P GO powersave configuration If a driver supports P2P GO powersave, allow it to set the new feature flags for it and allow userspace to configure the parameters for it. This can be done at GO startup and later changed with SET_BSS. Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a238f41..731b48f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -538,6 +538,8 @@ struct cfg80211_beacon_data { * @privacy: the BSS uses privacy * @auth_type: Authentication type (algorithm) * @inactivity_timeout: time in seconds to determine station's inactivity. + * @p2p_ctwindow: P2P CT Window + * @p2p_opp_ps: P2P opportunistic PS */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -552,6 +554,8 @@ struct cfg80211_ap_settings { bool privacy; enum nl80211_auth_type auth_type; int inactivity_timeout; + u8 p2p_ctwindow; + bool p2p_opp_ps; }; /** @@ -913,6 +917,8 @@ struct mpath_info { * @ap_isolate: do not forward packets between connected stations * @ht_opmode: HT Operation mode * (u16 = opmode, -1 = do not change) + * @p2p_ctwindow: P2P CT Window (-1 = no change) + * @p2p_opp_ps: P2P opportunistic PS (-1 = no change) */ struct bss_parameters { int use_cts_prot; @@ -922,6 +928,7 @@ struct bss_parameters { u8 basic_rates_len; int ap_isolate; int ht_opmode; + s8 p2p_ctwindow, p2p_opp_ps; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 33a4174..e3e19f8 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1303,6 +1303,13 @@ enum nl80211_commands { * * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32) * + * @NL80211_ATTR_P2P_CTWINDOW: P2P GO Client Traffic Window (u8), used with + * the START_AP and SET_BSS commands + * @NL80211_ATTR_P2P_OPPPS: P2P GO opportunistic PS (u8), used with the + * START_AP and SET_BSS commands. This can have the values 0 or 1; + * if not given in START_AP 0 is assumed, if not given in SET_BSS + * no change is made. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1570,6 +1577,9 @@ enum nl80211_attrs { NL80211_ATTR_CENTER_FREQ1, NL80211_ATTR_CENTER_FREQ2, + NL80211_ATTR_P2P_CTWINDOW, + NL80211_ATTR_P2P_OPPPS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3126,6 +3136,10 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform * OBSS scans and generate 20/40 BSS coex reports. This flag is used only * for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied. + * @NL80211_FEATURE_P2P_GO_CTWIN: P2P GO implementation supports CT Window + * setting + * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic + * powersave */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3139,6 +3153,8 @@ enum nl80211_feature_flags { NL80211_FEATURE_AP_SCAN = 1 << 8, NL80211_FEATURE_VIF_TXPOWER = 1 << 9, NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, + NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, + NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index eb0aa71..7f53aaf 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -363,6 +363,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, + [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, + [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, }; /* policy for the key attributes */ @@ -2702,6 +2704,32 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); } + if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + params.p2p_ctwindow = + nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); + if (params.p2p_ctwindow > 127) + return -EINVAL; + if (params.p2p_ctwindow != 0 && + !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_P2P_OPPPS]) { + u8 tmp; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); + if (tmp > 1) + return -EINVAL; + params.p2p_opp_ps = tmp; + if (params.p2p_opp_ps != 0 && + !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) + return -EINVAL; + } + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); if (err) @@ -3668,6 +3696,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) params.use_short_slot_time = -1; params.ap_isolate = -1; params.ht_opmode = -1; + params.p2p_ctwindow = -1; + params.p2p_opp_ps = -1; if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) params.use_cts_prot = @@ -3690,6 +3720,32 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) params.ht_opmode = nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); + if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + params.p2p_ctwindow = + nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); + if (params.p2p_ctwindow < 0) + return -EINVAL; + if (params.p2p_ctwindow != 0 && + !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_P2P_OPPPS]) { + u8 tmp; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; + tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); + if (tmp > 1) + return -EINVAL; + params.p2p_opp_ps = tmp; + if (params.p2p_opp_ps && + !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) + return -EINVAL; + } + if (!rdev->ops->change_bss) return -EOPNOTSUPP; -- cgit v0.10.2 From 339afbf4819e5c7c0a0422af43b8c2eccd059abf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Nov 2012 15:21:17 +0100 Subject: mac80211: support P2P GO powersave configuration If the low-level driver wants to support P2P GO powersave configuration, it must set the cfg80211 flags and mac80211 will pass the parameters to it. Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5d30e5f..97cf615 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -893,7 +893,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, u32 changed = BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | - BSS_CHANGED_SSID; + BSS_CHANGED_SSID | + BSS_CHANGED_P2P_PS; int err; old = rtnl_dereference(sdata->u.ap.beacon); @@ -932,6 +933,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.hidden_ssid = (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); + sdata->vif.bss_conf.p2p_ctwindow = params->p2p_ctwindow; + sdata->vif.bss_conf.p2p_oppps = params->p2p_opp_ps; + err = ieee80211_assign_beacon(sdata, ¶ms->beacon); if (err < 0) return err; @@ -1807,6 +1811,16 @@ static int ieee80211_change_bss(struct wiphy *wiphy, changed |= BSS_CHANGED_HT; } + if (params->p2p_ctwindow >= 0) { + sdata->vif.bss_conf.p2p_ctwindow = params->p2p_ctwindow; + changed |= BSS_CHANGED_P2P_PS; + } + + if (params->p2p_opp_ps >= 0) { + sdata->vif.bss_conf.p2p_oppps = params->p2p_opp_ps; + changed |= BSS_CHANGED_P2P_PS; + } + ieee80211_bss_info_change_notify(sdata, changed); return 0; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index dc7f6b2..6e4c8bd 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1527,7 +1527,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) changed |= BSS_CHANGED_IBSS; /* fall through */ case NL80211_IFTYPE_AP: - changed |= BSS_CHANGED_SSID; + changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS; if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; -- cgit v0.10.2 From d9d8b01978f6510a262ddc4da3b3694d5b149cfe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 26 Nov 2012 12:51:52 +0100 Subject: nl80211: remove unnecessary checks The CQM TX-error rate/interval can't be less than zero since they're unsigned values, remove checks. Also fix indentation of the function. Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7f53aaf..7cce43b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6555,14 +6555,13 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { }; static int nl80211_set_cqm_txe(struct genl_info *info, - u32 rate, u32 pkts, u32 intvl) + u32 rate, u32 pkts, u32 intvl) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev; struct net_device *dev = info->user_ptr[1]; - if ((rate < 0 || rate > 100) || - (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) + if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL) return -EINVAL; wdev = dev->ieee80211_ptr; -- cgit v0.10.2 From 0624760c96da3ffeaec8027a016475ae752d75e1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 27 Nov 2012 20:31:19 +0300 Subject: mac80211: fix potential NULL dereference Smatch complains that we could dereference skb later in the function. It's probably unlikely, but we may as well return here and avoid it. Signed-off-by: Dan Carpenter [change summary] Signed-off-by: Johannes Berg diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9b13b8b..db343fa 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -49,7 +49,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, /* driver bug */ WARN_ON(1); dev_kfree_skb(skb); - skb = NULL; + return NULL; } } -- cgit v0.10.2 From 478622e81c735ecd83d45ee6be3fd45d500aaa3b Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Tue, 27 Nov 2012 18:23:06 +0100 Subject: mac80211: reject setting masked mac addresses If a driver registers an address mask we should ensure that no interface gets an address assigned that isn't covered by the registered address mask. This prevents invalid configurations from reaching the device and causing problems. Signed-off-by: Helmut Schaa [change function flow to reduce indentation, fix locking] Signed-off-by: Johannes Berg diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5331662..40c36d5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -223,6 +223,47 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) +{ + struct ieee80211_sub_if_data *sdata; + u64 new, mask, tmp; + u8 *m; + int ret = 0; + + if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) + return 0; + + m = addr; + new = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | + ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | + ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); + + m = local->hw.wiphy->addr_mask; + mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | + ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | + ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); + + + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + continue; + + m = sdata->vif.addr; + tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | + ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | + ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); + + if ((new & ~mask) != (tmp & ~mask)) { + ret = -EINVAL; + break; + } + } + mutex_unlock(&local->iflist_mtx); + + return ret; +} + static int ieee80211_change_mac(struct net_device *dev, void *addr) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -232,6 +273,10 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) if (ieee80211_sdata_running(sdata)) return -EBUSY; + ret = ieee80211_verify_mac(sdata->local, sa->sa_data); + if (ret) + return ret; + ret = eth_mac_addr(dev, sa); if (ret == 0) -- cgit v0.10.2 From 59cf1d65f7d69739a29a16fe678ebc4e1215e9c0 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Tue, 27 Nov 2012 18:03:13 +0100 Subject: mac80211: don't reinit rate control when mesh sta exists This fixes some unintended resets of the rate control statistics when minstrel_ht is used resulting in non-optimal throughput on mesh links. Tested-by: Emanuel Taube Signed-off-by: Helmut Schaa Signed-off-by: Johannes Berg diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ca52dfd..4b274e9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -391,7 +391,8 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, sta->ch_width = chandef.width; } - rate_control_rate_init(sta); + if (insert) + rate_control_rate_init(sta); spin_unlock_bh(&sta->lock); if (insert && sta_info_insert(sta)) -- cgit v0.10.2 From 289814918ce3af1296ac7d9b05508bde64e97348 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Mon, 26 Nov 2012 08:40:04 +0100 Subject: NFC: Fix incorrect llcp pointer dereference nfc_llcp_ns(s) dereferences the s pointer which is freed a line above. In a result, it can produce a crash or you will read incorrect value. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 9e8f4b2..3d63636 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -903,15 +903,18 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local, /* Remove skbs from the pending queue */ if (llcp_sock->send_ack_n != nr) { struct sk_buff *s, *tmp; + u8 n; llcp_sock->send_ack_n = nr; /* Remove and free all skbs until ns == nr */ skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) { + n = nfc_llcp_ns(s); + skb_unlink(s, &llcp_sock->tx_pending_queue); kfree_skb(s); - if (nfc_llcp_ns(s) == nr) + if (n == nr) break; } -- cgit v0.10.2 From dbeca2ea4642d9de0a59ac141b2825ea6804f408 Mon Sep 17 00:00:00 2001 From: Mahesh Palivela Date: Thu, 29 Nov 2012 14:11:07 +0530 Subject: cfg80211: Remove unused VHT chan code Cleanup of unused VHT channel config related code. Signed-off-by: Mahesh Palivela Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7cce43b..0e7e8d5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1371,9 +1371,7 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, struct genl_info *info, struct cfg80211_chan_def *chandef) { - struct ieee80211_sta_ht_cap *ht_cap; - struct ieee80211_sta_vht_cap *vht_cap; - u32 control_freq, width; + u32 control_freq; if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) return -EINVAL; @@ -1419,33 +1417,9 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, info->attrs[NL80211_ATTR_CENTER_FREQ2]); } - ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; - vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; - if (!cfg80211_chandef_valid(chandef)) return -EINVAL; - switch (chandef->width) { - case NL80211_CHAN_WIDTH_20: - case NL80211_CHAN_WIDTH_20_NOHT: - width = 20; - break; - case NL80211_CHAN_WIDTH_40: - width = 40; - break; - case NL80211_CHAN_WIDTH_80: - width = 80; - break; - case NL80211_CHAN_WIDTH_80P80: - width = 80; - break; - case NL80211_CHAN_WIDTH_160: - width = 160; - break; - default: - return -EINVAL; - } - if (!cfg80211_chandef_usable(&rdev->wiphy, chandef, IEEE80211_CHAN_DISABLED)) return -EINVAL; -- cgit v0.10.2 From db94357dbd79359496cd5189640cc36bb3c35733 Mon Sep 17 00:00:00 2001 From: Saravana Date: Wed, 28 Nov 2012 18:27:09 +0530 Subject: mac80211: add debugfs file for last ack signal Add a debugfs file showing the signal strength of the ack frame that is received for the currently sent tx packet Signed-off-by: Saravana Signed-off-by: Johannes Berg diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 89281d2..1566941 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -53,6 +53,7 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_FILE(aid, sta.aid, D); STA_FILE(dev, sdata->name, S); STA_FILE(last_signal, last_signal, D); +STA_FILE(last_ack_signal, last_ack_signal, D); static ssize_t sta_flags_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) @@ -369,6 +370,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(dev); DEBUGFS_ADD(last_signal); DEBUGFS_ADD(ht_capa); + DEBUGFS_ADD(last_ack_signal); DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6835cea..dce7693 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -250,6 +250,7 @@ struct sta_ampdu_mlme { * @rx_dropped: number of dropped MPDUs from this STA * @last_signal: signal of last received frame from this STA * @avg_signal: moving average of signal of received frames from this STA + * @last_ack_signal: signal of last received Ack frame from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) * @tx_filtered_count: number of frames the hardware filtered for this STA * @tx_retry_failed: number of frames that failed retry @@ -329,6 +330,7 @@ struct sta_info { unsigned long rx_dropped; int last_signal; struct ewma avg_signal; + int last_ack_signal; /* Plus 1 for non-QoS frames */ __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2d931ad..6400037 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -539,6 +539,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) sta->lost_packets = 0; } } + + if (acked) + sta->last_ack_signal = info->status.ack_signal; } rcu_read_unlock(); -- cgit v0.10.2 From 91b8c050b2a2ed3a1277de53d90e1899f28225e8 Mon Sep 17 00:00:00 2001 From: Saravana Date: Thu, 29 Nov 2012 19:22:37 +0530 Subject: mac80211: add debugfs file for current tx rate Add a debugfs file showing the current tx rate. The information available in the rc_stats file doesn't evidently provides us the current tx rate. This patch adds the support for the same. Signed-off-by: Saravana Signed-off-by: Johannes Berg diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 1566941..b6fd9f6 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -322,6 +322,21 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, } STA_OPS(ht_capa); +static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct rate_info rinfo; + u16 rate; + sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo); + rate = cfg80211_calculate_bitrate(&rinfo); + + return mac80211_format_buffer(userbuf, count, ppos, + "%d.%d MBit/s\n", + rate/10, rate%10); +} +STA_OPS(current_tx_rate); + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -371,6 +386,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(last_signal); DEBUGFS_ADD(ht_capa); DEBUGFS_ADD(last_ack_signal); + DEBUGFS_ADD(current_tx_rate); DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); -- cgit v0.10.2 From 003e676af5044c2168dafbb49c7b8d61dd68cc60 Mon Sep 17 00:00:00 2001 From: Saravana Date: Wed, 28 Nov 2012 18:29:38 +0530 Subject: mac80211: re-organize the rx rate calculation logic Currently the logic to fill a struct rate_info with a STA's last RX rate is accessible only in the cfg.c. As the RX rate calculation might be needed elsewhere, split this out into a separate function. Signed-off-by: Saravana [fix various whitespace issues, reword commit log] Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 97cf615..d645610 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -398,6 +398,38 @@ void sta_set_rate_info_tx(struct sta_info *sta, rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; } +void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) +{ + rinfo->flags = 0; + + if (sta->last_rx_rate_flag & RX_FLAG_HT) { + rinfo->flags |= RATE_INFO_FLAGS_MCS; + rinfo->mcs = sta->last_rx_rate_idx; + } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) { + rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS; + rinfo->nss = sta->last_rx_rate_vht_nss; + rinfo->mcs = sta->last_rx_rate_idx; + } else { + struct ieee80211_supported_band *sband; + + sband = sta->local->hw.wiphy->bands[ + ieee80211_get_sdata_band(sta->sdata)]; + rinfo->legacy = + sband->bitrates[sta->last_rx_rate_idx].bitrate; + } + + if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) + rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) + rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; + if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) + rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) + rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; + if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) + rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; +} + static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; @@ -444,34 +476,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) } sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); - - sinfo->rxrate.flags = 0; - if (sta->last_rx_rate_flag & RX_FLAG_HT) { - sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; - sinfo->rxrate.mcs = sta->last_rx_rate_idx; - } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) { - sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS; - sinfo->rxrate.nss = sta->last_rx_rate_vht_nss; - sinfo->rxrate.mcs = sta->last_rx_rate_idx; - } else { - struct ieee80211_supported_band *sband; - - sband = sta->local->hw.wiphy->bands[ - ieee80211_get_sdata_band(sta->sdata)]; - sinfo->rxrate.legacy = - sband->bitrates[sta->last_rx_rate_idx].bitrate; - } - - if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) - sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; - if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) - sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) - sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; - if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) - sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; - if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) - sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; + sta_set_rate_info_rx(sta, &sinfo->rxrate); if (ieee80211_vif_is_mesh(&sdata->vif)) { #ifdef CONFIG_MAC80211_MESH diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index dce7693..1489bca 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -554,6 +554,8 @@ int sta_info_flush(struct ieee80211_local *local, void sta_set_rate_info_tx(struct sta_info *sta, const struct ieee80211_tx_rate *rate, struct rate_info *rinfo); +void sta_set_rate_info_rx(struct sta_info *sta, + struct rate_info *rinfo); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); -- cgit v0.10.2 From 1f2e651c9aa4be5ace193b6a8f48e4b068a60207 Mon Sep 17 00:00:00 2001 From: Saravana Date: Thu, 29 Nov 2012 19:54:19 +0530 Subject: mac80211: add debugfs file for last rx rate Add a debugfs file showing the rate at which the last packet is received. Signed-off-by: Saravana [fix whitespace] Signed-off-by: Johannes Berg diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index b6fd9f6..49a1c70 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -337,6 +337,23 @@ static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, } STA_OPS(current_tx_rate); +static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct rate_info rinfo; + u16 rate; + + sta_set_rate_info_rx(sta, &rinfo); + + rate = cfg80211_calculate_bitrate(&rinfo); + + return mac80211_format_buffer(userbuf, count, ppos, + "%d.%d MBit/s\n", + rate/10, rate%10); +} +STA_OPS(last_rx_rate); + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -387,6 +404,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(ht_capa); DEBUGFS_ADD(last_ack_signal); DEBUGFS_ADD(current_tx_rate); + DEBUGFS_ADD(last_rx_rate); DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); -- cgit v0.10.2 From c04d61500d706b20361eef02e819b9bed8e92c01 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 29 Nov 2012 18:37:22 +0100 Subject: nl80211: Fix HT_IBSS feature check in ibss_join There is a standalone if, seems to be a regression of commit "nl80211/cfg80211: add VHT MCS support". Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0e7e8d5..4a71977 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5502,6 +5502,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return -EINVAL; if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) + return -EINVAL; ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; -- cgit v0.10.2 From 372039031c62886c8c5b57a7b0111446e9caefa8 Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Fri, 23 Nov 2012 12:23:18 -0800 Subject: mac80211: fix for mesh sync to indicate TBTT adjustment Currently the mesh sync code checks, whether peers indicate TBTT adjustment, but it never sets the corresponding flag itself. By setting ifmsh->tbtt_adjusting to true, it will set the corresponding field in the mesh configuration IE of own beacons. This indication will be set in the current beacon. The TBTT adjustment will be performed afterwards, affecting the next beacon. Thus, the first beacon with stable TBTT will not indicate adjustment anymore and peers will continue tracking the new offset. Signed-off-by: Marco Porsch Signed-off-by: Johannes Berg diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 0f40086..aa8d1e4 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -195,11 +195,15 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) ifmsh->sync_offset_clockdrift_max); set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags); + + ifmsh->adjusting_tbtt = true; } else { msync_dbg(sdata, "TBTT : max clockdrift=%lld; too small to adjust\n", (long long)ifmsh->sync_offset_clockdrift_max); ifmsh->sync_offset_clockdrift_max = 0; + + ifmsh->adjusting_tbtt = false; } spin_unlock_bh(&ifmsh->sync_offset_lock); } -- cgit v0.10.2 From 41e31b8b902397d5d507b275050fcbe8adaf4ff4 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 30 Nov 2012 00:18:12 +0100 Subject: mac80211: allow userspace registration for probe requests in IBSS This change allows userspace to register for probe request frames on an IBSS interface. Userspace then has to handle them and send replies. Signed-off-by: Antonio Quartulli Signed-off-by: Johannes Berg diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c4ed83b..4ece42c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -474,7 +474,8 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { .tx = 0xffff, .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4), + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), }, [NL80211_IFTYPE_STATION] = { .tx = 0xffff, -- cgit v0.10.2 From b629ea3db4c0da4465ffa532914e4a3081f93cdf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Nov 2012 22:14:56 +0100 Subject: cfg80211: don't BUG_ON BSS struct issues There's no need to stop the machine, just leak the BSS entry if there's an issue with its hold counter when freeing. Signed-off-by: Johannes Berg diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9596015..5af431f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -26,6 +26,10 @@ static void bss_release(struct kref *ref) struct cfg80211_internal_bss *bss; bss = container_of(ref, struct cfg80211_internal_bss, ref); + + if (WARN_ON(atomic_read(&bss->hold))) + return; + if (bss->pub.free_priv) bss->pub.free_priv(&bss->pub); @@ -34,8 +38,6 @@ static void bss_release(struct kref *ref) if (bss->proberesp_ies_allocated) kfree(bss->pub.proberesp_ies); - BUG_ON(atomic_read(&bss->hold)); - kfree(bss); } -- cgit v0.10.2 From 915de2ff4a79f1f98362035060777b6c8ce889bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Nov 2012 22:39:37 +0100 Subject: cfg80211: fix whitespace in scan handling Fix a number of indentation and similar issues. Signed-off-by: Johannes Berg diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5af431f..9233910 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -238,9 +238,8 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *bss; unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); - list_for_each_entry(bss, &dev->bss_list, list) { + list_for_each_entry(bss, &dev->bss_list, list) bss->ts -= age_jiffies; - } } void cfg80211_bss_expire(struct cfg80211_registered_device *dev) @@ -309,8 +308,7 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) return memcmp(ie1 + 2, ie2 + 2, ie1[1]); } -static bool is_bss(struct cfg80211_bss *a, - const u8 *bssid, +static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, const u8 *ssid, size_t ssid_len) { const u8 *ssidie; @@ -386,11 +384,10 @@ static bool is_mesh(struct cfg80211_bss *a, * part in the same mesh. */ return memcmp(ie + 2, meshcfg, - sizeof(struct ieee80211_meshconf_ie) - 2) == 0; + sizeof(struct ieee80211_meshconf_ie) - 2) == 0; } -static int cmp_bss_core(struct cfg80211_bss *a, - struct cfg80211_bss *b) +static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) { int r; @@ -435,8 +432,7 @@ static int cmp_bss(struct cfg80211_bss *a, b->len_information_elements); } -static int cmp_hidden_bss(struct cfg80211_bss *a, - struct cfg80211_bss *b) +static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) { const u8 *ie1; const u8 *ie2; @@ -448,11 +444,11 @@ static int cmp_hidden_bss(struct cfg80211_bss *a, return r; ie1 = cfg80211_find_ie(WLAN_EID_SSID, - a->information_elements, - a->len_information_elements); + a->information_elements, + a->len_information_elements); ie2 = cfg80211_find_ie(WLAN_EID_SSID, - b->information_elements, - b->len_information_elements); + b->information_elements, + b->len_information_elements); /* Key comparator must use same algorithm in any rb-tree * search function (order is important), otherwise ordering @@ -602,7 +598,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, static struct cfg80211_internal_bss * rb_find_hidden_bss(struct cfg80211_registered_device *dev, - struct cfg80211_internal_bss *res) + struct cfg80211_internal_bss *res) { struct rb_node *n = dev->bss_tree.rb_node; struct cfg80211_internal_bss *bss; @@ -625,7 +621,7 @@ rb_find_hidden_bss(struct cfg80211_registered_device *dev, static void copy_hidden_ies(struct cfg80211_internal_bss *res, - struct cfg80211_internal_bss *hidden) + struct cfg80211_internal_bss *hidden) { if (unlikely(res->pub.beacon_ies)) return; @@ -639,7 +635,7 @@ copy_hidden_ies(struct cfg80211_internal_bss *res, res->beacon_ies_allocated = true; res->pub.len_beacon_ies = hidden->pub.len_beacon_ies; memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies, - res->pub.len_beacon_ies); + res->pub.len_beacon_ies); } static struct cfg80211_internal_bss * @@ -704,6 +700,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, found->pub.len_information_elements = found->pub.len_proberesp_ies; } + if (res->pub.beacon_ies) { size_t used = dev->wiphy.bss_priv_size + sizeof(*res); size_t ielen = res->pub.len_beacon_ies; -- cgit v0.10.2 From f94f8b168cf2e46da180bbba2afd626d7af0579d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Nov 2012 22:42:34 +0100 Subject: cfg80211: fix cmp_hidden_bss The cmp_bss() comparator function uses memcmp() to compare the SSID. This means that cmp_hidden_bss() needs to similarly return a number bigger than zero (use 1) instead of -1 when ie1 is bigger than ie2, which is the case if an ie2 byte is non-zero. Signed-off-by: Johannes Berg diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9233910..834e0d1 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -450,10 +450,16 @@ static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) b->information_elements, b->len_information_elements); - /* Key comparator must use same algorithm in any rb-tree + /* + * Key comparator must use same algorithm in any rb-tree * search function (order is important), otherwise ordering * of items in the tree is broken and search gives incorrect - * results. This code uses same order as cmp_ies() does. */ + * results. This code uses same order as cmp_ies() does. + * + * Note that due to the differring behaviour with hidden SSIDs + * this function only works when "b" is the tree element and + * "a" is the key we're looking for. + */ /* sort missing IE before (left of) present IE */ if (!ie1) @@ -469,10 +475,14 @@ static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) if (ie1[1] != ie2[1]) return ie2[1] - ie1[1]; - /* zeroed SSID ie is another indication of a hidden bss */ + /* + * zeroed SSID ie is another indication of a hidden bss; + * if it isn't zeroed just return the regular sort value + * to find the next candidate + */ for (i = 0; i < ie2[1]; i++) if (ie2[i + 2]) - return -1; + return memcmp(ie1 + 2, ie2 + 2, ie1[1]); return 0; } -- cgit v0.10.2 From c604b9f219422e969fe371cc7259de34c3c5601d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Nov 2012 12:45:18 +0100 Subject: mac80211: make ieee80211_build_preq_ies safer Instead of assuming 200 bytes are always enough for all the IEs we add, give the length of the buffer to the function and warn instead of overrunning. Signed-off-by: Johannes Berg diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8d8bf71..53e97dc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1034,6 +1034,7 @@ struct ieee80211_local { enum ieee80211_band hw_scan_band; int scan_channel_idx; int scan_ies_len; + int hw_scan_ies_bufsize; struct work_struct sched_scan_stopped_work; struct ieee80211_sub_if_data __rcu *sched_scan_sdata; @@ -1573,7 +1574,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *bssid, u16 stype, u16 reason, bool send_frame, u8 *frame_buf); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - const u8 *ie, size_t ie_len, + size_t buffer_len, const u8 *ie, size_t ie_len, enum ieee80211_band band, u32 rate_mask, u8 channel); struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index ddd1a9a..d7c190b80 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -247,6 +247,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) local->hw_scan_req->n_channels = n_chans; ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, + local->hw_scan_ies_bufsize, req->ie, req->ie_len, band, req->rates[band], 0); local->hw_scan_req->ie_len = ielen; @@ -445,11 +446,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { u8 *ies; + local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + + req->ie_len; local->hw_scan_req = kmalloc( sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]) + - 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + - req->ie_len, GFP_KERNEL); + local->hw_scan_ies_bufsize, GFP_KERNEL); if (!local->hw_scan_req) return -ENOMEM; @@ -928,7 +931,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_sched_scan_ies sched_scan_ies; - int ret, i; + int ret, i, iebufsz; + + iebufsz = 2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + req->ie_len; mutex_lock(&local->mtx); @@ -946,10 +952,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, if (!local->hw.wiphy->bands[i]) continue; - sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + - req->ie_len, - GFP_KERNEL); + sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); if (!sched_scan_ies.ie[i]) { ret = -ENOMEM; goto out_free; @@ -957,8 +960,8 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, sched_scan_ies.len[i] = ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], - req->ie, req->ie_len, i, - (u32) -1, 0); + iebufsz, req->ie, req->ie_len, + i, (u32) -1, 0); } ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6e4c8bd..f119b1b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1107,12 +1107,12 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, } int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - const u8 *ie, size_t ie_len, + size_t buffer_len, const u8 *ie, size_t ie_len, enum ieee80211_band band, u32 rate_mask, u8 channel) { struct ieee80211_supported_band *sband; - u8 *pos; + u8 *pos = buffer, *end = buffer + buffer_len; size_t offset = 0, noffset; int supp_rates_len, i; u8 rates[32]; @@ -1123,8 +1123,6 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, if (WARN_ON_ONCE(!sband)) return 0; - pos = buffer; - num_rates = 0; for (i = 0; i < sband->n_bitrates; i++) { if ((BIT(i) & rate_mask) == 0) @@ -1134,6 +1132,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, supp_rates_len = min_t(int, num_rates, 8); + if (end - pos < 2 + supp_rates_len) + goto out_err; *pos++ = WLAN_EID_SUPP_RATES; *pos++ = supp_rates_len; memcpy(pos, rates, supp_rates_len); @@ -1150,6 +1150,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, before_extrates, ARRAY_SIZE(before_extrates), offset); + if (end - pos < noffset - offset) + goto out_err; memcpy(pos, ie + offset, noffset - offset); pos += noffset - offset; offset = noffset; @@ -1157,6 +1159,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, ext_rates_len = num_rates - supp_rates_len; if (ext_rates_len > 0) { + if (end - pos < 2 + ext_rates_len) + goto out_err; *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos++ = ext_rates_len; memcpy(pos, rates + supp_rates_len, ext_rates_len); @@ -1164,6 +1168,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, } if (channel && sband->band == IEEE80211_BAND_2GHZ) { + if (end - pos < 3) + goto out_err; *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; *pos++ = channel; @@ -1182,14 +1188,19 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, noffset = ieee80211_ie_split(ie, ie_len, before_ht, ARRAY_SIZE(before_ht), offset); + if (end - pos < noffset - offset) + goto out_err; memcpy(pos, ie + offset, noffset - offset); pos += noffset - offset; offset = noffset; } - if (sband->ht_cap.ht_supported) + if (sband->ht_cap.ht_supported) { + if (end - pos < 2 + sizeof(struct ieee80211_ht_cap)) + goto out_err; pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); + } /* * If adding more here, adjust code in main.c @@ -1199,15 +1210,23 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, /* add any remaining custom IEs */ if (ie && ie_len) { noffset = ie_len; + if (end - pos < noffset - offset) + goto out_err; memcpy(pos, ie + offset, noffset - offset); pos += noffset - offset; } - if (sband->vht_cap.vht_supported) + if (sband->vht_cap.vht_supported) { + if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) + goto out_err; pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap); + } return pos - buffer; + out_err: + WARN_ONCE(1, "not enough space for preq IEs\n"); + return pos - buffer; } struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, @@ -1239,7 +1258,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, else chan_no = ieee80211_frequency_to_channel(chan->center_freq); - buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, + buf_len = ieee80211_build_preq_ies(local, buf, 200 + ie_len, + ie, ie_len, chan->band, ratemask, chan_no); skb = ieee80211_probereq_get(&local->hw, &sdata->vif, -- cgit v0.10.2 From b9a9ada14aab17f08c1d9735601f1097cdcfc6de Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Nov 2012 13:00:10 +0100 Subject: mac80211: remove probe response temporary buffer allocation Instead of allocating a temporary buffer to build IEs build them right into the SKB. Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 2aa8a1a..8a61dbd 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1347,9 +1347,14 @@ static void hw_scan_work(struct work_struct *work) hwsim->hw_scan_vif, req->ssids[i].ssid, req->ssids[i].ssid_len, - req->ie, req->ie_len); + req->ie_len); if (!probe) continue; + + if (req->ie_len) + memcpy(skb_put(probe, req->ie_len), req->ie, + req->ie_len); + local_bh_disable(); mac80211_hwsim_tx_frame(hwsim->hw, probe, hwsim->tmp_chan); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 441cbcc..f47e8b0 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -896,11 +896,13 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, goto out; skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, - req->ie, req->ie_len); + req->ie_len); if (!skb) { ret = -ENOMEM; goto out; } + if (req->ie_len) + memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, skb->len); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index eaef3f4..27f83f7 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1038,11 +1038,13 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, - ie, ie_len); + ie_len); if (!skb) { ret = -ENOMEM; goto out; } + if (ie_len) + memcpy(skb_put(skb, ie_len), ie, ie_len); wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e806f1d..0472d80 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3144,8 +3144,7 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @ssid: SSID buffer * @ssid_len: length of SSID - * @ie: buffer containing all IEs except SSID for the template - * @ie_len: length of the IE buffer + * @tailroom: tailroom to reserve at end of SKB for IEs * * Creates a Probe Request template which can, for example, be uploaded to * hardware. @@ -3153,7 +3152,7 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); + size_t tailroom); /** * ieee80211_rts_get - RTS frame generation function diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d8ef341..ba1ac9d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2620,7 +2620,7 @@ EXPORT_SYMBOL(ieee80211_nullfunc_get); struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) + size_t tailroom) { struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local; @@ -2634,7 +2634,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, ie_ssid_len = 2 + ssid_len; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + - ie_ssid_len + ie_len); + ie_ssid_len + tailroom); if (!skb) return NULL; @@ -2655,11 +2655,6 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, memcpy(pos, ssid, ssid_len); pos += ssid_len; - if (ie) { - pos = skb_put(skb, ie_len); - memcpy(pos, ie, ie_len); - } - return skb; } EXPORT_SYMBOL(ieee80211_probereq_get); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f119b1b..41c9841 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1239,14 +1239,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - size_t buf_len; - u8 *buf; u8 chan_no; - - /* FIXME: come up with a proper value */ - buf = kmalloc(200 + ie_len, GFP_KERNEL); - if (!buf) - return NULL; + int ies_len; /* * Do not send DS Channel parameter for directed probe requests @@ -1258,15 +1252,16 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, else chan_no = ieee80211_frequency_to_channel(chan->center_freq); - buf_len = ieee80211_build_preq_ies(local, buf, 200 + ie_len, - ie, ie_len, chan->band, - ratemask, chan_no); - skb = ieee80211_probereq_get(&local->hw, &sdata->vif, - ssid, ssid_len, - buf, buf_len); + ssid, ssid_len, 100 + ie_len); if (!skb) - goto out; + return NULL; + + ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), + skb_tailroom(skb), + ie, ie_len, chan->band, + ratemask, chan_no); + skb_put(skb, ies_len); if (dst) { mgmt = (struct ieee80211_mgmt *) skb->data; @@ -1276,9 +1271,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - out: - kfree(buf); - return skb; } -- cgit v0.10.2 From 9caf03640279e64d0ba36539b42daa1b43a49486 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Nov 2012 01:25:20 +0100 Subject: cfg80211: fix BSS struct IE access races When a BSS struct is updated, the IEs are currently overwritten or freed. This can lead to races if some other CPU is accessing the BSS struct and using the IEs concurrently. Fix this by always allocating the IEs in a new struct that holds the data and length and protecting access to this new struct with RCU. Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index ec36868..ec6d5d6 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -298,6 +298,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss) const u8 *rates_eid, *ext_rates_eid; int n = 0; + rcu_read_lock(); rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); @@ -325,6 +326,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss) *tlv++ = 0x96; n = 4; } + rcu_read_unlock(); rate_tlv->header.len = cpu_to_le16(n); return sizeof(rate_tlv->header) + n; @@ -1140,11 +1142,13 @@ static int lbs_associate(struct lbs_private *priv, cmd->capability = cpu_to_le16(bss->capability); /* add SSID TLV */ + rcu_read_lock(); ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); if (ssid_eid) pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); else lbs_deb_assoc("no SSID\n"); + rcu_read_unlock(); /* add DS param TLV */ if (bss->channel) @@ -1782,7 +1786,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, struct cfg80211_ibss_params *params, struct cfg80211_bss *bss) { - const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); + const u8 *rates_eid; struct cmd_ds_802_11_ad_hoc_join cmd; u8 preamble = RADIO_PREAMBLE_SHORT; int ret = 0; @@ -1841,6 +1845,8 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, /* set rates to the intersection of our rates and the rates in the bss */ + rcu_read_lock(); + rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); if (!rates_eid) { lbs_add_rates(cmd.bss.rates); } else { @@ -1860,6 +1866,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, } } } + rcu_read_unlock(); /* Only v8 and below support setting this */ if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) { diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 24af6ba..5d7b83e 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -158,12 +158,22 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, struct cfg80211_bss *bss, struct mwifiex_bssdescriptor *bss_desc) { - int ret; + int ret, beacon_ie_len; u8 *beacon_ie; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; + const struct cfg80211_bss_ies *ies; + + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + if (WARN_ON(!ies)) { + /* should never happen */ + rcu_read_unlock(); + return -EINVAL; + } + beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); + beacon_ie_len = ies->len; + rcu_read_unlock(); - beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies, - GFP_KERNEL); if (!beacon_ie) { dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); return -ENOMEM; @@ -172,7 +182,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); bss_desc->rssi = bss->signal; bss_desc->beacon_buf = beacon_ie; - bss_desc->beacon_buf_size = bss->len_beacon_ies; + bss_desc->beacon_buf_size = beacon_ie_len; bss_desc->beacon_period = bss->beacon_interval; bss_desc->cap_info_bitmap = bss->capability; bss_desc->bss_band = bss_priv->band; @@ -198,18 +208,23 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { - u8 *country_ie, country_ie_len; + const u8 *country_ie; + u8 country_ie_len; struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; - country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); - - if (!country_ie) + rcu_read_lock(); + country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + if (!country_ie) { + rcu_read_unlock(); return 0; + } country_ie_len = country_ie[1]; - if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) + if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) { + rcu_read_unlock(); return 0; + } domain_info->country_code[0] = country_ie[2]; domain_info->country_code[1] = country_ie[3]; @@ -223,6 +238,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, memcpy((u8 *)domain_info->triplet, &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); + rcu_read_unlock(); + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(priv->adapter->wiphy, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 731b48f..8e6a6b7 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1206,6 +1206,18 @@ enum cfg80211_signal_type { }; /** + * struct cfg80211_bss_ie_data - BSS entry IE data + * @rcu_head: internal use, for freeing + * @len: length of the IEs + * @data: IE data + */ +struct cfg80211_bss_ies { + struct rcu_head rcu_head; + int len; + u8 data[]; +}; + +/** * struct cfg80211_bss - BSS description * * This structure describes a BSS (which may also be a mesh network) @@ -1216,36 +1228,34 @@ enum cfg80211_signal_type { * @tsf: timestamp of last received update * @beacon_interval: the beacon interval as from the frame * @capability: the capability field in host byte order - * @information_elements: the information elements (Note that there + * @ies: the information elements (Note that there * is no guarantee that these are well-formed!); this is a pointer to * either the beacon_ies or proberesp_ies depending on whether Probe * Response frame has been received - * @len_information_elements: total length of the information elements * @beacon_ies: the information elements from the last Beacon frame - * @len_beacon_ies: total length of the beacon_ies * @proberesp_ies: the information elements from the last Probe Response frame - * @len_proberesp_ies: total length of the proberesp_ies * @signal: signal strength value (type depends on the wiphy's signal_type) * @free_priv: function pointer to free private data * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes */ struct cfg80211_bss { + u64 tsf; + struct ieee80211_channel *channel; - u8 bssid[ETH_ALEN]; - u64 tsf; + const struct cfg80211_bss_ies __rcu *ies; + const struct cfg80211_bss_ies __rcu *beacon_ies; + const struct cfg80211_bss_ies __rcu *proberesp_ies; + + void (*free_priv)(struct cfg80211_bss *bss); + + s32 signal; + u16 beacon_interval; u16 capability; - u8 *information_elements; - size_t len_information_elements; - u8 *beacon_ies; - size_t len_beacon_ies; - u8 *proberesp_ies; - size_t len_proberesp_ies; - s32 signal; + u8 bssid[ETH_ALEN]; - void (*free_priv)(struct cfg80211_bss *bss); u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); }; @@ -1253,6 +1263,9 @@ struct cfg80211_bss { * ieee80211_bss_get_ie - find IE with given ID * @bss: the bss to search * @ie: the IE ID + * + * Note that the return value is an RCU-protected pointer, so + * rcu_read_lock() must be held when calling this function. * Returns %NULL if not found. */ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 35d8cff..481d503 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1382,19 +1382,26 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; if (sdata->vif.p2p) { - u8 noa[2]; - int ret; + const struct cfg80211_bss_ies *ies; - ret = cfg80211_get_p2p_attr(cbss->information_elements, - cbss->len_information_elements, - IEEE80211_P2P_ATTR_ABSENCE_NOTICE, - noa, sizeof(noa)); - if (ret >= 2) { - bss_conf->p2p_oppps = noa[1] & 0x80; - bss_conf->p2p_ctwindow = noa[1] & 0x7f; - bss_info_changed |= BSS_CHANGED_P2P_PS; - sdata->u.mgd.p2p_noa_index = noa[0]; + rcu_read_lock(); + ies = rcu_dereference(cbss->ies); + if (ies) { + u8 noa[2]; + int ret; + + ret = cfg80211_get_p2p_attr( + ies->data, ies->len, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + noa, sizeof(noa)); + if (ret >= 2) { + bss_conf->p2p_oppps = noa[1] & 0x80; + bss_conf->p2p_ctwindow = noa[1] & 0x7f; + bss_info_changed |= BSS_CHANGED_P2P_PS; + sdata->u.mgd.p2p_noa_index = noa[0]; + } } + rcu_read_unlock(); } /* just to be sure */ @@ -1659,6 +1666,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) } else { int ssid_len; + rcu_read_lock(); ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); if (WARN_ON_ONCE(ssid == NULL)) ssid_len = 0; @@ -1668,6 +1676,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, 0, (u32) -1, true, false, ifmgd->associated->channel, false); + rcu_read_unlock(); } ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); @@ -1763,6 +1772,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, else return NULL; + rcu_read_lock(); ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); if (WARN_ON_ONCE(ssid == NULL)) ssid_len = 0; @@ -1773,6 +1783,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, (u32) -1, cbss->channel, ssid + 2, ssid_len, NULL, 0, true); + rcu_read_unlock(); return skb; } @@ -2858,9 +2869,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) auth_data->bss->bssid, auth_data->tries, IEEE80211_AUTH_MAX_TRIES); + rcu_read_lock(); ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); - if (!ssidie) + if (!ssidie) { + rcu_read_unlock(); return -EINVAL; + } /* * Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. @@ -2868,6 +2882,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], NULL, 0, (u32) -1, true, false, auth_data->bss->channel, false); + rcu_read_unlock(); } auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; @@ -3404,9 +3419,7 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, if (ifmgd->flags & IEEE80211_STA_DISABLE_HT) return chains; - ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, - cbss->information_elements, - cbss->len_information_elements); + ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { ht_cap = (void *)(ht_cap_ie + 2); chains = ieee80211_mcs_to_chains(&ht_cap->mcs); @@ -3419,9 +3432,7 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) return chains; - vht_cap_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, - cbss->information_elements, - cbss->len_information_elements); + vht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY); if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) { u8 nss; u16 tx_mcs_map; @@ -3457,13 +3468,13 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, IEEE80211_STA_DISABLE_80P80MHZ | IEEE80211_STA_DISABLE_160MHZ); + rcu_read_lock(); + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && sband->ht_cap.ht_supported) { const u8 *ht_oper_ie; - ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, - cbss->information_elements, - cbss->len_information_elements); + ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) ht_oper = (void *)(ht_oper_ie + 2); } @@ -3472,9 +3483,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, sband->vht_cap.vht_supported) { const u8 *vht_oper_ie; - vht_oper_ie = cfg80211_find_ie(WLAN_EID_VHT_OPERATION, - cbss->information_elements, - cbss->len_information_elements); + vht_oper_ie = ieee80211_bss_get_ie(cbss, + WLAN_EID_VHT_OPERATION); if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper)) vht_oper = (void *)(vht_oper_ie + 2); if (vht_oper && !ht_oper) { @@ -3494,6 +3504,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), local->rx_chains); + rcu_read_unlock(); + /* will change later if needed */ sdata->smps_mode = IEEE80211_SMPS_OFF; @@ -3734,14 +3746,21 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, const u8 *ssidie, *ht_ie; int i, err; - ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - if (!ssidie) - return -EINVAL; - assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); if (!assoc_data) return -ENOMEM; + rcu_read_lock(); + ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + if (!ssidie) { + rcu_read_unlock(); + kfree(assoc_data); + return -EINVAL; + } + memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); + assoc_data->ssid_len = ssidie[1]; + rcu_read_unlock(); + mutex_lock(&ifmgd->mtx); if (ifmgd->associated) @@ -3836,12 +3855,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->supp_rates = bss->supp_rates; assoc_data->supp_rates_len = bss->supp_rates_len; + rcu_read_lock(); ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) assoc_data->ap_ht_param = ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; else ifmgd->flags |= IEEE80211_STA_DISABLE_HT; + rcu_read_unlock(); if (bss->wmm_used && bss->uapsd_supported && (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { @@ -3852,9 +3873,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; } - memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); - assoc_data->ssid_len = ssidie[1]; - if (req->prev_bssid) memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); diff --git a/net/wireless/core.h b/net/wireless/core.h index 6183a0d..3563097 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -138,8 +138,6 @@ struct cfg80211_internal_bss { unsigned long ts; struct kref ref; atomic_t hold; - bool beacon_ies_allocated; - bool proberesp_ies_allocated; /* must be last because of priv member */ struct cfg80211_bss pub; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4a71977..f45706a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4808,6 +4808,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, struct cfg80211_internal_bss *intbss) { struct cfg80211_bss *res = &intbss->pub; + const struct cfg80211_bss_ies *ies; void *hdr; struct nlattr *bss; @@ -4828,16 +4829,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, if (!bss) goto nla_put_failure; if ((!is_zero_ether_addr(res->bssid) && - nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)) || - (res->information_elements && res->len_information_elements && - nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, - res->len_information_elements, - res->information_elements)) || - (res->beacon_ies && res->len_beacon_ies && - res->beacon_ies != res->information_elements && - nla_put(msg, NL80211_BSS_BEACON_IES, - res->len_beacon_ies, res->beacon_ies))) + nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid))) goto nla_put_failure; + + rcu_read_lock(); + ies = rcu_dereference(res->ies); + if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, + ies->len, ies->data)) { + rcu_read_unlock(); + goto nla_put_failure; + } + ies = rcu_dereference(res->beacon_ies); + if (ies && ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, + ies->len, ies->data)) { + rcu_read_unlock(); + goto nla_put_failure; + } + rcu_read_unlock(); + if (res->tsf && nla_put_u64(msg, NL80211_BSS_TSF, res->tsf)) goto nla_put_failure; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bcc7d7e..b6c7ea6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1797,7 +1797,7 @@ EXPORT_SYMBOL(regulatory_hint); */ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, - u8 *country_ie, + const u8 *country_ie, u8 country_ie_len) { char alpha2[2]; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index f023c8a..4c0a32f 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -81,7 +81,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, */ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, - u8 *country_ie, + const u8 *country_ie, u8 country_ie_len); /** diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 834e0d1..01592d7 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -23,6 +23,7 @@ static void bss_release(struct kref *ref) { + struct cfg80211_bss_ies *ies; struct cfg80211_internal_bss *bss; bss = container_of(ref, struct cfg80211_internal_bss, ref); @@ -33,10 +34,12 @@ static void bss_release(struct kref *ref) if (bss->pub.free_priv) bss->pub.free_priv(&bss->pub); - if (bss->beacon_ies_allocated) - kfree(bss->pub.beacon_ies); - if (bss->proberesp_ies_allocated) - kfree(bss->pub.proberesp_ies); + ies = (void *)rcu_access_pointer(bss->pub.beacon_ies); + if (ies) + kfree_rcu(ies, rcu_head); + ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies); + if (ies) + kfree_rcu(ies, rcu_head); kfree(bss); } @@ -288,7 +291,7 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, } EXPORT_SYMBOL(cfg80211_find_vendor_ie); -static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) +static int cmp_ies(u8 num, const u8 *ies1, int len1, const u8 *ies2, int len2) { const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); @@ -311,6 +314,7 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, const u8 *ssid, size_t ssid_len) { + const struct cfg80211_bss_ies *ies; const u8 *ssidie; if (bssid && !ether_addr_equal(a->bssid, bssid)) @@ -319,9 +323,10 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, if (!ssid) return true; - ssidie = cfg80211_find_ie(WLAN_EID_SSID, - a->information_elements, - a->len_information_elements); + ies = rcu_access_pointer(a->ies); + if (!ies) + return false; + ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); if (!ssidie) return false; if (ssidie[1] != ssid_len) @@ -331,20 +336,21 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, static bool is_mesh_bss(struct cfg80211_bss *a) { + const struct cfg80211_bss_ies *ies; const u8 *ie; if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) return false; - ie = cfg80211_find_ie(WLAN_EID_MESH_ID, - a->information_elements, - a->len_information_elements); + ies = rcu_access_pointer(a->ies); + if (!ies) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, ies->data, ies->len); if (!ie) return false; - ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, - a->information_elements, - a->len_information_elements); + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, ies->data, ies->len); if (!ie) return false; @@ -355,14 +361,17 @@ static bool is_mesh(struct cfg80211_bss *a, const u8 *meshid, size_t meshidlen, const u8 *meshcfg) { + const struct cfg80211_bss_ies *ies; const u8 *ie; if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) return false; - ie = cfg80211_find_ie(WLAN_EID_MESH_ID, - a->information_elements, - a->len_information_elements); + ies = rcu_access_pointer(a->ies); + if (!ies) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, ies->data, ies->len); if (!ie) return false; if (ie[1] != meshidlen) @@ -370,9 +379,7 @@ static bool is_mesh(struct cfg80211_bss *a, if (memcmp(ie + 2, meshid, meshidlen)) return false; - ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, - a->information_elements, - a->len_information_elements); + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, ies->data, ies->len); if (!ie) return false; if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) @@ -389,24 +396,28 @@ static bool is_mesh(struct cfg80211_bss *a, static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) { + const struct cfg80211_bss_ies *a_ies, *b_ies; int r; if (a->channel != b->channel) return b->channel->center_freq - a->channel->center_freq; if (is_mesh_bss(a) && is_mesh_bss(b)) { + a_ies = rcu_access_pointer(a->ies); + if (!a_ies) + return -1; + b_ies = rcu_access_pointer(b->ies); + if (!b_ies) + return 1; + r = cmp_ies(WLAN_EID_MESH_ID, - a->information_elements, - a->len_information_elements, - b->information_elements, - b->len_information_elements); + a_ies->data, a_ies->len, + b_ies->data, b_ies->len); if (r) return r; return cmp_ies(WLAN_EID_MESH_CONFIG, - a->information_elements, - a->len_information_elements, - b->information_elements, - b->len_information_elements); + a_ies->data, a_ies->len, + b_ies->data, b_ies->len); } /* @@ -419,21 +430,28 @@ static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) static int cmp_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) { + const struct cfg80211_bss_ies *a_ies, *b_ies; int r; r = cmp_bss_core(a, b); if (r) return r; + a_ies = rcu_access_pointer(a->ies); + if (!a_ies) + return -1; + b_ies = rcu_access_pointer(b->ies); + if (!b_ies) + return 1; + return cmp_ies(WLAN_EID_SSID, - a->information_elements, - a->len_information_elements, - b->information_elements, - b->len_information_elements); + a_ies->data, a_ies->len, + b_ies->data, b_ies->len); } static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) { + const struct cfg80211_bss_ies *a_ies, *b_ies; const u8 *ie1; const u8 *ie2; int i; @@ -443,12 +461,15 @@ static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) if (r) return r; - ie1 = cfg80211_find_ie(WLAN_EID_SSID, - a->information_elements, - a->len_information_elements); - ie2 = cfg80211_find_ie(WLAN_EID_SSID, - b->information_elements, - b->len_information_elements); + a_ies = rcu_access_pointer(a->ies); + if (!a_ies) + return -1; + b_ies = rcu_access_pointer(b->ies); + if (!b_ies) + return 1; + + ie1 = cfg80211_find_ie(WLAN_EID_SSID, a_ies->data, a_ies->len); + ie2 = cfg80211_find_ie(WLAN_EID_SSID, b_ies->data, b_ies->len); /* * Key comparator must use same algorithm in any rb-tree @@ -633,126 +654,84 @@ static void copy_hidden_ies(struct cfg80211_internal_bss *res, struct cfg80211_internal_bss *hidden) { - if (unlikely(res->pub.beacon_ies)) - return; - if (WARN_ON(!hidden->pub.beacon_ies)) + const struct cfg80211_bss_ies *ies; + + if (rcu_access_pointer(res->pub.beacon_ies)) return; - res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC); - if (unlikely(!res->pub.beacon_ies)) + ies = rcu_access_pointer(hidden->pub.beacon_ies); + if (WARN_ON(!ies)) return; - res->beacon_ies_allocated = true; - res->pub.len_beacon_ies = hidden->pub.len_beacon_ies; - memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies, - res->pub.len_beacon_ies); + ies = kmemdup(ies, sizeof(*ies) + ies->len, GFP_ATOMIC); + if (unlikely(!ies)) + return; + rcu_assign_pointer(res->pub.beacon_ies, ies); } static struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *dev, - struct cfg80211_internal_bss *res) + struct cfg80211_internal_bss *tmp) { struct cfg80211_internal_bss *found = NULL; - /* - * The reference to "res" is donated to this function. - */ - - if (WARN_ON(!res->pub.channel)) { - kref_put(&res->ref, bss_release); + if (WARN_ON(!tmp->pub.channel)) return NULL; - } - res->ts = jiffies; + tmp->ts = jiffies; spin_lock_bh(&dev->bss_lock); - found = rb_find_bss(dev, res); + if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) { + spin_unlock_bh(&dev->bss_lock); + return NULL; + } + + found = rb_find_bss(dev, tmp); if (found) { - found->pub.beacon_interval = res->pub.beacon_interval; - found->pub.tsf = res->pub.tsf; - found->pub.signal = res->pub.signal; - found->pub.capability = res->pub.capability; - found->ts = res->ts; + found->pub.beacon_interval = tmp->pub.beacon_interval; + found->pub.tsf = tmp->pub.tsf; + found->pub.signal = tmp->pub.signal; + found->pub.capability = tmp->pub.capability; + found->ts = tmp->ts; /* Update IEs */ - if (res->pub.proberesp_ies) { - size_t used = dev->wiphy.bss_priv_size + sizeof(*res); - size_t ielen = res->pub.len_proberesp_ies; - - if (found->pub.proberesp_ies && - !found->proberesp_ies_allocated && - ksize(found) >= used + ielen) { - memcpy(found->pub.proberesp_ies, - res->pub.proberesp_ies, ielen); - found->pub.len_proberesp_ies = ielen; - } else { - u8 *ies = found->pub.proberesp_ies; - - if (found->proberesp_ies_allocated) - ies = krealloc(ies, ielen, GFP_ATOMIC); - else - ies = kmalloc(ielen, GFP_ATOMIC); - - if (ies) { - memcpy(ies, res->pub.proberesp_ies, - ielen); - found->proberesp_ies_allocated = true; - found->pub.proberesp_ies = ies; - found->pub.len_proberesp_ies = ielen; - } - } + if (rcu_access_pointer(tmp->pub.proberesp_ies)) { + const struct cfg80211_bss_ies *old; + + old = rcu_access_pointer(found->pub.proberesp_ies); + rcu_assign_pointer(found->pub.proberesp_ies, + tmp->pub.proberesp_ies); /* Override possible earlier Beacon frame IEs */ - found->pub.information_elements = - found->pub.proberesp_ies; - found->pub.len_information_elements = - found->pub.len_proberesp_ies; - } + rcu_assign_pointer(found->pub.ies, + tmp->pub.proberesp_ies); + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, + rcu_head); + } else if (rcu_access_pointer(tmp->pub.beacon_ies)) { + const struct cfg80211_bss_ies *old, *ies; - if (res->pub.beacon_ies) { - size_t used = dev->wiphy.bss_priv_size + sizeof(*res); - size_t ielen = res->pub.len_beacon_ies; - bool information_elements_is_beacon_ies = - (found->pub.information_elements == - found->pub.beacon_ies); - - if (found->pub.beacon_ies && - !found->beacon_ies_allocated && - ksize(found) >= used + ielen) { - memcpy(found->pub.beacon_ies, - res->pub.beacon_ies, ielen); - found->pub.len_beacon_ies = ielen; - } else { - u8 *ies = found->pub.beacon_ies; - - if (found->beacon_ies_allocated) - ies = krealloc(ies, ielen, GFP_ATOMIC); - else - ies = kmalloc(ielen, GFP_ATOMIC); - - if (ies) { - memcpy(ies, res->pub.beacon_ies, - ielen); - found->beacon_ies_allocated = true; - found->pub.beacon_ies = ies; - found->pub.len_beacon_ies = ielen; - } - } + old = rcu_access_pointer(found->pub.beacon_ies); + ies = rcu_access_pointer(found->pub.ies); + + rcu_assign_pointer(found->pub.beacon_ies, + tmp->pub.beacon_ies); /* Override IEs if they were from a beacon before */ - if (information_elements_is_beacon_ies) { - found->pub.information_elements = - found->pub.beacon_ies; - found->pub.len_information_elements = - found->pub.len_beacon_ies; - } - } + if (old == ies) + rcu_assign_pointer(found->pub.ies, + tmp->pub.beacon_ies); - kref_put(&res->ref, bss_release); + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, + rcu_head); + } } else { + struct cfg80211_internal_bss *new; struct cfg80211_internal_bss *hidden; + struct cfg80211_bss_ies *ies; /* First check if the beacon is a probe response from * a hidden bss. If so, copy beacon ies (with nullified @@ -763,14 +742,32 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, /* TODO: The code is not trying to update existing probe * response bss entries when beacon ies are * getting changed. */ - hidden = rb_find_hidden_bss(dev, res); + hidden = rb_find_hidden_bss(dev, tmp); if (hidden) - copy_hidden_ies(res, hidden); - - /* this "consumes" the reference */ - list_add_tail(&res->list, &dev->bss_list); - rb_insert_bss(dev, res); - found = res; + copy_hidden_ies(tmp, hidden); + + /* + * create a copy -- the "res" variable that is passed in + * is allocated on the stack since it's not needed in the + * more common case of an update + */ + new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size, + GFP_ATOMIC); + if (!new) { + ies = (void *)rcu_dereference(tmp->pub.beacon_ies); + if (ies) + kfree_rcu(ies, rcu_head); + ies = (void *)rcu_dereference(tmp->pub.proberesp_ies); + if (ies) + kfree_rcu(ies, rcu_head); + spin_unlock_bh(&dev->bss_lock); + return NULL; + } + memcpy(new, tmp, sizeof(*new)); + kref_init(&new->ref); + list_add_tail(&new->list, &dev->bss_list); + rb_insert_bss(dev, new); + found = new; } dev->bss_generation++; @@ -819,14 +816,12 @@ cfg80211_inform_bss(struct wiphy *wiphy, u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp) { - struct cfg80211_internal_bss *res; - size_t privsz; + struct cfg80211_bss_ies *ies; + struct cfg80211_internal_bss tmp = {}, *res; if (WARN_ON(!wiphy)) return NULL; - privsz = wiphy->bss_priv_size; - if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && (signal < 0 || signal > 100))) return NULL; @@ -835,36 +830,33 @@ cfg80211_inform_bss(struct wiphy *wiphy, if (!channel) return NULL; - res = kzalloc(sizeof(*res) + privsz + ielen, gfp); - if (!res) - return NULL; - - memcpy(res->pub.bssid, bssid, ETH_ALEN); - res->pub.channel = channel; - res->pub.signal = signal; - res->pub.tsf = tsf; - res->pub.beacon_interval = beacon_interval; - res->pub.capability = capability; + memcpy(tmp.pub.bssid, bssid, ETH_ALEN); + tmp.pub.channel = channel; + tmp.pub.signal = signal; + tmp.pub.tsf = tsf; + tmp.pub.beacon_interval = beacon_interval; + tmp.pub.capability = capability; /* * Since we do not know here whether the IEs are from a Beacon or Probe * Response frame, we need to pick one of the options and only use it * with the driver that does not provide the full Beacon/Probe Response * frame. Use Beacon frame pointer to avoid indicating that this should - * override the information_elements pointer should we have received an - * earlier indication of Probe Response data. + * override the iies pointer should we have received an earlier + * indication of Probe Response data. * * The initial buffer for the IEs is allocated with the BSS entry and * is located after the private area. */ - res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; - memcpy(res->pub.beacon_ies, ie, ielen); - res->pub.len_beacon_ies = ielen; - res->pub.information_elements = res->pub.beacon_ies; - res->pub.len_information_elements = res->pub.len_beacon_ies; + ies = kmalloc(sizeof(*ies) + ielen, gfp); + if (!ies) + return NULL; + ies->len = ielen; + memcpy(ies->data, ie, ielen); - kref_init(&res->ref); + rcu_assign_pointer(tmp.pub.beacon_ies, ies); + rcu_assign_pointer(tmp.pub.ies, ies); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); + res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); if (!res) return NULL; @@ -883,10 +875,10 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, s32 signal, gfp_t gfp) { - struct cfg80211_internal_bss *res; + struct cfg80211_internal_bss tmp = {}, *res; + struct cfg80211_bss_ies *ies; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - size_t privsz; BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != offsetof(struct ieee80211_mgmt, u.beacon.variable)); @@ -906,45 +898,31 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) return NULL; - privsz = wiphy->bss_priv_size; - channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, ielen, channel); if (!channel) return NULL; - res = kzalloc(sizeof(*res) + privsz + ielen, gfp); - if (!res) + ies = kmalloc(sizeof(*ies) + ielen, gfp); + if (!ies) return NULL; + ies->len = ielen; + memcpy(ies->data, mgmt->u.probe_resp.variable, ielen); - memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); - res->pub.channel = channel; - res->pub.signal = signal; - res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); - res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); - res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); - /* - * The initial buffer for the IEs is allocated with the BSS entry and - * is located after the private area. - */ - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; - memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, - ielen); - res->pub.len_proberesp_ies = ielen; - res->pub.information_elements = res->pub.proberesp_ies; - res->pub.len_information_elements = res->pub.len_proberesp_ies; - } else { - res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; - memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); - res->pub.len_beacon_ies = ielen; - res->pub.information_elements = res->pub.beacon_ies; - res->pub.len_information_elements = res->pub.len_beacon_ies; - } - - kref_init(&res->ref); - - res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); + if (ieee80211_is_probe_resp(mgmt->frame_control)) + rcu_assign_pointer(tmp.pub.proberesp_ies, ies); + else + rcu_assign_pointer(tmp.pub.beacon_ies, ies); + rcu_assign_pointer(tmp.pub.ies, ies); + + memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); + tmp.pub.channel = channel; + tmp.pub.signal = signal; + tmp.pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); + tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); + + res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); if (!res) return NULL; @@ -1136,22 +1114,21 @@ int cfg80211_wext_siwscan(struct net_device *dev, EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); static void ieee80211_scan_add_ies(struct iw_request_info *info, - struct cfg80211_bss *bss, + const struct cfg80211_bss_ies *ies, char **current_ev, char *end_buf) { - u8 *pos, *end, *next; + const u8 *pos, *end, *next; struct iw_event iwe; - if (!bss->information_elements || - !bss->len_information_elements) + if (!ies) return; /* * If needed, fragment the IEs buffer (at IE boundaries) into short * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. */ - pos = bss->information_elements; - end = pos + bss->len_information_elements; + pos = ies->data; + end = pos + ies->len; while (end - pos > IW_GENERIC_IE_MAX) { next = pos + 2 + pos[1]; @@ -1162,7 +1139,8 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, iwe.cmd = IWEVGENIE; iwe.u.data.length = next - pos; *current_ev = iwe_stream_add_point(info, *current_ev, - end_buf, &iwe, pos); + end_buf, &iwe, + (void *)pos); pos = next; } @@ -1172,7 +1150,8 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, iwe.cmd = IWEVGENIE; iwe.u.data.length = end - pos; *current_ev = iwe_stream_add_point(info, *current_ev, - end_buf, &iwe, pos); + end_buf, &iwe, + (void *)pos); } } @@ -1191,10 +1170,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, struct cfg80211_internal_bss *bss, char *current_ev, char *end_buf) { + const struct cfg80211_bss_ies *ies; struct iw_event iwe; + const u8 *ie; u8 *buf, *cfg, *p; - u8 *ie = bss->pub.information_elements; - int rem = bss->pub.len_information_elements, i, sig; + int rem, i, sig; bool ismesh = false; memset(&iwe, 0, sizeof(iwe)); @@ -1259,7 +1239,17 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); - while (rem >= 2) { + rcu_read_lock(); + ies = rcu_dereference(bss->pub.ies); + if (ies) { + rem = ies->len; + ie = ies->data; + } else { + rem = 0; + ie = NULL; + } + + while (ies && rem >= 2) { /* invalid data */ if (ie[1] > rem - 2) break; @@ -1271,7 +1261,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, iwe.u.data.length = ie[1]; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie + 2); + &iwe, (u8 *)ie + 2); break; case WLAN_EID_MESH_ID: memset(&iwe, 0, sizeof(iwe)); @@ -1279,7 +1269,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, iwe.u.data.length = ie[1]; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ie + 2); + &iwe, (u8 *)ie + 2); break; case WLAN_EID_MESH_CONFIG: ismesh = true; @@ -1288,7 +1278,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, buf = kmalloc(50, GFP_ATOMIC); if (!buf) break; - cfg = ie + 2; + cfg = (u8 *)ie + 2; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "Mesh Network Path Selection Protocol ID: " @@ -1386,7 +1376,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, kfree(buf); } - ieee80211_scan_add_ies(info, &bss->pub, ¤t_ev, end_buf); + ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf); + rcu_read_unlock(); return current_ev; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index c749002..f2431e4 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -417,7 +417,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, struct cfg80211_bss *bss) { struct wireless_dev *wdev = dev->ieee80211_ptr; - u8 *country_ie; + const u8 *country_ie; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -501,7 +501,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, wdev->sme_state = CFG80211_SME_CONNECTED; cfg80211_upload_connect_keys(wdev); - country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + rcu_read_lock(); + country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); + if (!country_ie) { + rcu_read_unlock(); + return; + } + + country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC); + rcu_read_unlock(); if (!country_ie) return; @@ -515,6 +523,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, bss->channel->band, country_ie + 2, country_ie[1]); + kfree(country_ie); } void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, diff --git a/net/wireless/util.c b/net/wireless/util.c index 3cce6e4..16d76a8 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -688,10 +688,13 @@ EXPORT_SYMBOL(cfg80211_classify8021d); const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) { - if (bss->information_elements == NULL) + const struct cfg80211_bss_ies *ies; + + ies = rcu_dereference(bss->ies); + if (!ies) return NULL; - return cfg80211_find_ie(ie, bss->information_elements, - bss->len_information_elements); + + return cfg80211_find_ie(ie, ies->data, ies->len); } EXPORT_SYMBOL(ieee80211_bss_get_ie); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 873af63..fb9622f 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -242,13 +242,17 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) { - const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, - WLAN_EID_SSID); + const u8 *ie; + + rcu_read_lock(); + ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, + WLAN_EID_SSID); if (ie) { data->flags = 1; data->length = ie[1]; memcpy(ssid, ie + 2, data->length); } + rcu_read_unlock(); } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { data->flags = 1; data->length = wdev->wext.connect.ssid_len; -- cgit v0.10.2 From a544ab7f9c09df591758931301a7c509bba6c913 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Nov 2012 21:36:27 +0100 Subject: mac80211: simplify loop in minstrel_ht Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index fb1d4aa..9f9c453 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -389,9 +389,9 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_tx_rate *ar = info->status.rates; struct minstrel_rate_stats *rate, *rate2; struct minstrel_priv *mp = priv; - bool last = false; + bool last; int group; - int i = 0; + int i; if (!msp->is_ht) return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb); @@ -419,13 +419,11 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) mi->sample_packets += info->status.ampdu_len; + last = !minstrel_ht_txstat_valid(&ar[0]); for (i = 0; !last; i++) { last = (i == IEEE80211_TX_MAX_RATES - 1) || !minstrel_ht_txstat_valid(&ar[i + 1]); - if (!minstrel_ht_txstat_valid(&ar[i])) - break; - group = minstrel_ht_get_group_idx(&ar[i]); rate = &mi->groups[group].rates[ar[i].idx % 8]; -- cgit v0.10.2 From 4a7267c9a03b9627e5e85c80b307eb4541bab902 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 27 Nov 2012 00:30:04 +0100 Subject: bcma: handle return value of pci_assign_resource This fixes the following warning: CC drivers/bcma/driver_pci_host.o drivers/bcma/driver_pci_host.c: In function 'bcma_core_pci_fixup_addresses': drivers/bcma/driver_pci_host.c:555:23: error: ignoring return value of 'pci_assign_resource', declared with attribute warn_unused_result [-Werror=unused-result] Reported-by: Arend van Spriel Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index e564495..e6b5c89 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -538,7 +538,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_pcibridge); static void bcma_core_pci_fixup_addresses(struct pci_dev *dev) { struct resource *res; - int pos; + int pos, err; if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) { /* This is not a device on the PCI-core bridge. */ @@ -551,8 +551,12 @@ static void bcma_core_pci_fixup_addresses(struct pci_dev *dev) for (pos = 0; pos < 6; pos++) { res = &dev->resource[pos]; - if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) - pci_assign_resource(dev, pos); + if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) { + err = pci_assign_resource(dev, pos); + if (err) + pr_err("PCI: Problem fixing up the addresses on %s\n", + pci_name(dev)); + } } } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses); -- cgit v0.10.2 From 0362063b7be97f6f8e2c644b970f5726489aacdf Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 27 Nov 2012 00:31:55 +0100 Subject: ssb: extif: fix compile errors If CONFIG_SSB_EMBEDDED or CONFIG_SSB_DRIVER_MIPS is set and CONFIG_SSB_DRIVER_EXTIF is not set, it will cause compile problems because of missing functions. This patch fixes these problems. The mips driver now also uses ssb_chipco_available() instead of checking bus->chipco.dev manually. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index b918ba9..5bd05b1 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore) { struct ssb_bus *bus = mcore->dev->bus; - if (bus->extif.dev) + if (ssb_extif_available(&bus->extif)) mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); - else if (bus->chipco.dev) + else if (ssb_chipco_available(&bus->chipco)) mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); else mcore->nr_serial_ports = 0; @@ -191,7 +191,7 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) struct ssb_bus *bus = mcore->dev->bus; /* When there is no chipcommon on the bus there is 4MB flash */ - if (!bus->chipco.dev) { + if (!ssb_chipco_available(&bus->chipco)) { mcore->pflash.present = true; mcore->pflash.buswidth = 2; mcore->pflash.window = SSB_FLASH1; @@ -227,9 +227,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *mcore) if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) return ssb_pmu_get_cpu_clock(&bus->chipco); - if (bus->extif.dev) { + if (ssb_extif_available(&bus->extif)) { ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); - } else if (bus->chipco.dev) { + } else if (ssb_chipco_available(&bus->chipco)) { ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); } else return 0; @@ -265,9 +265,9 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) hz = 100000000; ns = 1000000000 / hz; - if (bus->extif.dev) + if (ssb_extif_available(&bus->extif)) ssb_extif_timing_init(&bus->extif, ns); - else if (bus->chipco.dev) + else if (ssb_chipco_available(&bus->chipco)) ssb_chipco_timing_init(&bus->chipco, ns); /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 91161f0..2604efa 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -205,10 +205,52 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, } static inline +void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) +{ +} + +static inline void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { } +static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +#ifdef CONFIG_SSB_SERIAL +static inline int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports) +{ + return 0; +} +#endif /* CONFIG_SSB_SERIAL */ + #endif /* CONFIG_SSB_DRIVER_EXTIF */ #endif /* LINUX_SSB_EXTIFCORE_H_ */ -- cgit v0.10.2 From d6144d85f830848ab31eb5d073d9bb4742b64e03 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 27 Nov 2012 13:51:32 +0530 Subject: ath9k: Fix buffer overflow error The commit "ath9k: stomp audio profiles on weak signal strength" failed to take care of new stomp type while programming concurrent tx priority. That leads to array index out of bounds access. drivers/net/wireless/ath/ath9k/btcoex.c:414 ath9k_hw_btcoex_set_concur_txprio() error: buffer overflow 'stomp_txprio' 4 <= 4 Reported-by: Dan Carpenter Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 706378e..5c02702 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -257,8 +257,9 @@ static void ath_mci_set_concur_txprio(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; - u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */ + u8 stomp_txprio[ATH_BTCOEX_STOMP_MAX]; + memset(stomp_txprio, 0, sizeof(stomp_txprio)); if (mci->num_mgmt) { stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO; if (!mci->num_pan && !mci->num_other_acl) -- cgit v0.10.2 From dd0d83c220086dba81055e59b7c1f63f94b27003 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Tue, 27 Nov 2012 12:09:20 -0800 Subject: mwifiex: advertise GreenField, 40MHz intolerance support to cfg80211 This patch adds support for advertising GreenField, 40MHz intolerance or LDPC coding support to cfg80211. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 3b1c277..a875499 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1948,6 +1948,21 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, else ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + else + ht_info->cap &= ~IEEE80211_HT_CAP_GRN_FLD; + + if (ISENABLED_40MHZ_INTOLERANT(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + else + ht_info->cap &= ~IEEE80211_HT_CAP_40MHZ_INTOLERANT; + + if (ISSUPP_RXLDPC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + else + ht_info->cap &= ~IEEE80211_HT_CAP_LDPC_CODING; + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= IEEE80211_HT_CAP_SM_PS; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index dda588b..4dc8e2e 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -194,6 +194,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) +#define ISENABLED_40MHZ_INTOLERANT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) +#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) /* httxcfg bitmap * 0 reserved -- cgit v0.10.2 From 6c50f9459e62eb133563fd23606f68bfc9d120e8 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 28 Nov 2012 10:28:52 +0100 Subject: rt2x00: Use addr_mask to disallow invalid MAC addresses in mutli-bssid mode Reported-by: Petr Stetiar Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 67d1679..66b3b17 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1183,6 +1183,13 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); /* + * rt2x00 devices can only use the last n bits of the MAC address + * for virtual interfaces. + */ + rt2x00dev->hw->wiphy->addr_mask[ETH_ALEN - 1] = + (rt2x00dev->ops->max_ap_intf - 1); + + /* * Determine which operating modes are supported, all modes * which require beaconing, depend on the availability of * beacon entries. -- cgit v0.10.2 From c175db87411f0e79924a48563d5f595b9a352907 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:52 +0530 Subject: ath9k: Move ethtool functions to debug.c The ethtool statistics are available only when CONFIG_ATH9K_DEBUGFS is enabled, move these functions to debug.c Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 939308c..cb5e457 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1509,6 +1509,125 @@ static const struct file_operations fops_btcoex = { }; #endif +/* Ethtool support for get-stats */ + +#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" +static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { + "tx_pkts_nic", + "tx_bytes_nic", + "rx_pkts_nic", + "rx_bytes_nic", + AMKSTR(d_tx_pkts), + AMKSTR(d_tx_bytes), + AMKSTR(d_tx_mpdus_queued), + AMKSTR(d_tx_mpdus_completed), + AMKSTR(d_tx_mpdu_xretries), + AMKSTR(d_tx_aggregates), + AMKSTR(d_tx_ampdus_queued_hw), + AMKSTR(d_tx_ampdus_queued_sw), + AMKSTR(d_tx_ampdus_completed), + AMKSTR(d_tx_ampdu_retries), + AMKSTR(d_tx_ampdu_xretries), + AMKSTR(d_tx_fifo_underrun), + AMKSTR(d_tx_op_exceeded), + AMKSTR(d_tx_timer_expiry), + AMKSTR(d_tx_desc_cfg_err), + AMKSTR(d_tx_data_underrun), + AMKSTR(d_tx_delim_underrun), + "d_rx_decrypt_crc_err", + "d_rx_phy_err", + "d_rx_mic_err", + "d_rx_pre_delim_crc_err", + "d_rx_post_delim_crc_err", + "d_rx_decrypt_busy_err", + + "d_rx_phyerr_radar", + "d_rx_phyerr_ofdm_timing", + "d_rx_phyerr_cck_timing", + +}; +#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats) + +void ath9k_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data) +{ + if (sset == ETH_SS_STATS) + memcpy(data, *ath9k_gstrings_stats, + sizeof(ath9k_gstrings_stats)); +} + +int ath9k_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset) +{ + if (sset == ETH_SS_STATS) + return ATH9K_SSTATS_LEN; + return 0; +} + +#define AWDATA(elem) \ + do { \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \ + data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \ + } while (0) + +#define AWDATA_RX(elem) \ + do { \ + data[i++] = sc->debug.stats.rxstats.elem; \ + } while (0) + +void ath9k_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct ath_softc *sc = hw->priv; + int i = 0; + + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); + data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); + AWDATA_RX(rx_pkts_all); + AWDATA_RX(rx_bytes_all); + + AWDATA(tx_pkts_all); + AWDATA(tx_bytes_all); + AWDATA(queued); + AWDATA(completed); + AWDATA(xretries); + AWDATA(a_aggr); + AWDATA(a_queued_hw); + AWDATA(a_queued_sw); + AWDATA(a_completed); + AWDATA(a_retries); + AWDATA(a_xretries); + AWDATA(fifo_underrun); + AWDATA(xtxop); + AWDATA(timer_exp); + AWDATA(desc_cfg_err); + AWDATA(data_underrun); + AWDATA(delim_underrun); + + AWDATA_RX(decrypt_crc_err); + AWDATA_RX(phy_err); + AWDATA_RX(mic_err); + AWDATA_RX(pre_delim_crc_err); + AWDATA_RX(post_delim_crc_err); + AWDATA_RX(decrypt_busy_err); + + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]); + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]); + AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]); + + WARN_ON(i != ATH9K_SSTATS_LEN); +} + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index f9bee18..bfc21b3 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -307,6 +307,14 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, unsigned int flags); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); +int ath9k_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset); +void ath9k_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data); +void ath9k_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data); #else diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0653dbc..ffae384 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1882,133 +1882,6 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -#ifdef CONFIG_ATH9K_DEBUGFS - -/* Ethtool support for get-stats */ - -#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" -static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { - "tx_pkts_nic", - "tx_bytes_nic", - "rx_pkts_nic", - "rx_bytes_nic", - AMKSTR(d_tx_pkts), - AMKSTR(d_tx_bytes), - AMKSTR(d_tx_mpdus_queued), - AMKSTR(d_tx_mpdus_completed), - AMKSTR(d_tx_mpdu_xretries), - AMKSTR(d_tx_aggregates), - AMKSTR(d_tx_ampdus_queued_hw), - AMKSTR(d_tx_ampdus_queued_sw), - AMKSTR(d_tx_ampdus_completed), - AMKSTR(d_tx_ampdu_retries), - AMKSTR(d_tx_ampdu_xretries), - AMKSTR(d_tx_fifo_underrun), - AMKSTR(d_tx_op_exceeded), - AMKSTR(d_tx_timer_expiry), - AMKSTR(d_tx_desc_cfg_err), - AMKSTR(d_tx_data_underrun), - AMKSTR(d_tx_delim_underrun), - - "d_rx_decrypt_crc_err", - "d_rx_phy_err", - "d_rx_mic_err", - "d_rx_pre_delim_crc_err", - "d_rx_post_delim_crc_err", - "d_rx_decrypt_busy_err", - - "d_rx_phyerr_radar", - "d_rx_phyerr_ofdm_timing", - "d_rx_phyerr_cck_timing", - -}; -#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats) - -static void ath9k_get_et_strings(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - u32 sset, u8 *data) -{ - if (sset == ETH_SS_STATS) - memcpy(data, *ath9k_gstrings_stats, - sizeof(ath9k_gstrings_stats)); -} - -static int ath9k_get_et_sset_count(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int sset) -{ - if (sset == ETH_SS_STATS) - return ATH9K_SSTATS_LEN; - return 0; -} - -#define AWDATA(elem) \ - do { \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \ - data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \ - } while (0) - -#define AWDATA_RX(elem) \ - do { \ - data[i++] = sc->debug.stats.rxstats.elem; \ - } while (0) - -static void ath9k_get_et_stats(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ethtool_stats *stats, u64 *data) -{ - struct ath_softc *sc = hw->priv; - int i = 0; - - data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); - data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + - sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); - AWDATA_RX(rx_pkts_all); - AWDATA_RX(rx_bytes_all); - - AWDATA(tx_pkts_all); - AWDATA(tx_bytes_all); - AWDATA(queued); - AWDATA(completed); - AWDATA(xretries); - AWDATA(a_aggr); - AWDATA(a_queued_hw); - AWDATA(a_queued_sw); - AWDATA(a_completed); - AWDATA(a_retries); - AWDATA(a_xretries); - AWDATA(fifo_underrun); - AWDATA(xtxop); - AWDATA(timer_exp); - AWDATA(desc_cfg_err); - AWDATA(data_underrun); - AWDATA(delim_underrun); - - AWDATA_RX(decrypt_crc_err); - AWDATA_RX(phy_err); - AWDATA_RX(mic_err); - AWDATA_RX(pre_delim_crc_err); - AWDATA_RX(post_delim_crc_err); - AWDATA_RX(decrypt_busy_err); - - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]); - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]); - AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]); - - WARN_ON(i != ATH9K_SSTATS_LEN); -} - -/* End of ethtool get-stats functions */ - -#endif - - #ifdef CONFIG_PM_SLEEP static void ath9k_wow_map_triggers(struct ath_softc *sc, -- cgit v0.10.2 From de7b7604eae91f00cd587f8541eec11a7fc505aa Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:53 +0530 Subject: ath9k: Replace WME_NUM_TID with IEEE80211_NUM_TIDS Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 80bab1b..60bf784 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -261,7 +261,7 @@ struct ath_atx_tid { struct ath_node { struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ - struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; struct ath_atx_ac ac[IEEE80211_NUM_ACS]; int ps_key; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 76b5439..5f845be 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -23,7 +23,6 @@ /* Common header for Atheros 802.11n base driver cores */ -#define WME_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3413094..a0a3063 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1263,7 +1263,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { if (!tid->sched) continue; @@ -1297,7 +1297,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ac = tid->ac; txq = ac->txq; @@ -2448,7 +2448,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) int tidno, acno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { tid->an = an; tid->tidno = tidno; @@ -2481,7 +2481,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) int tidno; for (tidno = 0, tid = &an->tid[tidno]; - tidno < WME_NUM_TID; tidno++, tid++) { + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ac = tid->ac; txq = ac->txq; -- cgit v0.10.2 From a145daf7f04696d0cec98d5328760fe65fe418c5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:54 +0530 Subject: ath9k: Implement sta_add_debugfs/sta_remove_debugfs Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 60bf784..86e26a1 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -259,6 +259,7 @@ struct ath_atx_tid { }; struct ath_node { + struct ath_softc *sc; struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; @@ -269,6 +270,10 @@ struct ath_node { u8 mpdudensity; bool sleeping; + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + struct dentry *node_stat; +#endif }; #define AGGR_CLEANUP BIT(1) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index cb5e457..13ff9ed 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1509,6 +1509,96 @@ static const struct file_operations fops_btcoex = { }; #endif +static ssize_t read_file_node_stat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_node *an = file->private_data; + struct ath_softc *sc = an->sc; + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + u32 len = 0, size = 4096; + char *buf; + size_t retval; + int tidno, acno; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!an->sta->ht_cap.ht_supported) { + len = snprintf(buf, size, "%s\n", + "HT not supported"); + goto exit; + } + + len = snprintf(buf, size, "Max-AMPDU: %d\n", + an->maxampdu); + len += snprintf(buf + len, size - len, "MPDU Density: %d\n\n", + an->mpdudensity); + + len += snprintf(buf + len, size - len, + "%2s%7s\n", "AC", "SCHED"); + + for (acno = 0, ac = &an->ac[acno]; + acno < IEEE80211_NUM_ACS; acno++, ac++) { + txq = ac->txq; + ath_txq_lock(sc, txq); + len += snprintf(buf + len, size - len, + "%2d%7d\n", + acno, ac->sched); + ath_txq_unlock(sc, txq); + } + + len += snprintf(buf + len, size - len, + "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", + "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", + "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + txq = tid->ac->txq; + ath_txq_lock(sc, txq); + len += snprintf(buf + len, size - len, + "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n", + tid->tidno, tid->seq_start, tid->seq_next, + tid->baw_size, tid->baw_head, tid->baw_tail, + tid->bar_index, tid->sched, tid->paused); + ath_txq_unlock(sc, txq); + } +exit: + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_node_stat = { + .read = read_file_node_stat, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + an->node_stat = debugfs_create_file("node_stat", S_IRUGO, + dir, an, &fops_node_stat); +} + +void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + debugfs_remove(an->node_stat); +} + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index bfc21b3..72d4893 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -315,7 +315,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, void ath9k_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data); - +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); +void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir); #else #define RX_STAT_INC(c) /* NOP */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ffae384..be30a9a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -331,6 +331,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, u8 density; an = (struct ath_node *)sta->drv_priv; + an->sc = sc; an->sta = sta; an->vif = vif; @@ -2275,7 +2276,12 @@ struct ieee80211_ops ath9k_ops = { #ifdef CONFIG_ATH9K_DEBUGFS .get_et_sset_count = ath9k_get_et_sset_count, - .get_et_stats = ath9k_get_et_stats, - .get_et_strings = ath9k_get_et_strings, + .get_et_stats = ath9k_get_et_stats, + .get_et_strings = ath9k_get_et_strings, +#endif + +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) + .sta_add_debugfs = ath9k_sta_add_debugfs, + .sta_remove_debugfs = ath9k_sta_remove_debugfs, #endif }; -- cgit v0.10.2 From a56c919f05eb73f6d791cc14992f4b451059b68c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 28 Nov 2012 15:08:55 +0530 Subject: ath9k: Remove redundant NULL assignment 'bf_next' is cleared using ATH_TXBUF_RESET() in both the callsites of ath_tx_get_buffer(). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a0a3063..90e48a0 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,7 +312,6 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) } bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - bf->bf_next = NULL; list_del(&bf->list); spin_unlock_bh(&sc->tx.txbuflock); -- cgit v0.10.2 From 23c1d7f65975762386760e36c00f149059e537e2 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 28 Nov 2012 18:57:19 +0200 Subject: wireless: allow Atheros card to not depend on ath.ko There are 2 different things: - sub-menu for "Atheros Wireless cards" family - module ath.ko with common Atheros code Until now, they both used to depend on the same Kconfig variable ATH_COMMON. Thus, being "Atheros card" and "depending on ath.ko" was the same. To allow module to belong to the "Atheros Wireless cards" family but not use ath.ko, 2 conditions above need to be separated. So, this patch introduce new Kconfig variable ATH_CARDS for belonging to the "Atheros Wireless Cards" family; while ATH_COMMON becomes hidden variable to express dependency on common Atheros code in ath.ko. Modules that depend on this common code now express it by setting ATH_COMMON. Right now, ath6kl do not depend on common code and thus do not set ATH_COMMON. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index c25dcf1..1a67a4f 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,4 +1,7 @@ -menuconfig ATH_COMMON +config ATH_COMMON + tristate + +menuconfig ATH_CARDS tristate "Atheros Wireless Cards" depends on CFG80211 && (!UML || BROKEN) ---help--- @@ -14,7 +17,7 @@ menuconfig ATH_COMMON http://wireless.kernel.org/en/users/Drivers/Atheros -if ATH_COMMON +if ATH_CARDS config ATH_DEBUG bool "Atheros wireless debugging" diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig index 11d99ee..0d320cc 100644 --- a/drivers/net/wireless/ath/ar5523/Kconfig +++ b/drivers/net/wireless/ath/ar5523/Kconfig @@ -1,6 +1,7 @@ config AR5523 tristate "Atheros AR5523 wireless driver support" depends on MAC80211 && USB + select ATH_COMMON select FW_LOADER ---help--- This module add support for AR5523 based USB dongles such as D-Link diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 338c5c4..c9f81a3 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,7 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on (PCI || ATHEROS_AR231X) && MAC80211 + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index c7aa664..5fc15bf 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -17,6 +17,7 @@ config ATH9K_BTCOEX_SUPPORT config ATH9K tristate "Atheros 802.11n wireless cards support" depends on MAC80211 + select ATH_COMMON select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index 267d5dc..13a2045 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -1,6 +1,7 @@ config CARL9170 tristate "Linux Community AR9170 802.11n USB support" depends on USB && MAC80211 && EXPERIMENTAL + select ATH_COMMON select FW_LOADER select CRC32 help -- cgit v0.10.2 From 006a8f148690774d04965488415ee59269d061c3 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 28 Nov 2012 21:44:04 +0100 Subject: brcm80211: update the MAINTAINERS file Organizational changes need to be reflected in the MAINTAINERS file. The contact info on wireless.kernel.org has also been updated. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index ed5b5f5..46ce7c6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1658,10 +1658,9 @@ F: drivers/net/ethernet/broadcom/tg3.* BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER M: Brett Rudley -M: Roland Vossen M: Arend van Spriel M: Franky (Zhenhui) Lin -M: Kan Yan +M: Hante Meuleman L: linux-wireless@vger.kernel.org L: brcm80211-dev-list@broadcom.com S: Supported -- cgit v0.10.2 From c4dea35e34f5f46e1701156153a09cce429d1ea9 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 28 Nov 2012 21:44:05 +0100 Subject: brcmsmac: handle packet drop during transmit correctly The .tx() callback function can drop packets when there is no space in the DMA fifo. Propagate that information to caller and make sure the freed sk_buff reference is not accessed. Reviewed-by: Arend van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 1710ccb..f917d62 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -285,8 +285,8 @@ static void brcms_ops_tx(struct ieee80211_hw *hw, kfree_skb(skb); goto done; } - brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); - tx_info->rate_driver_data[0] = control->sta; + if (brcms_c_sendpkt_mac80211(wl->wlc, skb, hw)) + tx_info->rate_driver_data[0] = control->sta; done: spin_unlock_bh(&wl->lock); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 2a44593..54ab2f7 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -6928,17 +6928,20 @@ static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb) return ret; } -void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, +bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw) { uint fifo; struct scb *scb = &wlc->pri_scb; fifo = brcms_ac_to_fifo(skb_get_queue_mapping(sdu)); - if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0)) - return; - if (brcms_c_tx(wlc, sdu)) - dev_kfree_skb_any(sdu); + brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0); + if (!brcms_c_tx(wlc, sdu)) + return true; + + /* packet discarded */ + dev_kfree_skb_any(sdu); + return false; } int diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 0148dec..0d7af34 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -284,7 +284,7 @@ extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); extern bool brcms_c_intrsupd(struct brcms_c_info *wlc); extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc); extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); -extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, +extern bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw); extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid); -- cgit v0.10.2 From 94d9902dc06a28a1b25cf56a7cdc057608bdf48b Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 28 Nov 2012 21:44:06 +0100 Subject: brcmsmac: cleanup in isr code brcms_c_isr returns true if interrupt was for us and if dpc should be scheduled which is the same thing. Simplify it. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Arend van Spriel Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index f917d62..976720c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -896,27 +896,22 @@ static void brcms_remove(struct bcma_device *pdev) static irqreturn_t brcms_isr(int irq, void *dev_id) { struct brcms_info *wl; - bool ours, wantdpc; + irqreturn_t ret = IRQ_NONE; wl = (struct brcms_info *) dev_id; spin_lock(&wl->isr_lock); /* call common first level interrupt handler */ - ours = brcms_c_isr(wl->wlc, &wantdpc); - if (ours) { - /* if more to do... */ - if (wantdpc) { - - /* ...and call the second level interrupt handler */ - /* schedule dpc */ - tasklet_schedule(&wl->tasklet); - } + if (brcms_c_isr(wl->wlc)) { + /* schedule second level handler */ + tasklet_schedule(&wl->tasklet); + ret = IRQ_HANDLED; } spin_unlock(&wl->isr_lock); - return IRQ_RETVAL(ours); + return ret; } /* diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 54ab2f7..054e1da 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -2546,10 +2546,6 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) if (macintstatus == 0) return 0; - /* interrupts are already turned off for CFE build - * Caution: For CFE Turning off the interrupts again has some undesired - * consequences - */ /* turn off the interrupts */ bcma_write32(core, D11REGOFFS(macintmask), 0); (void)bcma_read32(core, D11REGOFFS(macintmask)); @@ -2592,33 +2588,31 @@ bool brcms_c_intrsupd(struct brcms_c_info *wlc) /* * First-level interrupt processing. - * Return true if this was our interrupt, false otherwise. - * *wantdpc will be set to true if further brcms_c_dpc() processing is required, + * Return true if this was our interrupt + * and if further brcms_c_dpc() processing is required, * false otherwise. */ -bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) +bool brcms_c_isr(struct brcms_c_info *wlc) { struct brcms_hardware *wlc_hw = wlc->hw; u32 macintstatus; - *wantdpc = false; - if (!wlc_hw->up || !wlc->macintmask) return false; /* read and clear macintstatus and intstatus registers */ macintstatus = wlc_intstatus(wlc, true); - if (macintstatus == 0xffffffff) + if (macintstatus == 0xffffffff) { brcms_err(wlc_hw->d11core, "DEVICEREMOVED detected in the ISR code path\n"); + return false; + } /* it is not for us */ if (macintstatus == 0) return false; - *wantdpc = true; - /* save interrupt status bits */ wlc->macintstatus = macintstatus; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 0d7af34..2aafe74 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -282,7 +282,7 @@ extern void brcms_c_intrson(struct brcms_c_info *wlc); extern u32 brcms_c_intrsoff(struct brcms_c_info *wlc); extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); extern bool brcms_c_intrsupd(struct brcms_c_info *wlc); -extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc); +extern bool brcms_c_isr(struct brcms_c_info *wlc); extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); extern bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, -- cgit v0.10.2 From 57fe504817ccec9b6ac23e973d2925343bf1e3b6 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 28 Nov 2012 21:44:07 +0100 Subject: brcmsmac: fix bounds checking in tx/rx brcms_b_txstatus and brcms_b_recv are off by one when doing bounds checking on number of packets to process Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Arend van Spriel Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 054e1da..8fce687 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -1044,11 +1044,17 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); while (!(*fatal) && (s1 & TXS_V)) { + /* !give others some time to run! */ + if (n >= max_tx_num) { + morepending = true; + break; + } if (s1 == 0xffffffff) { brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit, __func__); - return morepending; + *fatal = true; + return false; } s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2)); @@ -1060,17 +1066,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs); - /* !give others some time to run! */ - if (++n >= max_tx_num) - break; s1 = bcma_read32(core, D11REGOFFS(frmtxstatus)); + n++; } if (*fatal) - return 0; - - if (n >= max_tx_num) - morepending = true; + return false; return morepending; } @@ -7631,16 +7632,19 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) uint n = 0; uint bound_limit = bound ? RXBND : -1; + bool morepending; skb_queue_head_init(&recv_frames); /* gather received frames */ - while (dma_rx(wlc_hw->di[fifo], &recv_frames)) { - + do { /* !give others some time to run! */ - if (++n >= bound_limit) + if (n >= bound_limit) break; - } + + morepending = dma_rx(wlc_hw->di[fifo], &recv_frames); + n++; + } while (morepending); /* post more rbufs */ dma_rxfill(wlc_hw->di[fifo]); @@ -7670,7 +7674,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) brcms_c_recv(wlc_hw->wlc, p); } - return n >= bound_limit; + return morepending; } /* second-level interrupt processing -- cgit v0.10.2 From 8e21df23894e12937fb3b51197bf5d0c4d7cc8ba Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 28 Nov 2012 21:44:08 +0100 Subject: brcmsmac: hardware info in debugfs Put basic information about hardware in debugfs. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Arend van Spriel Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Acked-by: Seth Forshee Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c index 6ba4136..be84791 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c @@ -1,8 +1,121 @@ +/* + * Copyright (c) 2012 Broadcom Corporation + * Copyright (c) 2012 Canonical Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include #include +#include +#include +#include +#include +#include + +#include +#include +#include #include "types.h" +#include "main.h" #include "debug.h" #include "brcms_trace_events.h" +static struct dentry *root_folder; + +void brcms_debugfs_init(void) +{ + root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(root_folder)) + root_folder = NULL; +} + +void brcms_debugfs_exit(void) +{ + if (!root_folder) + return; + + debugfs_remove_recursive(root_folder); + root_folder = NULL; +} + +int brcms_debugfs_attach(struct brcms_pub *drvr) +{ + if (!root_folder) + return -ENODEV; + + drvr->dbgfs_dir = debugfs_create_dir( + dev_name(&drvr->wlc->hw->d11core->dev), root_folder); + return PTR_RET(drvr->dbgfs_dir); +} + +void brcms_debugfs_detach(struct brcms_pub *drvr) +{ + if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) + debugfs_remove_recursive(drvr->dbgfs_dir); +} + +struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr) +{ + return drvr->dbgfs_dir; +} + +static +ssize_t brcms_debugfs_hardware_read(struct file *f, char __user *data, + size_t count, loff_t *ppos) +{ + char buf[128]; + int res; + struct brcms_pub *drvr = f->private_data; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), + "board vendor: %x\n" + "board type: %x\n" + "board revision: %x\n" + "board flags: %x\n" + "board flags2: %x\n" + "firmware revision: %x\n", + drvr->wlc->hw->d11core->bus->boardinfo.vendor, + drvr->wlc->hw->d11core->bus->boardinfo.type, + drvr->wlc->hw->boardrev, + drvr->wlc->hw->boardflags, + drvr->wlc->hw->boardflags2, + drvr->wlc->ucode_rev + ); + + return simple_read_from_buffer(data, count, ppos, buf, res); +} + +static const struct file_operations brcms_debugfs_hardware_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = brcms_debugfs_hardware_read +}; + +void brcms_debugfs_create_files(struct brcms_pub *drvr) +{ + struct dentry *dentry = drvr->dbgfs_dir; + + if (!IS_ERR_OR_NULL(dentry)) + debugfs_create_file("hardware", S_IRUGO, dentry, + drvr, &brcms_debugfs_hardware_ops); +} + #define __brcms_fn(fn) \ void __brcms_ ##fn(struct device *dev, const char *fmt, ...) \ { \ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.h b/drivers/net/wireless/brcm80211/brcmsmac/debug.h index f77066b..796836b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.h @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2012 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #ifndef _BRCMS_DEBUG_H_ #define _BRCMS_DEBUG_H_ @@ -49,4 +64,12 @@ void __brcms_dbg(struct device *dev, u32 level, const char *func, #define brcms_dbg_dma(core, f, a...) brcms_dbg(core, BRCM_DL_DMA, f, ##a) #define brcms_dbg_ht(core, f, a...) brcms_dbg(core, BRCM_DL_HT, f, ##a) +struct brcms_pub; +void brcms_debugfs_init(void); +void brcms_debugfs_exit(void); +int brcms_debugfs_attach(struct brcms_pub *drvr); +void brcms_debugfs_detach(struct brcms_pub *drvr); +struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr); +void brcms_debugfs_create_files(struct brcms_pub *drvr); + #endif /* _BRCMS_DEBUG_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 976720c..85dbaf8 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -846,8 +846,10 @@ static void brcms_free(struct brcms_info *wl) /* kill dpc */ tasklet_kill(&wl->tasklet); - if (wl->pub) + if (wl->pub) { + brcms_debugfs_detach(wl->pub); brcms_c_module_unregister(wl->pub, "linux", wl); + } /* free common resources */ if (wl->wlc) { @@ -1077,6 +1079,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) regulatory_hint(wl->wiphy, wl->pub->srom_ccode)) wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__); + brcms_debugfs_attach(wl->pub); + brcms_debugfs_create_files(wl->pub); n_adapters_found++; return wl; @@ -1185,6 +1189,7 @@ static DECLARE_WORK(brcms_driver_work, brcms_driver_init); static int __init brcms_module_init(void) { + brcms_debugfs_init(); if (!schedule_work(&brcms_driver_work)) return -EBUSY; @@ -1202,6 +1207,7 @@ static void __exit brcms_module_exit(void) { cancel_work_sync(&brcms_driver_work); bcma_driver_unregister(&brcms_bcma_driver); + brcms_debugfs_exit(); } module_init(brcms_module_init); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 2aafe74..4fb2834 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -176,6 +176,7 @@ struct brcms_pub { bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */ struct wl_cnt *_cnt; /* low-level counters in driver */ + struct dentry *dbgfs_dir; }; enum wlc_par_id { -- cgit v0.10.2 From b83576341664957978e125f5f5db2f15496980b1 Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 28 Nov 2012 21:44:09 +0100 Subject: brcmsmac: move PHY functions Move functions in preparation for 4313iPA changes Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index abfd788..18d3764 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1860,41 +1860,6 @@ wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type) return (filt_index != -1) ? 0 : -1; } -void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) -{ - u8 channel = CHSPEC_CHANNEL(chanspec); - - wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec); - - wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); - - or_phy_reg(pi, 0x44a, 0x44); - write_phy_reg(pi, 0x44a, 0x80); - - wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); - udelay(1000); - - wlc_lcnphy_toggle_afe_pwdn(pi); - - write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); - write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); - - if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { - mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); - - wlc_lcnphy_load_tx_iir_filter(pi, false, 3); - } else { - mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); - - wlc_lcnphy_load_tx_iir_filter(pi, false, 2); - } - - wlc_lcnphy_load_tx_iir_filter(pi, true, 0); - - mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); - -} - static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi) { u16 pa_gain; @@ -1936,6 +1901,21 @@ static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi, wlc_lcnphy_enable_tx_gain_override(pi); } +static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) +{ + u16 m0m1; + struct phytbl_info tab; + + tab.tbl_ptr = &m0m1; + tab.tbl_len = 1; + tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; + tab.tbl_offset = 87; + tab.tbl_width = 16; + wlc_lcnphy_read_table(pi, &tab); + + return (u8) ((m0m1 & 0xff00) >> 8); +} + static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0) { u16 m0m1 = (u16) m0 << 8; @@ -3075,21 +3055,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) wlapi_enable_mac(pi->sh->physhim); } -static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) -{ - u16 m0m1; - struct phytbl_info tab; - - tab.tbl_ptr = &m0m1; - tab.tbl_len = 1; - tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; - tab.tbl_offset = 87; - tab.tbl_width = 16; - wlc_lcnphy_read_table(pi, &tab); - - return (u8) ((m0m1 & 0xff00) >> 8); -} - static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain) { mod_phy_reg(pi, 0x4fb, @@ -4946,6 +4911,43 @@ void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi) } } +void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) +{ + u8 channel = CHSPEC_CHANNEL(chanspec); + + wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec); + + wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); + + or_phy_reg(pi, 0x44a, 0x44); + write_phy_reg(pi, 0x44a, 0x80); + + wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); + udelay(1000); + + wlc_lcnphy_toggle_afe_pwdn(pi); + + write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); + write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); + + if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { + mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); + + wlc_lcnphy_load_tx_iir_filter(pi, false, 3); + } else { + mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); + + wlc_lcnphy_load_tx_iir_filter(pi, false, 2); + } + + if (pi->sh->boardflags & BFL_FEM) + wlc_lcnphy_load_tx_iir_filter(pi, true, 0); + else + wlc_lcnphy_load_tx_iir_filter(pi, true, 3); + + mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); +} + void wlc_phy_detach_lcnphy(struct brcms_phy *pi) { kfree(pi->u.pi_lcnphy); -- cgit v0.10.2 From b6fc28a158076ca2764edc9a6d1e1402f56e1c0c Mon Sep 17 00:00:00 2001 From: Piotr Haber Date: Wed, 28 Nov 2012 21:44:10 +0100 Subject: brcmsmac: support 4313iPA Add support for 4313 iPA variant. It is a variant of already supported 4313 ePA and needs some PHY changes to work properly. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Piotr Haber Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 18d3764..606b534 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1137,8 +1137,9 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, gain0_15 = ((biq1 & 0xf) << 12) | ((tia & 0xf) << 8) | ((lna2 & 0x3) << 6) | - ((lna2 & - 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0); + ((lna2 & 0x3) << 4) | + ((lna1 & 0x3) << 2) | + ((lna1 & 0x3) << 0); mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); @@ -1156,6 +1157,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, } mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); + mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); + mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3); } @@ -1328,6 +1331,43 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples) return (iq_est.i_pwr + iq_est.q_pwr) / nsamples; } +static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain, + u16 tia_gain, u16 lna2_gain) +{ + u32 i_thresh_l, q_thresh_l; + u32 i_thresh_h, q_thresh_h; + struct lcnphy_iq_est iq_est_h, iq_est_l; + + wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain, + lna2_gain, 0); + + wlc_lcnphy_rx_gain_override_enable(pi, true); + wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0); + usleep_range(500, 500); + write_radio_reg(pi, RADIO_2064_REG112, 0); + if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l)) + return false; + + wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0); + usleep_range(500, 500); + write_radio_reg(pi, RADIO_2064_REG112, 0); + if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h)) + return false; + + i_thresh_l = (iq_est_l.i_pwr << 1); + i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr; + + q_thresh_l = (iq_est_l.q_pwr << 1); + q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr; + if ((iq_est_h.i_pwr > i_thresh_l) && + (iq_est_h.i_pwr < i_thresh_h) && + (iq_est_h.q_pwr > q_thresh_l) && + (iq_est_h.q_pwr < q_thresh_h)) + return true; + + return false; +} + static bool wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, const struct lcnphy_rx_iqcomp *iqcomp, @@ -1342,8 +1382,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old, rfoverride3_old, rfoverride3val_old, rfoverride4_old, rfoverride4val_old, afectrlovr_old, afectrlovrval_old; - int tia_gain; - u32 received_power, rx_pwr_threshold; + int tia_gain, lna2_gain, biq1_gain; + bool set_gain; u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl; u16 values_to_save[11]; s16 *ptr; @@ -1368,126 +1408,134 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, goto cal_done; } - if (module == 1) { + WARN_ON(module != 1); + tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); - tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + for (i = 0; i < 11; i++) + values_to_save[i] = + read_radio_reg(pi, rxiq_cal_rf_reg[i]); + Core1TxControl_old = read_phy_reg(pi, 0x631); + + or_phy_reg(pi, 0x631, 0x0015); + + RFOverride0_old = read_phy_reg(pi, 0x44c); + RFOverrideVal0_old = read_phy_reg(pi, 0x44d); + rfoverride2_old = read_phy_reg(pi, 0x4b0); + rfoverride2val_old = read_phy_reg(pi, 0x4b1); + rfoverride3_old = read_phy_reg(pi, 0x4f9); + rfoverride3val_old = read_phy_reg(pi, 0x4fa); + rfoverride4_old = read_phy_reg(pi, 0x938); + rfoverride4val_old = read_phy_reg(pi, 0x939); + afectrlovr_old = read_phy_reg(pi, 0x43b); + afectrlovrval_old = read_phy_reg(pi, 0x43c); + old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - for (i = 0; i < 11; i++) - values_to_save[i] = - read_radio_reg(pi, rxiq_cal_rf_reg[i]); - Core1TxControl_old = read_phy_reg(pi, 0x631); - - or_phy_reg(pi, 0x631, 0x0015); - - RFOverride0_old = read_phy_reg(pi, 0x44c); - RFOverrideVal0_old = read_phy_reg(pi, 0x44d); - rfoverride2_old = read_phy_reg(pi, 0x4b0); - rfoverride2val_old = read_phy_reg(pi, 0x4b1); - rfoverride3_old = read_phy_reg(pi, 0x4f9); - rfoverride3val_old = read_phy_reg(pi, 0x4fa); - rfoverride4_old = read_phy_reg(pi, 0x938); - rfoverride4val_old = read_phy_reg(pi, 0x939); - afectrlovr_old = read_phy_reg(pi, 0x43b); - afectrlovrval_old = read_phy_reg(pi, 0x43c); - old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); - old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); - - tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); - if (tx_gain_override_old) { - wlc_lcnphy_get_tx_gain(pi, &old_gains); - tx_gain_index_old = pi_lcn->lcnphy_current_index; - } + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + if (tx_gain_override_old) { + wlc_lcnphy_get_tx_gain(pi, &old_gains); + tx_gain_index_old = pi_lcn->lcnphy_current_index; + } - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); - mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); - write_radio_reg(pi, RADIO_2064_REG116, 0x06); - write_radio_reg(pi, RADIO_2064_REG12C, 0x07); - write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); - write_radio_reg(pi, RADIO_2064_REG098, 0x03); - write_radio_reg(pi, RADIO_2064_REG00B, 0x7); - mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); - write_radio_reg(pi, RADIO_2064_REG01D, 0x01); - write_radio_reg(pi, RADIO_2064_REG114, 0x01); - write_radio_reg(pi, RADIO_2064_REG02E, 0x10); - write_radio_reg(pi, RADIO_2064_REG12A, 0x08); - - mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); - mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); - mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); - mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); - mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); - mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); - - mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); - mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); - - wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); - write_phy_reg(pi, 0x6da, 0xffff); - or_phy_reg(pi, 0x6db, 0x3); - wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); - wlc_lcnphy_rx_gain_override_enable(pi, true); - - tia_gain = 8; - rx_pwr_threshold = 950; - while (tia_gain > 0) { - tia_gain -= 1; - wlc_lcnphy_set_rx_gain_by_distribution(pi, - 0, 0, 2, 2, - (u16) - tia_gain, 1, 0); - udelay(500); + write_radio_reg(pi, RADIO_2064_REG116, 0x06); + write_radio_reg(pi, RADIO_2064_REG12C, 0x07); + write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); + write_radio_reg(pi, RADIO_2064_REG098, 0x03); + write_radio_reg(pi, RADIO_2064_REG00B, 0x7); + mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); + write_radio_reg(pi, RADIO_2064_REG01D, 0x01); + write_radio_reg(pi, RADIO_2064_REG114, 0x01); + write_radio_reg(pi, RADIO_2064_REG02E, 0x10); + write_radio_reg(pi, RADIO_2064_REG12A, 0x08); + + mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); - received_power = - wlc_lcnphy_measure_digital_power(pi, 2000); - if (received_power < rx_pwr_threshold) - break; + mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); + + write_phy_reg(pi, 0x6da, 0xffff); + or_phy_reg(pi, 0x6db, 0x3); + + wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); + set_gain = false; + + lna2_gain = 3; + while ((lna2_gain >= 0) && !set_gain) { + tia_gain = 4; + + while ((tia_gain >= 0) && !set_gain) { + biq1_gain = 6; + + while ((biq1_gain >= 0) && !set_gain) { + set_gain = wlc_lcnphy_rx_iq_cal_gain(pi, + (u16) + biq1_gain, + (u16) + tia_gain, + (u16) + lna2_gain); + biq1_gain -= 1; + } + tia_gain -= 1; } - result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); + lna2_gain -= 1; + } - wlc_lcnphy_stop_tx_tone(pi); + if (set_gain) + result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024); + else + result = false; - write_phy_reg(pi, 0x631, Core1TxControl_old); + wlc_lcnphy_stop_tx_tone(pi); - write_phy_reg(pi, 0x44c, RFOverrideVal0_old); - write_phy_reg(pi, 0x44d, RFOverrideVal0_old); - write_phy_reg(pi, 0x4b0, rfoverride2_old); - write_phy_reg(pi, 0x4b1, rfoverride2val_old); - write_phy_reg(pi, 0x4f9, rfoverride3_old); - write_phy_reg(pi, 0x4fa, rfoverride3val_old); - write_phy_reg(pi, 0x938, rfoverride4_old); - write_phy_reg(pi, 0x939, rfoverride4val_old); - write_phy_reg(pi, 0x43b, afectrlovr_old); - write_phy_reg(pi, 0x43c, afectrlovrval_old); - write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); - write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); + write_phy_reg(pi, 0x631, Core1TxControl_old); + + write_phy_reg(pi, 0x44c, RFOverrideVal0_old); + write_phy_reg(pi, 0x44d, RFOverrideVal0_old); + write_phy_reg(pi, 0x4b0, rfoverride2_old); + write_phy_reg(pi, 0x4b1, rfoverride2val_old); + write_phy_reg(pi, 0x4f9, rfoverride3_old); + write_phy_reg(pi, 0x4fa, rfoverride3val_old); + write_phy_reg(pi, 0x938, rfoverride4_old); + write_phy_reg(pi, 0x939, rfoverride4val_old); + write_phy_reg(pi, 0x43b, afectrlovr_old); + write_phy_reg(pi, 0x43c, afectrlovrval_old); + write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); + write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); - wlc_lcnphy_clear_trsw_override(pi); + wlc_lcnphy_clear_trsw_override(pi); - mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); + mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); - for (i = 0; i < 11; i++) - write_radio_reg(pi, rxiq_cal_rf_reg[i], - values_to_save[i]); + for (i = 0; i < 11; i++) + write_radio_reg(pi, rxiq_cal_rf_reg[i], + values_to_save[i]); - if (tx_gain_override_old) - wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); - else - wlc_lcnphy_disable_tx_gain_override(pi); + if (tx_gain_override_old) + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); + else + wlc_lcnphy_disable_tx_gain_override(pi); - wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); - wlc_lcnphy_rx_gain_override_enable(pi, false); - } + wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); + wlc_lcnphy_rx_gain_override_enable(pi, false); cal_done: kfree(ptr); @@ -1781,6 +1829,17 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel) write_radio_reg(pi, RADIO_2064_REG038, 3); write_radio_reg(pi, RADIO_2064_REG091, 7); } + + if (!(pi->sh->boardflags & BFL_FEM)) { + u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc, + 0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0}; + + write_radio_reg(pi, RADIO_2064_REG02A, 0xf); + write_radio_reg(pi, RADIO_2064_REG091, 0x3); + write_radio_reg(pi, RADIO_2064_REG038, 0x3); + + write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]); + } } static int @@ -1975,6 +2034,16 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) } else { mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2); + mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4); + mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); + mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1); + mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7); + mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1); + mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4); } } else { mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); @@ -2061,12 +2130,14 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); + mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0)); } static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) { struct phytbl_info tab; u32 rfseq, ind; + u8 tssi_sel; tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; @@ -2088,7 +2159,13 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); - wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); + if (pi->sh->boardflags & BFL_FEM) { + tssi_sel = 0x1; + wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); + } else { + tssi_sel = 0xe; + wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA); + } mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); @@ -2124,9 +2201,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { - mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe); + mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel); mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); } else { + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1); mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); } @@ -2173,6 +2251,10 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); + mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0); + mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + wlc_lcnphy_pwrctrl_rssiparams(pi); } @@ -2791,6 +2873,8 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) read_radio_reg(pi, RADIO_2064_REG007) & 1; u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; + u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi); + idleTssi = read_phy_reg(pi, 0x4ab); suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); @@ -2808,6 +2892,12 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); wlc_lcnphy_tssi_setup(pi); + + mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0)); + mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6)); + + wlc_lcnphy_set_bbmult(pi, 0x0); + wlc_phy_do_dummy_tx(pi, true, OFF); idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) >> 0); @@ -2829,6 +2919,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); + wlc_lcnphy_set_bbmult(pi, SAVE_bbmult); wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); wlc_lcnphy_set_tx_gain(pi, &old_gains); wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); @@ -3042,6 +3133,11 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) wlc_lcnphy_write_table(pi, &tab); tab.tbl_offset++; } + mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0); + mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0); + mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8); + mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4); + mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2); mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); @@ -3843,7 +3939,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) target_gains.pad_gain = 21; target_gains.dac_gain = 0; wlc_lcnphy_set_tx_gain(pi, &target_gains); - wlc_lcnphy_set_tx_pwr_by_index(pi, 16); if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { @@ -3854,6 +3949,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) lcnphy_recal ? LCNPHY_CAL_RECAL : LCNPHY_CAL_FULL), false); } else { + wlc_lcnphy_set_tx_pwr_by_index(pi, 16); wlc_lcnphy_tx_iqlo_soft_cal_full(pi); } @@ -4278,17 +4374,22 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, if (CHSPEC_IS5G(pi->radio_chanspec)) pa_gain = 0x70; else - pa_gain = 0x70; + pa_gain = 0x60; if (pi->sh->boardflags & BFL_FEM) pa_gain = 0x10; + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; tab.tbl_len = 1; tab.tbl_ptr = &val; for (j = 0; j < 128; j++) { - gm_gain = gain_table[j].gm; + if (pi->sh->boardflags & BFL_FEM) + gm_gain = gain_table[j].gm; + else + gm_gain = 15; + val = (((u32) pa_gain << 24) | (gain_table[j].pad << 16) | (gain_table[j].pga << 8) | gm_gain); @@ -4499,7 +4600,10 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) write_phy_reg(pi, 0x4ea, 0x4688); - mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + if (pi->sh->boardflags & BFL_FEM) + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + else + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0); mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); @@ -4510,6 +4614,13 @@ static void wlc_radio_2064_init(struct brcms_phy *pi) wlc_lcnphy_rcal(pi); wlc_lcnphy_rc_cal(pi); + + if (!(pi->sh->boardflags & BFL_FEM)) { + write_radio_reg(pi, RADIO_2064_REG032, 0x6f); + write_radio_reg(pi, RADIO_2064_REG033, 0x19); + write_radio_reg(pi, RADIO_2064_REG039, 0xe); + } + } static void wlc_lcnphy_radio_init(struct brcms_phy *pi) @@ -4539,22 +4650,20 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) wlc_lcnphy_write_table(pi, &tab); } - tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; - tab.tbl_width = 16; - tab.tbl_ptr = &val; - tab.tbl_len = 1; - - val = 114; - tab.tbl_offset = 0; - wlc_lcnphy_write_table(pi, &tab); + if (!(pi->sh->boardflags & BFL_FEM)) { + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &val; + tab.tbl_len = 1; - val = 130; - tab.tbl_offset = 1; - wlc_lcnphy_write_table(pi, &tab); + val = 150; + tab.tbl_offset = 0; + wlc_lcnphy_write_table(pi, &tab); - val = 6; - tab.tbl_offset = 8; - wlc_lcnphy_write_table(pi, &tab); + val = 220; + tab.tbl_offset = 1; + wlc_lcnphy_write_table(pi, &tab); + } if (CHSPEC_IS2G(pi->radio_chanspec)) { if (pi->sh->boardflags & BFL_FEM) @@ -4946,6 +5055,7 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) wlc_lcnphy_load_tx_iir_filter(pi, true, 3); mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); + wlc_lcnphy_tssi_setup(pi); } void wlc_phy_detach_lcnphy(struct brcms_phy *pi) @@ -4984,8 +5094,7 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) return false; - if ((pi->sh->boardflags & BFL_FEM) && - (LCNREV_IS(pi->pubpi.phy_rev, 1))) { + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { if (pi_lcn->lcnphy_tempsense_option == 3) { pi->hwpwrctrl = true; pi->hwpwrctrl_capable = true; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c index 622c01c..b7e95ac 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = { }; static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, - 0x000a, 0x0009, - 0x0006, - 0x0005, 0x000a, - 0x0009, - 0x0006, 0x0005, - 0x000a, - 0x0009, 0x0006, - 0x0005, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, + 0x0009, 0x000a, + 0x0005, + 0x0006, 0x0009, + 0x000a, + 0x0005, 0x0006, + 0x0009, + 0x000a, 0x0005, + 0x0006, }; static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { -- cgit v0.10.2 From 903e0eeeb9b0d8c587ddd37fd6664a734f827b56 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 28 Nov 2012 21:44:11 +0100 Subject: brcmfmac: get rid of struct brcmf_cfg80211_info::link_up attribute This attribute indicates successful IBSS or AP connection has been established. However, this no longer works for virtual interfaces. As it turns out this attribute is identical to the CONNECTED bit in struct brcmf_cfg80211_vif::sme_state. This patch removes the attribute and rework some functions relying on it. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 2044fdb..87b3476 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -963,22 +963,21 @@ static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, } } -static void brcmf_link_down(struct brcmf_cfg80211_info *cfg) +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) { - struct net_device *ndev = NULL; s32 err = 0; WL_TRACE("Enter\n"); - if (cfg->link_up) { - ndev = cfg_to_ndev(cfg); + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) { WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); - err = brcmf_fil_cmd_data_set(netdev_priv(ndev), + err = brcmf_fil_cmd_data_set(vif->ifp, BRCMF_C_DISASSOC, NULL, 0); if (err) WL_ERR("WLC_DISASSOC failed (%d)\n", err); - cfg->link_up = false; + clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); } + clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); WL_TRACE("Exit\n"); } @@ -1130,7 +1129,6 @@ done: static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); s32 err = 0; @@ -1138,7 +1136,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) if (!check_vif_up(ifp->vif)) return -EIO; - brcmf_link_down(cfg); + brcmf_link_down(ifp->vif); WL_TRACE("Exit\n"); @@ -1496,7 +1494,6 @@ static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, u16 reason_code) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_scb_val_le scbval; @@ -1515,8 +1512,6 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, if (err) WL_ERR("error (%d)\n", err); - cfg->link_up = false; - WL_TRACE("Exit\n"); return err; } @@ -2596,17 +2591,13 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, * While going to suspend if associated with AP disassociate * from AP to save power while system is in suspended state */ - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state) || - test_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state)) { - WL_INFO("Disassociating from AP before suspend\n"); - brcmf_link_down(cfg); - - /* Make sure WPA_Supplicant receives all the event - * generated due to DISASSOC call to the fw to keep - * the state fw and WPA_Supplicant state consistent - */ - brcmf_delay(500); - } + brcmf_link_down(vif); + + /* Make sure WPA_Supplicant receives all the event + * generated due to DISASSOC call to the fw to keep + * the state fw and WPA_Supplicant state consistent + */ + brcmf_delay(500); } /* end any scanning */ @@ -3849,23 +3840,20 @@ static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) } } -static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg, - const struct brcmf_event_msg *e) +static bool brcmf_is_linkup(const struct brcmf_event_msg *e) { u32 event = e->event_code; u32 status = e->status; if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { WL_CONN("Processing set ssid\n"); - cfg->link_up = true; return true; } return false; } -static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg, - const struct brcmf_event_msg *e) +static bool brcmf_is_linkdown(const struct brcmf_event_msg *e) { u32 event = e->event_code; u16 flags = e->flags; @@ -4117,7 +4105,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, if (cfg->conf->mode == WL_MODE_AP) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); - } else if (brcmf_is_linkup(cfg, e)) { + } else if (brcmf_is_linkup(e)) { WL_CONN("Linkup\n"); if (brcmf_is_ibssmode(cfg)) { memcpy(profile->bssid, e->addr, ETH_ALEN); @@ -4129,23 +4117,16 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, &ifp->vif->sme_state); } else brcmf_bss_connect_done(cfg, ndev, e, true); - } else if (brcmf_is_linkdown(cfg, e)) { + } else if (brcmf_is_linkdown(e)) { WL_CONN("Linkdown\n"); - if (brcmf_is_ibssmode(cfg)) { - clear_bit(BRCMF_VIF_STATUS_CONNECTING, - &ifp->vif->sme_state); - if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) - brcmf_link_down(cfg); - } else { + if (!brcmf_is_ibssmode(cfg)) { brcmf_bss_connect_done(cfg, ndev, e, false); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) { + &ifp->vif->sme_state)) cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - brcmf_link_down(cfg); - } } + brcmf_link_down(ifp->vif); brcmf_init_prof(ndev_to_prof(ndev)); } else if (brcmf_is_nonetwork(cfg, e)) { if (brcmf_is_ibssmode(cfg)) @@ -4282,7 +4263,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) mutex_init(&cfg->usr_sync); brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); - brcmf_link_down(cfg); return err; } @@ -4290,7 +4270,6 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) { cfg->dongle_up = false; /* dongle down */ - brcmf_link_down(cfg); brcmf_abort_scanning(cfg); brcmf_deinit_priv_mem(cfg); } @@ -4537,11 +4516,8 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) * While going down, if associated with AP disassociate * from AP to save power */ - if ((test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state) || - test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) && - check_vif_up(ifp->vif)) { - WL_INFO("Disassociating from AP"); - brcmf_link_down(cfg); + if (check_vif_up(ifp->vif)) { + brcmf_link_down(ifp->vif); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index e2ef851..c1acda2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -359,7 +359,6 @@ struct brcmf_pno_scanresults_le { * @active_scan: current scan mode. * @sched_escan: e-scan for scheduled scan support running. * @ibss_starter: indicates this sta is ibss starter. - * @link_up: link/connection up flag. * @pwr_save: indicate whether dongle to support power save mode. * @dongle_up: indicate whether dongle up or not. * @roam_on: on/off switch for dongle self-roaming. @@ -391,7 +390,6 @@ struct brcmf_cfg80211_info { bool active_scan; bool sched_escan; bool ibss_starter; - bool link_up; bool pwr_save; bool dongle_up; bool roam_on; -- cgit v0.10.2 From 128ce3b6f3b5d3c59dd46de8fff6aef0c1d4ff51 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 28 Nov 2012 21:44:12 +0100 Subject: brcmfmac: remove mode from struct brcmf_cfg80211_conf The mode should be stored and used per virtual interface. Remove the mode from device global structure and rework the code to use the mode from brcmf_cfg80211_vif. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 87b3476..5dea1b4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -447,7 +447,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, struct vif_params *params) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif = ifp->vif; s32 infra = 0; s32 ap = 0; s32 err = 0; @@ -461,15 +461,15 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, type); return -EOPNOTSUPP; case NL80211_IFTYPE_ADHOC: - cfg->conf->mode = WL_MODE_IBSS; + vif->mode = WL_MODE_IBSS; infra = 0; break; case NL80211_IFTYPE_STATION: - cfg->conf->mode = WL_MODE_BSS; + vif->mode = WL_MODE_BSS; infra = 1; break; case NL80211_IFTYPE_AP: - cfg->conf->mode = WL_MODE_AP; + vif->mode = WL_MODE_AP; ap = 1; break; default: @@ -478,18 +478,16 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, } if (ap) { - set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); + set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); WL_INFO("IF Type = AP\n"); } else { - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), - BRCMF_C_SET_INFRA, infra); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); if (err) { WL_ERR("WLC_SET_INFRA error (%d)\n", err); err = -EAGAIN; goto done; } - WL_INFO("IF Type = %s\n", - (cfg->conf->mode == WL_MODE_IBSS) ? + WL_INFO("IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); } ndev->ieee80211_ptr->iftype = type; @@ -1711,7 +1709,6 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_wsec_key key; s32 val; @@ -1753,7 +1750,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: - if (cfg->conf->mode != WL_MODE_AP) { + if (ifp->vif->mode != WL_MODE_AP) { WL_CONN("Swapping key\n"); memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); @@ -1903,7 +1900,6 @@ static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac, struct station_info *sinfo) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_scb_val_le scb_val; @@ -1917,7 +1913,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { memcpy(&sta_info_le, mac, ETH_ALEN); err = brcmf_fil_iovar_data_get(ifp, "sta_info", &sta_info_le, @@ -1934,7 +1930,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, } WL_TRACE("STA idle time : %d ms, connected time :%d sec\n", sinfo->inactive_time, sinfo->connected_time); - } else if (cfg->conf->mode == WL_MODE_BSS) { + } else if (ifp->vif->mode == WL_MODE_BSS) { if (memcmp(mac, bssid, ETH_ALEN)) { WL_ERR("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", mac, bssid); @@ -2244,9 +2240,9 @@ CleanUp: return err; } -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_info *cfg) +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) { - return cfg->conf->mode == WL_MODE_IBSS; + return vif->mode == WL_MODE_IBSS; } /* @@ -2331,7 +2327,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) s32 err = 0; WL_TRACE("Enter\n"); - if (brcmf_is_ibssmode(cfg)) + if (brcmf_is_ibssmode(ifp->vif)) return err; ssid = &profile->ssid; @@ -3634,22 +3630,20 @@ exit: static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); s32 err = -EPERM; WL_TRACE("Enter\n"); - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { /* Due to most likely deauths outstanding we sleep */ /* first to make sure they get processed by fw. */ msleep(400); - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), - BRCMF_C_SET_AP, 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); if (err < 0) { WL_ERR("setting AP mode failed %d\n", err); goto exit; } - err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_UP, 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0); if (err < 0) { WL_ERR("BRCMF_C_UP error %d\n", err); goto exit; @@ -4103,11 +4097,11 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; s32 err = 0; - if (cfg->conf->mode == WL_MODE_AP) { + if (ifp->vif->mode == WL_MODE_AP) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); } else if (brcmf_is_linkup(e)) { WL_CONN("Linkup\n"); - if (brcmf_is_ibssmode(cfg)) { + if (brcmf_is_ibssmode(ifp->vif)) { memcpy(profile->bssid, e->addr, ETH_ALEN); wl_inform_ibss(cfg, ndev, e->addr); cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); @@ -4119,7 +4113,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, brcmf_bss_connect_done(cfg, ndev, e, true); } else if (brcmf_is_linkdown(e)) { WL_CONN("Linkdown\n"); - if (!brcmf_is_ibssmode(cfg)) { + if (!brcmf_is_ibssmode(ifp->vif)) { brcmf_bss_connect_done(cfg, ndev, e, false); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) @@ -4129,7 +4123,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, brcmf_link_down(ifp->vif); brcmf_init_prof(ndev_to_prof(ndev)); } else if (brcmf_is_nonetwork(cfg, e)) { - if (brcmf_is_ibssmode(cfg)) + if (brcmf_is_ibssmode(ifp->vif)) clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); else @@ -4178,7 +4172,6 @@ brcmf_notify_mic_status(struct brcmf_if *ifp, static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) { - conf->mode = (u32)-1; conf->frag_threshold = (u32)-1; conf->rts_threshold = (u32)-1; conf->retry_short = (u32)-1; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index c1acda2..d60de18 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -128,7 +128,6 @@ enum wl_mode { /* dongle configuration */ struct brcmf_cfg80211_conf { - u32 mode; /* adhoc , infrastructure or ap */ u32 frag_threshold; u32 rts_threshold; u32 retry_short; -- cgit v0.10.2 From b41fc3d740ae80a82167acbe848583da4a74d006 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 28 Nov 2012 21:44:13 +0100 Subject: brcmfmac: fix bug in setting mgmt ie and parsing vndrs ie. Parsing vndrs ie was not taking len of tlv itself in account. Setting mgmt ie was missing check for length indicating non configured ie and wrongly checking available length. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 5dea1b4..96bc349 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -3293,11 +3293,12 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) break; next: - remaining_len -= ie->len; - if (remaining_len <= 2) + remaining_len -= (ie->len + TLV_HDR_LEN); + if (remaining_len <= TLV_HDR_LEN) ie = NULL; else - ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len); + ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len + + TLV_HDR_LEN); } return err; } @@ -3396,11 +3397,11 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, } } - if (mgmt_ie_buf != NULL) { + if (mgmt_ie_buf && *mgmt_ie_len) { if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { - WL_TRACE("Previous mgmt IE is equals to current IE"); + WL_TRACE("Previous mgmt IE equals to current IE\n"); goto exit; } @@ -3438,6 +3439,16 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, for (i = 0; i < new_vndr_ies.count; i++) { vndrie_info = &new_vndr_ies.ie_info[i]; + /* verify remained buf size before copy data */ + if (remained_buf_len < (vndrie_info->vndrie.len + + VNDR_IE_VSIE_OFFSET)) { + WL_ERR("no space in mgmt_ie_buf: len left %d", + remained_buf_len); + break; + } + remained_buf_len -= (vndrie_info->ie_len + + VNDR_IE_VSIE_OFFSET); + WL_TRACE("ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n", vndrie_info->vndrie.id, vndrie_info->vndrie.len, @@ -3449,13 +3460,6 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, vndrie_info->ie_ptr, vndrie_info->ie_len, "add"); - /* verify remained buf size before copy data */ - remained_buf_len -= vndrie_info->ie_len; - if (remained_buf_len < 0) { - WL_ERR("no space in mgmt_ie_buf: len left %d", - remained_buf_len); - break; - } /* save the parsed IE in wl struct */ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, -- cgit v0.10.2 From 1b4e027e1b1176b70a59665c0de58c04c7a4e210 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 28 Nov 2012 21:44:14 +0100 Subject: brcmfmac: change debug output for received event. see header. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index fa8fc44..7a00c46 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -314,7 +314,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) while ((event = brcmf_fweh_dequeue_event(fweh))) { ifp = drvr->iflist[event->ifidx]; - brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n", + brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", brcmf_fweh_event_name(event->code), event->code, event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.addr); @@ -337,7 +337,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) emsg.version, emsg.flags, emsg.status, emsg.reason); brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, min_t(u32, emsg.datalen, 64), - "appended:"); + "event payload, len=%d\n", emsg.datalen); /* special handling of interface event */ if (event->code == BRCMF_E_IF) { -- cgit v0.10.2 From 904f137d478215b7c5c1daabae03618ed2f703cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Nov 2012 21:53:45 +0100 Subject: mwifiex: fix struct member mismatch Using bss->information_elements and treating bss->len_beacon_ies as its size is wrong, the real size is len_information_elements. Found while I was reviewing the use of this cfg80211 API (as it is actually potentially broken due to races.) Signed-off-by: Johannes Berg Acked-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 237c8d2b..cf8918c 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -161,8 +161,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, int ret; u8 *beacon_ie; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; + size_t beacon_ie_len = bss->len_information_elements; - beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies, + beacon_ie = kmemdup(bss->information_elements, beacon_ie_len, GFP_KERNEL); if (!beacon_ie) { dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); @@ -172,7 +173,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); bss_desc->rssi = bss->signal; bss_desc->beacon_buf = beacon_ie; - bss_desc->beacon_buf_size = bss->len_beacon_ies; + bss_desc->beacon_buf_size = beacon_ie_len; bss_desc->beacon_period = bss->beacon_interval; bss_desc->cap_info_bitmap = bss->capability; bss_desc->bss_band = bss_priv->band; -- cgit v0.10.2 From dac67975f3dc8565e4254b1d7a49618494f1a2f1 Mon Sep 17 00:00:00 2001 From: Daniel Stamer Date: Thu, 29 Nov 2012 17:09:26 +0100 Subject: rtlwifi: rtl8192se: Fixed coding style issues in the driver This patch fixes almost all coding issues in the rtl8192se driver. Only exception is putting trailing */ on separate lines. Signed-off-by: Daniel Stamer Acked-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h index 20afec6..2d255e0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -522,8 +522,7 @@ enum fwcmd_iotype { FW_CMD_IQK_ENABLE = 30, }; -/* - * Driver info contain PHY status +/* Driver info contain PHY status * and other variabel size info * PHY Status content as below */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index bf79a52..e551fe5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -465,8 +465,8 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) digtable->cur_igvalue = digtable->rx_gain_range_min; else - digtable->cur_igvalue = digtable->rssi_val + 10 - - digtable->back_val; + digtable->cur_igvalue = digtable->rssi_val + 10 + - digtable->back_val; if (falsealm_cnt->cnt_all > 10000) digtable->cur_igvalue = @@ -518,7 +518,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *digtable = &rtlpriv->dm_digtable; + struct dig_t *dig = &rtlpriv->dm_digtable; if (rtlpriv->mac80211.act_scanning) return; @@ -526,17 +526,17 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) /* Decide the current status and if modify initial gain or not */ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED || rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) - digtable->cur_sta_cstate = DIG_STA_CONNECT; + dig->cur_sta_cstate = DIG_STA_CONNECT; else - digtable->cur_sta_cstate = DIG_STA_DISCONNECT; + dig->cur_sta_cstate = DIG_STA_DISCONNECT; - digtable->rssi_val = rtlpriv->dm.undec_sm_pwdb; + dig->rssi_val = rtlpriv->dm.undec_sm_pwdb; /* Change dig mode to rssi */ - if (digtable->cur_sta_cstate != DIG_STA_DISCONNECT) { - if (digtable->dig_twoport_algorithm == + if (dig->cur_sta_cstate != DIG_STA_DISCONNECT) { + if (dig->dig_twoport_algorithm == DIG_TWO_PORT_ALGO_FALSE_ALARM) { - digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + dig->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); } } @@ -544,7 +544,7 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) _rtl92s_dm_false_alarm_counter_statistics(hw); _rtl92s_dm_initial_gain_sta_beforeconnect(hw); - digtable->pre_sta_cstate = digtable->cur_sta_cstate; + dig->pre_sta_cstate = dig->cur_sta_cstate; } static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 1d72779..28526a7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1089,8 +1089,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) return err; } -void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr) +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr) { + /* This is a stub. */ } void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h index 1886c26..a8e068c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h @@ -54,7 +54,7 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw); int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); -void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr); +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr); void rtl92se_set_qos(struct ieee80211_hw *hw, int aci); void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw); void rtl92se_set_beacon_interval(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index ad4b480..c725133 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -50,8 +50,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) /*close ASPM for AMD defaultly */ rtlpci->const_amdpci_aspm = 0; - /* - * ASPM PS mode. + /* ASPM PS mode. * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, * 2 - Enable ASPM with Clock Req, @@ -67,8 +66,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) /*Setting for PCI-E bridge */ rtlpci->const_hostpci_aspm_setting = 0x02; - /* - * In Hw/Sw Radio Off situation. + /* In Hw/Sw Radio Off situation. * 0 - Default, * 1 - From ASPM setting without low Mac Pwr, * 2 - From ASPM setting with low Mac Pwr, @@ -77,8 +75,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) */ rtlpci->const_hwsw_rfoff_d3 = 2; - /* - * This setting works for those device with + /* This setting works for those device with * backdoor ASPM setting such as EPHY setting. * 0 - Not support ASPM, * 1 - Support ASPM, -- cgit v0.10.2 From 88427588993db079a1b2cdbcba69f3c162f8ee21 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 29 Nov 2012 23:27:15 +0100 Subject: ath9k: use SIMPLE_DEV_PM_OPS ath9k does not provide any runtime pm callbacks, so support for PM_RUNTIME is not needed and we could go to PM_SLEEP. This also makes it possible to use SIMPLE_DEV_PM_OPS instead of manually filling struct dev_pm_ops. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 9553203..8e9b826 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -287,7 +287,7 @@ static void ath_pci_remove(struct pci_dev *pdev) pci_release_region(pdev, 0); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ath_pci_suspend(struct device *device) { @@ -333,22 +333,15 @@ static int ath_pci_resume(struct device *device) return 0; } -static const struct dev_pm_ops ath9k_pm_ops = { - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, - .freeze = ath_pci_suspend, - .thaw = ath_pci_resume, - .poweroff = ath_pci_suspend, - .restore = ath_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(ath9k_pm_ops, ath_pci_suspend, ath_pci_resume); #define ATH9K_PM_OPS (&ath9k_pm_ops) -#else /* !CONFIG_PM */ +#else /* !CONFIG_PM_SLEEP */ #define ATH9K_PM_OPS NULL -#endif /* !CONFIG_PM */ +#endif /* !CONFIG_PM_SLEEP */ MODULE_DEVICE_TABLE(pci, ath_pci_id_table); -- cgit v0.10.2 From 88823492736a43f04d2ee114e0ec2b7725d3be35 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 29 Nov 2012 23:27:16 +0100 Subject: p54pci: use SIMPLE_DEV_PM_OPS p54pci does not provide any runtime pm callbacks, so support for PM_RUNTIME is not needed and we could go to PM_SLEEP. This also makes it possible to use SIMPLE_DEV_PM_OPS instead of manually filling struct dev_pm_ops. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index b439079..810c343 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -659,7 +659,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev) p54_free_common(dev); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int p54p_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); @@ -681,19 +681,12 @@ static int p54p_resume(struct device *device) return pci_set_power_state(pdev, PCI_D0); } -static const struct dev_pm_ops p54pci_pm_ops = { - .suspend = p54p_suspend, - .resume = p54p_resume, - .freeze = p54p_suspend, - .thaw = p54p_resume, - .poweroff = p54p_suspend, - .restore = p54p_resume, -}; +static SIMPLE_DEV_PM_OPS(p54pci_pm_ops, p54p_suspend, p54p_resume); #define P54P_PM_OPS (&p54pci_pm_ops) #else #define P54P_PM_OPS (NULL) -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static struct pci_driver p54p_driver = { .name = "p54pci", -- cgit v0.10.2 From 244a77e9d708d5a23eed21a4fb62a62acc9c69a6 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 29 Nov 2012 23:27:17 +0100 Subject: rtlwifi: use SIMPLE_DEV_PM_OPS rtlwifi only provides pm callbacks for functions covered by pm sleep and they are also just called if CONFIG_PM_SLEEP is set. Only add functions rtl_pci_suspend and rtl_pci_resume if CONFIG_PM_SLEEP is set and use SIMPLE_DEV_PM_OPS instead of manually filling struct dev_pm_ops. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index f38e30a..086140c 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1982,6 +1982,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev) } EXPORT_SYMBOL(rtl_pci_disconnect); +#ifdef CONFIG_PM_SLEEP /*************************************** kernel pci power state define: PCI_D0 ((pci_power_t __force) 0) @@ -2021,6 +2022,7 @@ int rtl_pci_resume(struct device *dev) return 0; } EXPORT_SYMBOL(rtl_pci_resume); +#endif /* CONFIG_PM_SLEEP */ struct rtl_intf_ops rtl_pci_ops = { .read_efuse_byte = read_efuse_byte, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index f71b12a..7ea50a3 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -239,8 +239,10 @@ extern struct rtl_intf_ops rtl_pci_ops; int __devinit rtl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtl_pci_disconnect(struct pci_dev *pdev); +#ifdef CONFIG_PM_SLEEP int rtl_pci_suspend(struct device *dev); int rtl_pci_resume(struct device *dev); +#endif /* CONFIG_PM_SLEEP */ static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) { return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 60451ee..49f663b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -372,14 +372,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl92ce_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index 480862c..e17f670 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -378,14 +378,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl92de_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index c725133..45c3443 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -429,14 +429,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl92se_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c index 0afdc24..18b0bc5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -367,14 +367,7 @@ MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const struct dev_pm_ops rtlwifi_pm_ops = { - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, - .freeze = rtl_pci_suspend, - .thaw = rtl_pci_resume, - .poweroff = rtl_pci_suspend, - .restore = rtl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl8723ae_driver = { .name = KBUILD_MODNAME, -- cgit v0.10.2 From 697978383e94fff79fc72d9dbf1a03db8ac9784a Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 30 Nov 2012 22:08:31 +0900 Subject: wireless: mwifiex: Fix typo in wireless/mwifiex driver Correct spelling typo in wireless/mwifiex driver. Signed-off-by: Masanari Iida Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index cf8918c..95e3ab5 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -462,7 +462,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) } if (adapter->hs_activated) { - dev_dbg(adapter->dev, "cmd: HS Already actived\n"); + dev_dbg(adapter->dev, "cmd: HS Already activated\n"); return true; } diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index bbe1f35..63ac9f2 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -351,7 +351,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf, card->udev = udev; card->intf = intf; - pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocl=%#x\n", + pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); -- cgit v0.10.2 From 55cec505559dade9e7776de8f3d23fc3e54e091d Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Thu, 29 Nov 2012 07:36:00 -0600 Subject: brcmsmac: Fix possible NULL pointer dereference in _dma_ctrlflags() There's a debug message to warn if this function is passed a NULL pointer, but in order to print the message we have to dereference the pointer. Obviously this isn't a good idea, so remove the message. Reported-by: Fengguang Wu Signed-off-by: Seth Forshee Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 511e457..1860c57 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -349,10 +349,8 @@ static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) { uint dmactrlflags; - if (di == NULL) { - brcms_dbg_dma(di->core, "NULL dma handle\n"); + if (di == NULL) return 0; - } dmactrlflags = di->dma.dmactrlflags; dmactrlflags &= ~mask; -- cgit v0.10.2 From 5d7fad48ca763f6b20c2d4daf7df9fd7aa2cb242 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Fri, 30 Nov 2012 19:17:28 +0100 Subject: mac80211: Fix typo in mac80211.h Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0472d80..1c02fb3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -164,7 +164,7 @@ enum ieee80211_chanctx_change { * active on the channel to receive MIMO transmissions * @rx_chains_dynamic: The number of RX chains that must be enabled * after RTS/CTS handshake to receive SMPS MIMO transmissions; - * this will always be >= @rx_chains_always. + * this will always be >= @rx_chains_static. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. */ -- cgit v0.10.2 From 246dc3fddf4a01bb47dd56215a48dd2b270520db Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Fri, 30 Nov 2012 19:17:27 +0100 Subject: mac80211: return if CSA is not handle If channel contexts are enabled, the CSA should not be processed further. A return is missing here. Signed-off-by: Simon Wunderlich Signed-off-by: Johannes Berg diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 481d503..0955630 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -789,6 +789,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, "not handling channel switch with channel contexts\n"); ieee80211_queue_work(&sdata->local->hw, &ifmgd->csa_connection_drop_work); + return; } mutex_lock(&sdata->local->chanctx_mtx); -- cgit v0.10.2 From da29d2a5780d80857773d7776b7603a449b0b6e0 Mon Sep 17 00:00:00 2001 From: Marco Porsch Date: Mon, 3 Dec 2012 11:23:37 +0100 Subject: cfg80211: fix channel error on mesh join Fix an error on mesh join when no channel has been explicitly set beforehand. Also remove a double semicolon. Signed-off-by: Marco Porsch Signed-off-by: Johannes Berg diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 3ee5a72..f9d6ce5 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -146,7 +146,8 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!setup->chandef.chan) return -EINVAL; - setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;; + setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT; + setup->chandef.center_freq1 = setup->chandef.chan->center_freq; } if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) -- cgit v0.10.2 From dc2a0e20fbc85a71c63aa4330b496fda33f6bf80 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 20 Nov 2012 23:25:54 -0200 Subject: Bluetooth: Add missing lock nesting notation This patch fixes the following report, it happens when accepting rfcomm connections: [ 228.165378] ============================================= [ 228.165378] [ INFO: possible recursive locking detected ] [ 228.165378] 3.7.0-rc1-00536-gc1d5dc4 #120 Tainted: G W [ 228.165378] --------------------------------------------- [ 228.165378] bluetoothd/1341 is trying to acquire lock: [ 228.165378] (sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM){+.+...}, at: [] bt_accept_dequeue+0xa0/0x180 [bluetooth] [ 228.165378] [ 228.165378] but task is already holding lock: [ 228.165378] (sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM){+.+...}, at: [] rfcomm_sock_accept+0x58/0x2d0 [rfcomm] [ 228.165378] [ 228.165378] other info that might help us debug this: [ 228.165378] Possible unsafe locking scenario: [ 228.165378] [ 228.165378] CPU0 [ 228.165378] ---- [ 228.165378] lock(sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM); [ 228.165378] lock(sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM); [ 228.165378] [ 228.165378] *** DEADLOCK *** [ 228.165378] [ 228.165378] May be due to missing lock nesting notation Cc: stable@vger.kernel.org Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 4ddef57..ce3f665 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -467,7 +467,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f long timeo; int err = 0; - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); if (sk->sk_type != SOCK_STREAM) { err = -EINVAL; @@ -504,7 +504,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f release_sock(sk); timeo = schedule_timeout(timeo); - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); } __set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); -- cgit v0.10.2 From b9b5ef188e5a2222cfc16ef62a4703080750b451 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 21 Nov 2012 00:50:21 -0200 Subject: Bluetooth: cancel power_on work when unregistering the device We need to cancel the hci_power_on work in order to avoid it run when we try to free the hdev. [ 1434.201149] ------------[ cut here ]------------ [ 1434.204998] WARNING: at lib/debugobjects.c:261 debug_print_object+0x8e/0xb0() [ 1434.208324] ODEBUG: free active (active state 0) object type: work_struct hint: hci _power_on+0x0/0x90 [ 1434.210386] Pid: 8564, comm: trinity-child25 Tainted: G W 3.7.0-rc5-next- 20121112-sasha-00018-g2f4ce0e #127 [ 1434.210760] Call Trace: [ 1434.210760] [] ? debug_print_object+0x8e/0xb0 [ 1434.210760] [] warn_slowpath_common+0x87/0xb0 [ 1434.210760] [] warn_slowpath_fmt+0x41/0x50 [ 1434.210760] [] debug_print_object+0x8e/0xb0 [ 1434.210760] [] ? hci_dev_open+0x310/0x310 [ 1434.210760] [] ? _raw_spin_unlock_irqrestore+0x55/0xa0 [ 1434.210760] [] __debug_check_no_obj_freed+0xa5/0x230 [ 1434.210760] [] ? bt_host_release+0x10/0x20 [ 1434.210760] [] debug_check_no_obj_freed+0x15/0x20 [ 1434.210760] [] kfree+0x227/0x330 [ 1434.210760] [] bt_host_release+0x10/0x20 [ 1434.210760] [] device_release+0x65/0xc0 [ 1434.210760] [] kobject_cleanup+0x145/0x190 [ 1434.210760] [] kobject_release+0xd/0x10 [ 1434.210760] [] kobject_put+0x4c/0x60 [ 1434.210760] [] put_device+0x12/0x20 [ 1434.210760] [] hci_free_dev+0x24/0x30 [ 1434.210760] [] vhci_release+0x31/0x60 [ 1434.210760] [] __fput+0x122/0x250 [ 1434.210760] [] ? rcu_user_exit+0x9d/0xd0 [ 1434.210760] [] ____fput+0x9/0x10 [ 1434.210760] [] task_work_run+0xb2/0xf0 [ 1434.210760] [] do_notify_resume+0x77/0xa0 [ 1434.210760] [] int_signal+0x12/0x17 [ 1434.210760] ---[ end trace a6d57fefbc8a8cc7 ]--- Cc: stable@vger.kernel.org Reported-by: Sasha Levin Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 81f4bac..69eb644 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1854,6 +1854,8 @@ void hci_unregister_dev(struct hci_dev *hdev) for (i = 0; i < NUM_REASSEMBLY; i++) kfree_skb(hdev->reassembly[i]); + cancel_work_sync(&hdev->power_on); + if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); -- cgit v0.10.2 From b96e9c671b05f95126753a22145d4509d45ca197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Dalleau?= Date: Wed, 21 Nov 2012 10:51:11 +0100 Subject: Bluetooth: Add BT_DEFER_SETUP option to sco socket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option will set the BT_SK_DEFER_SETUP bit in socket flags. Signed-off-by: Frédéric Dalleau Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 450cdcd..c6678f2 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -666,12 +666,31 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char { struct sock *sk = sock->sk; int err = 0; + u32 opt; BT_DBG("sk %p", sk); lock_sock(sk); switch (optname) { + + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + break; + default: err = -ENOPROTOOPT; break; @@ -753,6 +772,19 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char lock_sock(sk); switch (optname) { + + case BT_DEFER_SETUP: + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { + err = -EINVAL; + break; + } + + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) + err = -EFAULT; + + break; + default: err = -ENOPROTOOPT; break; -- cgit v0.10.2 From 20714bfef84d3e690c9c6f8e9cd46543b5ae1eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Dalleau?= Date: Wed, 21 Nov 2012 10:51:12 +0100 Subject: Bluetooth: Implement deferred sco socket setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to authenticate and configure an incoming SCO connection, the BT_DEFER_SETUP option was added. This option is intended to defer reply to Connect Request on SCO sockets. When a connection is requested, the listening socket is unblocked but the effective connection setup happens only on first recv. Any send between accept and recv fails with -ENOTCONN. Signed-off-by: Frédéric Dalleau Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ef5b85d..76891a9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -376,7 +376,7 @@ extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt); extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); -extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); +extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status); extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); @@ -577,6 +577,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); int hci_conn_del(struct hci_conn *conn); void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); +void hci_conn_accept(struct hci_conn *conn, int mask); struct hci_chan *hci_chan_create(struct hci_conn *conn); void hci_chan_del(struct hci_chan *chan); @@ -779,8 +780,10 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR) /* ----- HCI protocols ----- */ +#define HCI_PROTO_DEFER 0x01 + static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, - __u8 type) + __u8 type, __u8 *flags) { switch (type) { case ACL_LINK: @@ -788,7 +791,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, case SCO_LINK: case ESCO_LINK: - return sco_connect_ind(hdev, bdaddr); + return sco_connect_ind(hdev, bdaddr, flags); default: BT_ERR("unknown link type %d", type); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9f5c5f2..3843f18 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2047,15 +2047,53 @@ unlock: hci_conn_check_pending(hdev); } +void hci_conn_accept(struct hci_conn *conn, int mask) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p", conn); + + conn->state = BT_CONFIG; + + if (!lmp_esco_capable(hdev)) { + struct hci_cp_accept_conn_req cp; + + bacpy(&cp.bdaddr, &conn->dst); + + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + cp.role = 0x00; /* Become master */ + else + cp.role = 0x01; /* Remain slave */ + + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); + } else /* lmp_esco_capable(hdev)) */ { + struct hci_cp_accept_sync_conn_req cp; + + bacpy(&cp.bdaddr, &conn->dst); + cp.pkt_type = cpu_to_le16(conn->pkt_type); + + cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.max_latency = __constant_cpu_to_le16(0xffff); + cp.content_format = cpu_to_le16(hdev->voice_setting); + cp.retrans_effort = 0xff; + + hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, + sizeof(cp), &cp); + } +} + static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; int mask = hdev->link_mode; + __u8 flags = 0; BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, ev->link_type); - mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); + mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, + &flags); if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) { @@ -2081,12 +2119,13 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) } memcpy(conn->dev_class, ev->dev_class, 3); - conn->state = BT_CONNECT; hci_dev_unlock(hdev); - if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) { + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { struct hci_cp_accept_conn_req cp; + conn->state = BT_CONNECT; bacpy(&cp.bdaddr, &ev->bdaddr); @@ -2097,8 +2136,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); - } else { + } else if (!(flags & HCI_PROTO_DEFER)) { struct hci_cp_accept_sync_conn_req cp; + conn->state = BT_CONNECT; bacpy(&cp.bdaddr, &ev->bdaddr); cp.pkt_type = cpu_to_le16(conn->pkt_type); @@ -2111,6 +2151,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(cp), &cp); + } else { + conn->state = BT_CONNECT2; + hci_proto_connect_cfm(conn, 0); + hci_conn_put(conn); } } else { /* Connection rejected */ diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c6678f2..eea17cd 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -397,6 +397,7 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) if (parent) { sk->sk_type = parent->sk_type; + bt_sk(sk)->flags = bt_sk(parent)->flags; security_sk_clone(parent, sk); } } @@ -662,6 +663,28 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; } +static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags) +{ + struct sock *sk = sock->sk; + struct sco_pinfo *pi = sco_pi(sk); + + lock_sock(sk); + + if (sk->sk_state == BT_CONNECT2 && + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { + hci_conn_accept(pi->conn->hcon, 0); + sk->sk_state = BT_CONFIG; + + release_sock(sk); + return 0; + } + + release_sock(sk); + + return bt_sock_recvmsg(iocb, sock, msg, len, flags); +} + static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; @@ -906,7 +929,10 @@ static void sco_conn_ready(struct sco_conn *conn) hci_conn_hold(conn->hcon); __sco_chan_add(conn, sk, parent); - sk->sk_state = BT_CONNECTED; + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) + sk->sk_state = BT_CONNECT2; + else + sk->sk_state = BT_CONNECTED; /* Wake up parent */ parent->sk_data_ready(parent, 1); @@ -919,7 +945,7 @@ done: } /* ----- SCO interface with lower layer (HCI) ----- */ -int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) +int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) { struct sock *sk; struct hlist_node *node; @@ -936,6 +962,9 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) || !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm |= HCI_LM_ACCEPT; + + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) + *flags |= HCI_PROTO_DEFER; break; } } @@ -1024,7 +1053,7 @@ static const struct proto_ops sco_sock_ops = { .accept = sco_sock_accept, .getname = sco_sock_getname, .sendmsg = sco_sock_sendmsg, - .recvmsg = bt_sock_recvmsg, + .recvmsg = sco_sock_recvmsg, .poll = bt_sock_poll, .ioctl = bt_sock_ioctl, .mmap = sock_no_mmap, -- cgit v0.10.2 From ffa88e02bc67a1496fae762ad899e8f49136e7a1 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 23 Nov 2012 16:50:51 -0200 Subject: Bluetooth: Move double negation to macros Some comparisons needs to double negation(!!) in order to make the value of the field boolean. Add it to the macro makes the code more readable. Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 76891a9..2f2b743 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -767,7 +767,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) #define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC) #define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ) -#define lmp_le_br_capable(dev) ((dev)->features[6] & LMP_SIMUL_LE_BR) +#define lmp_le_br_capable(dev) !!((dev)->features[6] & LMP_SIMUL_LE_BR) #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) #define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO) @@ -776,8 +776,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn); /* ----- Extended LMP capabilities ----- */ #define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP) -#define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE) -#define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR) +#define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE) +#define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR) /* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3843f18..705078a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -794,10 +794,10 @@ static void hci_set_le_support(struct hci_dev *hdev) if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; - cp.simul = !!lmp_le_br_capable(hdev); + cp.simul = lmp_le_br_capable(hdev); } - if (cp.le != !!lmp_host_le_capable(hdev)) + if (cp.le != lmp_host_le_capable(hdev)) hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index dedbb1d..5d0ef75 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1225,7 +1225,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } val = !!cp->val; - enabled = !!lmp_host_le_capable(hdev); + enabled = lmp_host_le_capable(hdev); if (!hdev_is_powered(hdev) || val == enabled) { bool changed = false; @@ -1261,7 +1261,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (val) { hci_cp.le = val; - hci_cp.simul = !!lmp_le_br_capable(hdev); + hci_cp.simul = lmp_le_br_capable(hdev); } err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), @@ -2924,13 +2924,13 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) struct hci_cp_write_le_host_supported cp; cp.le = 1; - cp.simul = !!lmp_le_br_capable(hdev); + cp.simul = lmp_le_br_capable(hdev); /* Check first if we already have the right * host state (host features set) */ - if (cp.le != !!lmp_host_le_capable(hdev) || - cp.simul != !!lmp_host_le_br_capable(hdev)) + if (cp.le != lmp_host_le_capable(hdev) || + cp.simul != lmp_host_le_br_capable(hdev)) hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); -- cgit v0.10.2 From 5e4e3972b8da23e270fa37670caec4d32f2197f7 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Nov 2012 17:59:39 +0200 Subject: Bluetooth: Refactor l2cap_send_disconn_req l2cap_send_disconn_req takes 3 parameters of which conn might be derived from chan. Make this conversion inside l2cap_send_disconn_req. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b52f66d..f7ee037 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -53,8 +53,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); -static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err); +static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err); static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control, struct sk_buff_head *skbs, u8 event); @@ -632,7 +631,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && conn->hcon->type == ACL_LINK) { __set_chan_timer(chan, sk->sk_sndtimeo); - l2cap_send_disconn_req(conn, chan, reason); + l2cap_send_disconn_req(chan, reason); } else l2cap_chan_del(chan, reason); break; @@ -1180,10 +1179,10 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) } } -static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err) +static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct l2cap_disconn_req req; if (!conn) @@ -1960,7 +1959,7 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) if (chan->max_tx != 0 && bt_cb(skb)->control.retries > chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); l2cap_seq_list_clear(&chan->retrans_list); break; } @@ -2666,7 +2665,7 @@ static void l2cap_tx_state_wait_f(struct l2cap_chan *chan, __set_monitor_timer(chan); chan->retry_count++; } else { - l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan, ECONNABORTED); } break; default: @@ -3877,7 +3876,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, /* Complete config. */ len = l2cap_parse_conf_req(chan, rsp); if (len < 0) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto unlock; } @@ -3899,7 +3898,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, err = l2cap_ertm_init(chan); if (err < 0) - l2cap_send_disconn_req(chan->conn, chan, -err); + l2cap_send_disconn_req(chan, -err); else l2cap_chan_ready(chan); @@ -3967,7 +3966,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, len = l2cap_parse_conf_rsp(chan, rsp->data, len, buf, &result); if (len < 0) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -3988,7 +3987,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -3997,7 +3996,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, len = l2cap_parse_conf_rsp(chan, rsp->data, len, req, &result); if (len < 0) { - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -4013,7 +4012,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_chan_set_err(chan, ECONNRESET); __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); - l2cap_send_disconn_req(conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto done; } @@ -4030,7 +4029,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, err = l2cap_ertm_init(chan); if (err < 0) - l2cap_send_disconn_req(chan->conn, chan, -err); + l2cap_send_disconn_req(chan, -err); else l2cap_chan_ready(chan); } @@ -4392,7 +4391,7 @@ static void l2cap_logical_fail(struct l2cap_chan *chan) /* Logical link setup failed */ if (chan->state != BT_CONNECTED) { /* Create channel failure, disconnect */ - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -4435,7 +4434,7 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan, err = l2cap_ertm_init(chan); if (err < 0) - l2cap_send_disconn_req(chan->conn, chan, -err); + l2cap_send_disconn_req(chan, -err); else l2cap_chan_ready(chan); } @@ -5400,7 +5399,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan, if (control->reqseq == chan->next_tx_seq) { BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5414,7 +5413,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan, if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5458,7 +5457,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan, if (control->reqseq == chan->next_tx_seq) { BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5467,7 +5466,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan, if (chan->max_tx && skb && bt_cb(skb)->control.retries >= chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); return; } @@ -5651,8 +5650,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan, break; case L2CAP_TXSEQ_INVALID: default: - l2cap_send_disconn_req(chan->conn, chan, - ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); break; } break; @@ -5785,8 +5783,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan, break; case L2CAP_TXSEQ_INVALID: default: - l2cap_send_disconn_req(chan->conn, chan, - ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); break; } break; @@ -5981,7 +5978,7 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d", control->reqseq, chan->next_tx_seq, chan->expected_ack_seq); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); } return err; @@ -6050,7 +6047,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) len -= L2CAP_FCS_SIZE; if (len > chan->mps) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto drop; } @@ -6075,8 +6072,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) } if (err) - l2cap_send_disconn_req(chan->conn, chan, - ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); } else { const u8 rx_func_to_event[4] = { L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ, @@ -6093,7 +6089,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) if (len != 0) { BT_ERR("Trailing bytes: %d in sframe", len); - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); goto drop; } @@ -6104,7 +6100,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) event = rx_func_to_event[control->super]; if (l2cap_rx(chan, control, skb, event)) - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan, ECONNRESET); } return 0; -- cgit v0.10.2 From ced5c338d7b696021058c23fb6a286def2171df5 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Nov 2012 17:59:42 +0200 Subject: Bluetooth: AMP: Mark controller radio powered down after HCIDEVDOWN After getting HCIDEVDOWN controller did not mark itself as 0x00 which means: "The Controller radio is available but is currently physically powered down". The result was even if the hdev was down we return in controller list value 0x01 "status 0x01 (Bluetooth only)". Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 69eb644..ec7d3a7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -861,6 +861,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Clear flags */ hdev->flags = 0; + /* Controller radio is available but is currently powered down */ + hdev->amp_status = 0; + memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); -- cgit v0.10.2 From 5d05416e0907b0dd30b62b002bed3b85e6efbd61 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 29 Nov 2012 17:46:05 +0200 Subject: Bluetooth: AMP: Check that AMP is present and active Before starting quering remote AMP controllers make sure that there is local active AMP controller. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2f2b743..014a2ea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -779,6 +779,22 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE) #define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR) +/* returns true if at least one AMP active */ +static inline bool hci_amp_capable(void) +{ + struct hci_dev *hdev; + bool ret = false; + + read_lock(&hci_dev_list_lock); + list_for_each_entry(hdev, &hci_dev_list, list) + if (hdev->amp_type == HCI_AMP && + test_bit(HCI_UP, &hdev->flags)) + ret = true; + read_unlock(&hci_dev_list_lock); + + return ret; +} + /* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f7ee037..d8cffdb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1013,6 +1013,7 @@ static bool __amp_capable(struct l2cap_chan *chan) struct l2cap_conn *conn = chan->conn; if (enable_hs && + hci_amp_capable() && chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED && conn->fixed_chan_mask & L2CAP_FC_A2MP) return true; -- cgit v0.10.2 From 60918918a9f3455859a4be0d4e381003cbdb843f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 29 Nov 2012 17:46:06 +0200 Subject: Bluetooth: Fix missing L2CAP EWS Conf parameter If L2CAP_FEAT_FCS is not supported we sould miss EWS option configuration because of break. Make code more readable by combining FCS configuration in the single block. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d8cffdb..d22d183 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3106,18 +3106,17 @@ done: if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) l2cap_add_opt_efs(&ptr, chan); - if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) - break; - - if (chan->fcs == L2CAP_FCS_NONE || - test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { - chan->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); - } - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, chan->tx_win); + + if (chan->conn->feat_mask & L2CAP_FEAT_FCS) + if (chan->fcs == L2CAP_FCS_NONE || + test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, + chan->fcs); + } break; case L2CAP_MODE_STREAMING: @@ -3139,14 +3138,13 @@ done: if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) l2cap_add_opt_efs(&ptr, chan); - if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) - break; - - if (chan->fcs == L2CAP_FCS_NONE || - test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { - chan->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); - } + if (chan->conn->feat_mask & L2CAP_FEAT_FCS) + if (chan->fcs == L2CAP_FCS_NONE || + test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, + chan->fcs); + } break; } -- cgit v0.10.2 From cbabee788ff881b87bbaf258caf080b49a61fa43 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 29 Nov 2012 17:46:07 +0200 Subject: Bluetooth: Process receiving FCS_NONE in L2CAP Conf Rsp Process L2CAP Config rsp Pending with FCS Option 0x00 (No FCS) which is sent by Motorola Windows 7 Bluetooth stack. The trace is shown below (all other options are skipped). ... < ACL data: handle 1 flags 0x00 dlen 48 L2CAP(s): Config req: dcid 0x0043 flags 0x00 clen 36 ... FCS Option 0x00 (No FCS) > ACL data: handle 1 flags 0x02 dlen 48 L2CAP(s): Config req: dcid 0x0041 flags 0x00 clen 36 ... FCS Option 0x01 (CRC16 Check) < ACL data: handle 1 flags 0x00 dlen 47 L2CAP(s): Config rsp: scid 0x0043 flags 0x00 result 4 clen 33 Pending ... > ACL data: handle 1 flags 0x02 dlen 50 L2CAP(s): Config rsp: scid 0x0041 flags 0x00 result 4 clen 36 Pending ... FCS Option 0x00 (No FCS) < ACL data: handle 1 flags 0x00 dlen 14 L2CAP(s): Config rsp: scid 0x0043 flags 0x00 result 0 clen 0 Success > ACL data: handle 1 flags 0x02 dlen 14 L2CAP(s): Config rsp: scid 0x0041 flags 0x00 result 0 clen 0 Success ... Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d22d183..8c43277 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3431,6 +3431,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), (unsigned long) &efs); break; + + case L2CAP_CONF_FCS: + if (*result == L2CAP_CONF_PENDING) + if (val == L2CAP_FCS_NONE) + set_bit(CONF_NO_FCS_RECV, + &chan->conf_state); + break; } } -- cgit v0.10.2 From f2592d3ee3c5817981f343b90bfb9c5612f38d23 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 29 Nov 2012 17:46:08 +0200 Subject: Bluetooth: trivial: Change NO_FCS_RECV to RECV_NO_FCS Make code more readable by changing CONF_NO_FCS_RECV which is read as "No L2CAP FCS option received" to CONF_RECV_NO_FCS which means "Received L2CAP option NO_FCS". This flag really means that we have received L2CAP FRAME CHECK SEQUENCE (FCS) OPTION with value "No FCS". Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f57fab0..7588ef4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -611,7 +611,7 @@ enum { CONF_MTU_DONE, CONF_MODE_DONE, CONF_CONNECT_PEND, - CONF_NO_FCS_RECV, + CONF_RECV_NO_FCS, CONF_STATE2_DEVICE, CONF_EWS_RECV, CONF_LOC_CONF_PEND, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8c43277..2c78208 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3112,7 +3112,7 @@ done: if (chan->conn->feat_mask & L2CAP_FEAT_FCS) if (chan->fcs == L2CAP_FCS_NONE || - test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { + test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) { chan->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); @@ -3140,7 +3140,7 @@ done: if (chan->conn->feat_mask & L2CAP_FEAT_FCS) if (chan->fcs == L2CAP_FCS_NONE || - test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { + test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) { chan->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); @@ -3196,7 +3196,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_CONF_FCS: if (val == L2CAP_FCS_NONE) - set_bit(CONF_NO_FCS_RECV, &chan->conf_state); + set_bit(CONF_RECV_NO_FCS, &chan->conf_state); break; case L2CAP_CONF_EFS: @@ -3435,7 +3435,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, case L2CAP_CONF_FCS: if (*result == L2CAP_CONF_PENDING) if (val == L2CAP_FCS_NONE) - set_bit(CONF_NO_FCS_RECV, + set_bit(CONF_RECV_NO_FCS, &chan->conf_state); break; } @@ -3807,7 +3807,7 @@ static inline void set_default_fcs(struct l2cap_chan *chan) */ if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) chan->fcs = L2CAP_FCS_NONE; - else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) + else if (!test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) chan->fcs = L2CAP_FCS_CRC16; } -- cgit v0.10.2 From 0b27a4b97cb1874503c78453c0903df53c0c86b2 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 3 Dec 2012 15:36:51 -0200 Subject: Revert "Bluetooth: Fix possible deadlock in SCO code" This reverts commit 269c4845d5b3627b95b1934107251bacbe99bb68. The commit was causing dead locks and NULL dereferences in the sco code: [28084.104013] BUG: soft lockup - CPU#0 stuck for 22s! [kworker/u:0H:7] [28084.104021] Modules linked in: btusb bluetooth ] _raw_spin_lock+0xd/0x10 [28084.104021] [] sco_conn_del+0x58/0x1b0 [bluetooth] [28084.104021] [] sco_connect_cfm+0xb9/0x2b0 [bluetooth] [28084.104021] [] hci_sync_conn_complete_evt.isra.94+0x1c9/0x260 [bluetooth] [28084.104021] [] hci_event_packet+0x74d/0x2b40 [bluetooth] [28084.104021] [] ? __kfree_skb+0x3d/0x90 [28084.104021] [] ? kfree_skb+0x36/0x90 [28084.104021] [] ? hci_send_to_monitor+0x10e/0x190 [bluetooth] [28084.104021] [] ? hci_send_to_monitor+0x10e/0x190 [bluetooth] Cc: stable@vger.kernel.org Reported-by: Chan-yeol Park Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index eea17cd..531a93d 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -131,15 +131,6 @@ static int sco_conn_del(struct hci_conn *hcon, int err) sco_sock_clear_timer(sk); sco_chan_del(sk, err); bh_unlock_sock(sk); - - sco_conn_lock(conn); - conn->sk = NULL; - sco_pi(sk)->conn = NULL; - sco_conn_unlock(conn); - - if (conn->hcon) - hci_conn_put(conn->hcon); - sco_sock_kill(sk); } @@ -885,6 +876,16 @@ static void sco_chan_del(struct sock *sk, int err) BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + if (conn) { + sco_conn_lock(conn); + conn->sk = NULL; + sco_pi(sk)->conn = NULL; + sco_conn_unlock(conn); + + if (conn->hcon) + hci_conn_put(conn->hcon); + } + sk->sk_state = BT_CLOSED; sk->sk_err = err; sk->sk_state_change(sk); -- cgit v0.10.2 From 6dac3447425d932fa76a4e69d32eead9dd090b27 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 2 Dec 2012 13:36:09 +0300 Subject: p54: potential signedness issue in p54_parse_rssical() "entries" is unsigned here, so it is never less than zero. In theory, len could be less than offset so I have added a check for that. Signed-off-by: Dan Carpenter Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 1ef1bfe..d43e374 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -541,8 +541,9 @@ static int p54_parse_rssical(struct ieee80211_hw *dev, entries = (len - offset) / sizeof(struct pda_rssi_cal_ext_entry); - if ((len - offset) % sizeof(struct pda_rssi_cal_ext_entry) || - entries <= 0) { + if (len < offset || + (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) || + entries == 0) { wiphy_err(dev->wiphy, "invalid rssi database.\n"); goto err_data; } -- cgit v0.10.2 From e6d227b97691584068675a624abe1bce4f9434cb Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 2 Dec 2012 15:53:28 +0100 Subject: rt2x00: rt2800lib: fix indentation of some rt2x00_rt calls The patch contains no functional changes. Signed-off-by: Gabor Juhos Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c0441a7..3d7b74e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2173,7 +2173,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 59, r59_nonbt_rev[idx]); } else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { static const char r59_non_bt[] = {0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d, 0x8a, 0x88, 0x88, 0x87, 0x87, 0x86}; @@ -2264,7 +2264,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rf->channel <= 14) { if (!rt2x00_rt(rt2x00dev, RT5390) && - !rt2x00_rt(rt2x00dev, RT5392)) { + !rt2x00_rt(rt2x00dev, RT5392)) { if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { rt2800_bbp_write(rt2x00dev, 82, 0x62); @@ -3592,8 +3592,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D)) rt2800_bbp_write(rt2x00dev, 84, 0x19); else if (rt2x00_rt(rt2x00dev, RT3290) || - rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 84, 0x9a); else rt2800_bbp_write(rt2x00dev, 84, 0x99); @@ -3652,7 +3652,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) else if (rt2x00_rt(rt2x00dev, RT3352)) rt2800_bbp_write(rt2x00dev, 105, 0x34); else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 105, 0x3c); else rt2800_bbp_write(rt2x00dev, 105, 0x05); @@ -3746,7 +3746,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { int ant, div_mode; rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); @@ -4356,7 +4356,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); if (!rt2x00_rt(rt2x00dev, RT5390) && - !rt2x00_rt(rt2x00dev, RT5392)) { + !rt2x00_rt(rt2x00dev, RT5392)) { /* * Set back to initial state */ @@ -4385,7 +4385,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, OPT_14_CSR, reg); if (!rt2x00_rt(rt2x00dev, RT5390) && - !rt2x00_rt(rt2x00dev, RT5392)) { + !rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0); if (rt2x00_rt(rt2x00dev, RT3070) || @@ -4457,7 +4457,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) } if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 38, rfcsr); -- cgit v0.10.2 From 33e274e66949a0806fb760b6f99543ba0d32ce02 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 2 Dec 2012 15:53:29 +0100 Subject: rt2x00: rt2800lib: fix indentation in rt2800_init_rfcsr The patch contains no functional changes. Signed-off-by: Gabor Juhos Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3d7b74e..1cc6599 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4220,66 +4220,66 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 61, 0xdd); rt2800_rfcsr_write(rt2x00dev, 62, 0x00); rt2800_rfcsr_write(rt2x00dev, 63, 0x00); - } else if (rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_rfcsr_write(rt2x00dev, 1, 0x17); - rt2800_rfcsr_write(rt2x00dev, 2, 0x80); - rt2800_rfcsr_write(rt2x00dev, 3, 0x88); - rt2800_rfcsr_write(rt2x00dev, 5, 0x10); - rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); - rt2800_rfcsr_write(rt2x00dev, 7, 0x00); - rt2800_rfcsr_write(rt2x00dev, 10, 0x53); - rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); - rt2800_rfcsr_write(rt2x00dev, 12, 0x46); - rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); - rt2800_rfcsr_write(rt2x00dev, 14, 0x00); - rt2800_rfcsr_write(rt2x00dev, 15, 0x00); - rt2800_rfcsr_write(rt2x00dev, 16, 0x00); - rt2800_rfcsr_write(rt2x00dev, 18, 0x03); - rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); - rt2800_rfcsr_write(rt2x00dev, 20, 0x00); - rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); - rt2800_rfcsr_write(rt2x00dev, 22, 0x20); - rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); - rt2800_rfcsr_write(rt2x00dev, 24, 0x44); - rt2800_rfcsr_write(rt2x00dev, 25, 0x80); - rt2800_rfcsr_write(rt2x00dev, 26, 0x82); - rt2800_rfcsr_write(rt2x00dev, 27, 0x09); - rt2800_rfcsr_write(rt2x00dev, 28, 0x00); - rt2800_rfcsr_write(rt2x00dev, 29, 0x10); - rt2800_rfcsr_write(rt2x00dev, 30, 0x10); - rt2800_rfcsr_write(rt2x00dev, 31, 0x80); - rt2800_rfcsr_write(rt2x00dev, 32, 0x20); - rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); - rt2800_rfcsr_write(rt2x00dev, 34, 0x07); - rt2800_rfcsr_write(rt2x00dev, 35, 0x12); - rt2800_rfcsr_write(rt2x00dev, 36, 0x00); - rt2800_rfcsr_write(rt2x00dev, 37, 0x08); - rt2800_rfcsr_write(rt2x00dev, 38, 0x89); - rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); - rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); - rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); - rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); - rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); - rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); - rt2800_rfcsr_write(rt2x00dev, 46, 0x73); - rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); - rt2800_rfcsr_write(rt2x00dev, 48, 0x10); - rt2800_rfcsr_write(rt2x00dev, 49, 0x94); - rt2800_rfcsr_write(rt2x00dev, 50, 0x94); - rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); - rt2800_rfcsr_write(rt2x00dev, 52, 0x48); - rt2800_rfcsr_write(rt2x00dev, 53, 0x44); - rt2800_rfcsr_write(rt2x00dev, 54, 0x38); - rt2800_rfcsr_write(rt2x00dev, 55, 0x43); - rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); - rt2800_rfcsr_write(rt2x00dev, 57, 0x00); - rt2800_rfcsr_write(rt2x00dev, 58, 0x39); - rt2800_rfcsr_write(rt2x00dev, 59, 0x07); - rt2800_rfcsr_write(rt2x00dev, 60, 0x45); - rt2800_rfcsr_write(rt2x00dev, 61, 0x91); - rt2800_rfcsr_write(rt2x00dev, 62, 0x39); - rt2800_rfcsr_write(rt2x00dev, 63, 0x07); + } else if (rt2x00_rt(rt2x00dev, RT5392)) { + rt2800_rfcsr_write(rt2x00dev, 1, 0x17); + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x88); + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); + rt2800_rfcsr_write(rt2x00dev, 6, 0xe0); + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); + rt2800_rfcsr_write(rt2x00dev, 16, 0x00); + rt2800_rfcsr_write(rt2x00dev, 18, 0x03); + rt2800_rfcsr_write(rt2x00dev, 19, 0x4d); + rt2800_rfcsr_write(rt2x00dev, 20, 0x00); + rt2800_rfcsr_write(rt2x00dev, 21, 0x8d); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 23, 0x0b); + rt2800_rfcsr_write(rt2x00dev, 24, 0x44); + rt2800_rfcsr_write(rt2x00dev, 25, 0x80); + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); + rt2800_rfcsr_write(rt2x00dev, 28, 0x00); + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x20); + rt2800_rfcsr_write(rt2x00dev, 33, 0xC0); + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); + rt2800_rfcsr_write(rt2x00dev, 37, 0x08); + rt2800_rfcsr_write(rt2x00dev, 38, 0x89); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 40, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); + rt2800_rfcsr_write(rt2x00dev, 43, 0x9b); + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); + rt2800_rfcsr_write(rt2x00dev, 47, 0x0c); + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); + rt2800_rfcsr_write(rt2x00dev, 49, 0x94); + rt2800_rfcsr_write(rt2x00dev, 50, 0x94); + rt2800_rfcsr_write(rt2x00dev, 51, 0x3a); + rt2800_rfcsr_write(rt2x00dev, 52, 0x48); + rt2800_rfcsr_write(rt2x00dev, 53, 0x44); + rt2800_rfcsr_write(rt2x00dev, 54, 0x38); + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); + rt2800_rfcsr_write(rt2x00dev, 56, 0xa1); + rt2800_rfcsr_write(rt2x00dev, 57, 0x00); + rt2800_rfcsr_write(rt2x00dev, 58, 0x39); + rt2800_rfcsr_write(rt2x00dev, 59, 0x07); + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); + rt2800_rfcsr_write(rt2x00dev, 61, 0x91); + rt2800_rfcsr_write(rt2x00dev, 62, 0x39); + rt2800_rfcsr_write(rt2x00dev, 63, 0x07); } if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) { -- cgit v0.10.2 From 649a6ac4a7d6eab2752893d69f722ccd9674dd4e Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 2 Dec 2012 16:52:00 +0100 Subject: carl9170: fix signal strength reporting issues On A-MPDU frames, the hardware only reports valid signal strength data for the last subframe. This patch fixes it by flagging everything but the last subframe in an A-MPDU to tell mac80211 to ignore the signal strength entirely. Otherwise the empty value (= 0 dbm) will distort the average quite badly. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 6d22382..876a773 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -814,6 +814,8 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len) if (phy) carl9170_rx_phy_status(ar, phy, &status); + else + status.flag |= RX_FLAG_NO_SIGNAL_VAL; if (carl9170_handle_mpdu(ar, buf, mpdu_len, &status)) goto drop; -- cgit v0.10.2 From fc1b63d75d9551bbfaff178a3f191c3d05db8c6e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 2 Dec 2012 17:24:02 +0100 Subject: rt2x00: rt2800lib: remove trailing semicolons from RFCSR3_* defines Signed-off-by: Gabor Juhos Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 6d67c3e..1157b06 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1993,8 +1993,8 @@ struct mac_iveiv_entry { */ #define RFCSR3_K FIELD8(0x0f) /* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */ -#define RFCSR3_PA1_BIAS_CCK FIELD8(0x70); -#define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80); +#define RFCSR3_PA1_BIAS_CCK FIELD8(0x70) +#define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80) /* * FRCSR 5: -- cgit v0.10.2 From d6d82020d07711f0095f2925bc1b9a28f94bb9b5 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Sun, 2 Dec 2012 18:34:47 +0100 Subject: rt2x00: rt2800lib: introduce RFCSR3_VCOCAL_EN On the RF3290,RF5360,RF5370,RF5372,RF5390,RF5392 radio frontends, the VCO calibration can be controlled via the RFCSR3 register. The current code uses the RFCSR30_RF_CALIBRATION constant to enable the calibration, however that belongs to the RFCSR30 register. Although the values of the constant is correct, but using that for another register is confusing. Add a new definition for the VCO calibration enable bit of the RFCSR3 register and use that in the relevant places in order to avoid confusions. The patch contains no functional changes. Signed-off-by: Gabor Juhos Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 1157b06..4db1088 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1995,6 +1995,8 @@ struct mac_iveiv_entry { /* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */ #define RFCSR3_PA1_BIAS_CCK FIELD8(0x70) #define RFCSR3_PA2_CASCODE_BIAS_CCKK FIELD8(0x80) +/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */ +#define RFCSR3_VCOCAL_EN FIELD8(0x80) /* * FRCSR 5: diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1cc6599..d4d0c36 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2243,7 +2243,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); } @@ -2804,7 +2804,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF5390: case RF5392: rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); break; default: -- cgit v0.10.2 From 795e9364215dc98b1dea888ebae22383ecbbb92a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 3 Dec 2012 16:56:34 +0100 Subject: mwl8k: remove useless pci shutdown callback and stray debugging This patch removes a left over debugging print present in the pci shutdown callback, since this callback does not do anything useful, get rid of it entirely. Signed-off-by: Florian Fainelli Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 0cdae66..434d508 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5873,11 +5873,6 @@ err_disable_device: return rc; } -static void __devexit mwl8k_shutdown(struct pci_dev *pdev) -{ - printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__); -} - static void __devexit mwl8k_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); @@ -5931,7 +5926,6 @@ static struct pci_driver mwl8k_driver = { .id_table = mwl8k_pci_id_table, .probe = mwl8k_probe, .remove = __devexit_p(mwl8k_remove), - .shutdown = __devexit_p(mwl8k_shutdown), }; module_pci_driver(mwl8k_driver); -- cgit v0.10.2 From f241b244dd4703a560c74e2538f27fd466c8d41f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 29 Nov 2012 12:45:09 -0800 Subject: brcmfmac: convert struct spinlock to spinlock_t spinlock_t should always be used. LD drivers/net/wireless/brcm80211/built-in.o CHECK drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.o CHECK drivers/net/wireless/brcm80211/brcmfmac/fwil.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/fwil.o CHECK drivers/net/wireless/brcm80211/brcmfmac/fweh.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/fweh.o CHECK drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.o CHECK drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/dhd_common.o CHECK drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.o CHECK drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.o CHECK drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.o CHECK drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.o CHECK drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.o CHECK drivers/net/wireless/brcm80211/brcmfmac/usb.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/usb.o CHECK drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c CC [M] drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.o LD [M] drivers/net/wireless/brcm80211/brcmfmac/brcmfmac.o LD drivers/net/wireless/brcm80211/brcmsmac/built-in.o CHECK drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c:1311:6: warning: context imbalance in 'brcms_down' - unexpected unlock drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c:1598:6: warning: context imbalance in 'brcms_rfkill_set_hw_state' - unexpected unlock CC [M] drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.o CHECK drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.o CHECK drivers/net/wireless/brcm80211/brcmsmac/ampdu.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/ampdu.o CHECK drivers/net/wireless/brcm80211/brcmsmac/antsel.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/antsel.o CHECK drivers/net/wireless/brcm80211/brcmsmac/channel.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/channel.o CHECK drivers/net/wireless/brcm80211/brcmsmac/main.c drivers/net/wireless/brcm80211/brcmsmac/main.c:6246:36: warning: Initializer entry defined twice drivers/net/wireless/brcm80211/brcmsmac/main.c:6246:43: also defined here CC [M] drivers/net/wireless/brcm80211/brcmsmac/main.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy_shim.o CHECK drivers/net/wireless/brcm80211/brcmsmac/pmu.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/pmu.o CHECK drivers/net/wireless/brcm80211/brcmsmac/rate.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/rate.o CHECK drivers/net/wireless/brcm80211/brcmsmac/stf.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/stf.o CHECK drivers/net/wireless/brcm80211/brcmsmac/aiutils.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/aiutils.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c:3313:46: warning: cast truncates bits from constant value (ffff7fff becomes 7fff) CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c:17688:47: warning: cast truncates bits from constant value (ffff7fff becomes 7fff) drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c:18187:53: warning: cast truncates bits from constant value (ffff3fff becomes 3fff) drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c:21160:36: warning: cast truncates bits from constant value (ffff3fff becomes 3fff) drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c:23321:35: warning: cast truncates bits from constant value (ffff7fff becomes 7fff) drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c:28343:44: warning: cast truncates bits from constant value (ffff1fff becomes 1fff) CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.o CHECK drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.o CHECK drivers/net/wireless/brcm80211/brcmsmac/dma.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/dma.o CHECK drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.o CHECK drivers/net/wireless/brcm80211/brcmsmac/debug.c CC [M] drivers/net/wireless/brcm80211/brcmsmac/debug.o LD [M] drivers/net/wireless/brcm80211/brcmsmac/brcmsmac.o LD drivers/net/wireless/brcm80211/brcmutil/built-in.o CHECK drivers/net/wireless/brcm80211/brcmutil/utils.c CC [M] drivers/net/wireless/brcm80211/brcmutil/utils.o LD [M] drivers/net/wireless/brcm80211/brcmutil/brcmutil.o Building modules, stage 2. MODPOST 3 modules CC drivers/net/wireless/brcm80211/brcmfmac/brcmfmac.mod.o LD [M] drivers/net/wireless/brcm80211/brcmfmac/brcmfmac.ko CC drivers/net/wireless/brcm80211/brcmsmac/brcmsmac.mod.o LD [M] drivers/net/wireless/brcm80211/brcmsmac/brcmsmac.ko CC drivers/net/wireless/brcm80211/brcmutil/brcmutil.mod.o LD [M] drivers/net/wireless/brcm80211/brcmutil/brcmutil.ko Cc: Brett Rudley Cc: Roland Vossen Cc: Arend van Spriel Cc: Franky (Zhenhui) Lin Cc: Kan Yan Cc: linux-wireless@vger.kernel.org Cc: brcm80211-dev-list@broadcom.com Reported-by: Hauke Mehrtens Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index b39246a..240a2ea 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -158,7 +158,7 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, */ struct brcmf_fweh_info { struct work_struct event_work; - struct spinlock evt_q_lock; + spinlock_t evt_q_lock; struct list_head event_q; int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, const struct brcmf_event_msg *evtmsg, -- cgit v0.10.2 From 1981e881fd32160bf886a09b12794c640aafffb3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 3 Dec 2012 18:48:05 +0100 Subject: carl9170: explain why sta cannot be NULL for ampdus Dan Carpenter reported that smatch detected a potential problem with the code [1]: drivers/net/wireless/ath/carl9170/tx.c:1488 carl9170_op_tx() error: we previously assumed 'sta' could be null (see line 1482) drivers/net/wireless/ath/carl9170/tx.c 1482 if (sta) { ^^^^^ New check. [...] 1485 } 1487 if (info->flags & IEEE80211_TX_CTL_AMPDU) { 1488 run = carl9170_tx_ampdu_queue(ar, sta, skb); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Old dereference of "sta" inside the call to carl9170_tx_ampdu_queue(). A range of solutions have been discussed in [2] and we agreed on the following: " > we might as well add a comment to carl9170_tx_ampdu_queue > and explain the situation [in a way that's obvious to a > human reader]. This way we can save the "if"... which is > a small win since carl9170_op_tx is sort of a hot-path. Putting a comment there is fine. Without the comment it's easy for a human reader to get confused why the check is there. So long as humans can read the code, that's all that matters." [1] [2] Reported-by: Dan Carpenter Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 84377cf..ef4ec0d 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1485,6 +1485,13 @@ void carl9170_op_tx(struct ieee80211_hw *hw, } if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* to static code analyzers and reviewers: + * mac80211 guarantees that a valid "sta" + * reference is present, if a frame is to + * be part of an ampdu. Hence any extra + * sta == NULL checks are redundant in this + * special case. + */ run = carl9170_tx_ampdu_queue(ar, sta, skb); if (run) carl9170_tx_ampdu(ar); -- cgit v0.10.2 From f5685ba675449b072feab6a5391a9ef9f604bc94 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 3 Dec 2012 22:35:39 +0100 Subject: rt2x00: Only specify interface combinations if more then one interface is possible Otherwise rt2500* triggers a warning in cfg80211, from net/wireless/core.c: /* Combinations with just one interface aren't real */ if (WARN_ON(c->max_interfaces < 2)) This was introduced in commit 55d2e9da744ba11eae900b4bfc2da72eace3c1e1: rt2x00: Replace open coded interface checking with interface combinations. Reported-by: Stefan Lippers-Hollmann Tested-by: Stefan Lippers-Hollmann Signed-off-by: Helmut Schaa Cc: stable@vger.kernel.org [3.7+] Acked-by: Gertjan van Wingerde Acked-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 66b3b17..3248b42 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1124,6 +1124,9 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) struct ieee80211_iface_limit *if_limit; struct ieee80211_iface_combination *if_combination; + if (rt2x00dev->ops->max_ap_intf < 2) + return; + /* * Build up AP interface limits structure. */ -- cgit v0.10.2 From 9304a1c7430590a7ee8ded5fc401ef483123de66 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 4 Dec 2012 03:30:20 -0500 Subject: brcmsmac: remove duplicated include from debug.c Remove duplicated include. Signed-off-by: Wei Yongjun Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c index be84791..9761deb 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 8df0f1e5cbd4ff1e2059a1e11bd89b35aa5ed004 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 5 Dec 2012 03:08:11 -0500 Subject: ipw2200: return error code on error in ipw_wx_get_auth() We have assinged error code to 'ret' when get auth from some option is not supported but never used it, but we'd better return the error code. Signed-off-by: Wei Yongjun Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 482f505..b0879ad 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -6812,7 +6812,6 @@ static int ipw_wx_get_auth(struct net_device *dev, struct libipw_device *ieee = priv->ieee; struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; - int ret = 0; switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -6822,8 +6821,7 @@ static int ipw_wx_get_auth(struct net_device *dev, /* * wpa_supplicant will control these internally */ - ret = -EOPNOTSUPP; - break; + return -EOPNOTSUPP; case IW_AUTH_TKIP_COUNTERMEASURES: crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; -- cgit v0.10.2 From bc245cc36c5687dd3fbf6d4a1b3c13d41f9cb189 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:45:58 +0100 Subject: ssb/bcma: add common header for watchdog This adds a common header for watchdog functions, so a watchdog driver just needs to use this and could provide watchdog functionality for ssb and bcma based SoCs. Patches for a watchdog driver using this interface will be send later. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/include/linux/bcm47xx_wdt.h b/include/linux/bcm47xx_wdt.h new file mode 100644 index 0000000..e5dfc25 --- /dev/null +++ b/include/linux/bcm47xx_wdt.h @@ -0,0 +1,19 @@ +#ifndef LINUX_BCM47XX_WDT_H_ +#define LINUX_BCM47XX_WDT_H_ + +#include + + +struct bcm47xx_wdt { + u32 (*timer_set)(struct bcm47xx_wdt *, u32); + u32 (*timer_set_ms)(struct bcm47xx_wdt *, u32); + u32 max_timer_ms; + + void *driver_data; +}; + +static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt) +{ + return wdt->driver_data; +} +#endif /* LINUX_BCM47XX_WDT_H_ */ -- cgit v0.10.2 From 56fd5f077223df1284a3501d1e3ba2e5b19d154a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:45:59 +0100 Subject: bcma: add bcma_chipco_alp_clock For devices without a PMU the alp clock is always 20000000. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index ffd74e5..ef68553 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -4,6 +4,7 @@ * * Copyright 2005, Broadcom Corporation * Copyright 2006, 2007, Michael Buesch + * Copyright 2012, Hauke Mehrtens * * Licensed under the GNU/GPL. See COPYING for details. */ @@ -22,6 +23,14 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, return value; } +static u32 bcma_chipco_alp_clock(struct bcma_drv_cc *cc) +{ + if (cc->capabilities & BCMA_CC_CAP_PMU) + return bcma_pmu_alp_clock(cc); + + return 20000000; +} + void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { if (cc->early_setup_done) @@ -131,8 +140,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc) struct bcma_serial_port *ports = cc->serial_ports; if (ccrev >= 11 && ccrev != 15) { - /* Fixed ALP clock */ - baud_base = bcma_pmu_alp_clock(cc); + baud_base = bcma_chipco_alp_clock(cc); if (ccrev >= 21) { /* Turn off UART clock before switching clocksource. */ bcma_cc_write32(cc, BCMA_CC_CORECTL, -- cgit v0.10.2 From f6354c8cf9a3be15de441fad593ce53e63e9bf2a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:00 +0100 Subject: bcma: set the pmu watchdog if available Mostly all bcma based devices have a PMU and the PMU watchdog should be used and not the old one in chip common. This patch also calculates the maximal number the watchdog could be set to. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index ef68553..7c132e5 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -31,6 +31,28 @@ static u32 bcma_chipco_alp_clock(struct bcma_drv_cc *cc) return 20000000; } +static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + u32 nb; + + if (cc->capabilities & BCMA_CC_CAP_PMU) { + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) + nb = 32; + else if (cc->core->id.rev < 26) + nb = 16; + else + nb = (cc->core->id.rev >= 37) ? 32 : 24; + } else { + nb = 28; + } + if (nb == 32) + return 0xffffffff; + else + return (1 << nb) - 1; +} + + void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { if (cc->early_setup_done) @@ -85,8 +107,24 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { - /* instant NMI */ - bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); + u32 maxt; + enum bcma_clkmode clkmode; + + maxt = bcma_chipco_watchdog_get_max_timer(cc); + if (cc->capabilities & BCMA_CC_CAP_PMU) { + if (ticks == 1) + ticks = 2; + else if (ticks > maxt) + ticks = maxt; + bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); + } else { + clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC; + bcma_core_set_clockmode(cc->core, clkmode); + if (ticks > maxt) + ticks = maxt; + /* instant NMI */ + bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); + } } void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) -- cgit v0.10.2 From a22a3114a820ca3eadee6af53d90736e5ca68fa1 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:01 +0100 Subject: bcma: add methods for watchdog driver The watchdog driver wants to set the watchdog timeout in ms and not in ticks, which is depending on the SoC type and the clock. Calculate the number of ticks per millisecond and provide two functions for the watchdog driver. Also return the ticks or millisecond the timer was set to in case the provided value was bigger than the max allowed value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 7c132e5..1172226 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -10,6 +10,7 @@ */ #include "bcma_private.h" +#include #include #include @@ -52,6 +53,39 @@ static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc) return (1 << nb) - 1; } +static u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, + u32 ticks) +{ + struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); + + return bcma_chipco_watchdog_timer_set(cc, ticks); +} + +static u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt, + u32 ms) +{ + struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); + u32 ticks; + + ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); + return ticks / cc->ticks_per_ms; +} + +static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + if (cc->capabilities & BCMA_CC_CAP_PMU) { + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) + /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */ + return bcma_chipco_alp_clock(cc) / 4000; + else + /* based on 32KHz ILP clock */ + return 32; + } else { + return bcma_chipco_alp_clock(cc) / 1000; + } +} void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { @@ -100,12 +134,13 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); } + cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc); cc->setup_done = true; } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) +u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { u32 maxt; enum bcma_clkmode clkmode; @@ -125,6 +160,7 @@ void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) /* instant NMI */ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); } + return ticks; } void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 145f3c5..2f9b014 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -570,6 +570,7 @@ struct bcma_drv_cc { int nr_serial_ports; struct bcma_serial_port serial_ports[4]; #endif /* CONFIG_BCMA_DRIVER_MIPS */ + u32 ticks_per_ms; }; /* Register access */ @@ -593,8 +594,7 @@ extern void bcma_chipco_resume(struct bcma_drv_cc *cc); void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); -extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, - u32 ticks); +extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks); void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value); -- cgit v0.10.2 From a4855f39d4eb3f550ca5f4aac79bd999da42dc54 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:02 +0100 Subject: bcma: register watchdog driver Register the watchdog driver to the system if this is a SoC. Using the watchdog on a non SoC device, like a PCIe card, will make the PCIe card die when the timeout expired, but starting it again is not supported by bcma. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 169fc58..bcb830e 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -84,6 +84,8 @@ extern void __exit bcma_host_pci_exit(void); /* driver_pci.c */ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address); +extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc); + #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc); void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 1172226..d017f25 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -12,6 +12,7 @@ #include "bcma_private.h" #include #include +#include #include static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, @@ -87,6 +88,27 @@ static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) } } +int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc) +{ + struct bcm47xx_wdt wdt = {}; + struct platform_device *pdev; + + wdt.driver_data = cc; + wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt; + wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt; + wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; + + pdev = platform_device_register_data(NULL, "bcm47xx-wdt", + cc->core->bus->num, &wdt, + sizeof(wdt)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + cc->watchdog = pdev; + + return 0; +} + void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { if (cc->early_setup_done) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index a971889..debd4f1 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -165,6 +165,12 @@ static int bcma_register_cores(struct bcma_bus *bus) } #endif + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + err = bcma_chipco_watchdog_register(&bus->drv_cc); + if (err) + bcma_err(bus, "Error registering watchdog driver\n"); + } + return 0; } @@ -177,6 +183,8 @@ static void bcma_unregister_cores(struct bcma_bus *bus) if (core->dev_registered) device_unregister(&core->dev); } + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + platform_device_unregister(bus->drv_cc.watchdog); } int __devinit bcma_bus_register(struct bcma_bus *bus) diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 2f9b014..e513591 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -1,6 +1,8 @@ #ifndef LINUX_BCMA_DRIVER_CC_H_ #define LINUX_BCMA_DRIVER_CC_H_ +#include + /** ChipCommon core registers. **/ #define BCMA_CC_ID 0x0000 #define BCMA_CC_ID_ID 0x0000FFFF @@ -571,6 +573,7 @@ struct bcma_drv_cc { struct bcma_serial_port serial_ports[4]; #endif /* CONFIG_BCMA_DRIVER_MIPS */ u32 ticks_per_ms; + struct platform_device *watchdog; }; /* Register access */ -- cgit v0.10.2 From f924e1e989b0bdaf6472668400d67a2142cb6b60 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:03 +0100 Subject: ssb: get alp clock from devices with PMU If there is a PMU in the device, get the alp clock from that part and do not assume 20000000. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index e9d2ca1..603b630 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -280,6 +280,14 @@ static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) cc->fast_pwrup_delay = tmp; } +static u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc) +{ + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) + return ssb_pmu_get_alp_clock(cc); + + return 20000000; +} + void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) @@ -473,12 +481,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc, 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); - } + baud_base = ssb_chipco_alp_clock(cc); div = 1; if (ccrev >= 21) { /* Turn off UART clock before switching clocksource. */ diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index d7d5804..a43415a 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -618,6 +618,33 @@ void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on) EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage); EXPORT_SYMBOL(ssb_pmu_set_ldo_paref); +static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc) +{ + u32 crystalfreq; + const struct pmu0_plltab_entry *e = NULL; + + crystalfreq = chipco_read32(cc, SSB_CHIPCO_PMU_CTL) & + SSB_CHIPCO_PMU_CTL_XTALFREQ >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT; + e = pmu0_plltab_find_entry(crystalfreq); + BUG_ON(!e); + return e->freq * 1000; +} + +u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + + switch (bus->chip_id) { + case 0x5354: + ssb_pmu_get_alp_clock_clk0(cc); + default: + ssb_printk(KERN_ERR PFX + "ERROR: PMU alp clock unknown for device %04X\n", + bus->chip_id); + return 0; + } +} + u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc) { struct ssb_bus *bus = cc->dev->bus; diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index a305550..98b2915 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -210,5 +210,6 @@ static inline void b43_pci_ssb_bridge_exit(void) /* driver_chipcommon_pmu.c */ extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); +extern u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc); #endif /* LINUX_SSB_PRIVATE_H_ */ -- cgit v0.10.2 From 26107309c08f8548a2e0aef0d0aabd64bc2d22c1 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:04 +0100 Subject: ssb: set the PMU watchdog if available Some ssb based devices have a PMU and the PMU watchdog register should be used instead of the register in the chip common part, if the device has a PMU. This patch also calculates the maximal number the watchdog could be set to. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 603b630..6e080f6 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -288,6 +288,24 @@ static u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc) return 20000000; } +static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc) +{ + u32 nb; + + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { + if (cc->dev->id.revision < 26) + nb = 16; + else + nb = (cc->dev->id.revision >= 37) ? 32 : 24; + } else { + nb = 28; + } + if (nb == 32) + return 0xffffffff; + else + return (1 << nb) - 1; +} + void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) @@ -405,8 +423,24 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc, /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) { - /* instant NMI */ - chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); + u32 maxt; + enum ssb_clkmode clkmode; + + maxt = ssb_chipco_watchdog_get_max_timer(cc); + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { + if (ticks == 1) + ticks = 2; + else if (ticks > maxt) + ticks = maxt; + chipco_write32(cc, SSB_CHIPCO_PMU_WATCHDOG, ticks); + } else { + clkmode = ticks ? SSB_CLKMODE_FAST : SSB_CLKMODE_DYNAMIC; + ssb_chipco_set_clockmode(cc, clkmode); + if (ticks > maxt) + ticks = maxt; + /* instant NMI */ + chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); + } } void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) -- cgit v0.10.2 From 7ffbffe37de3979d43c1105e38eb2918bf5d35fe Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:05 +0100 Subject: ssb: add methods for watchdog driver The watchdog driver wants to set the watchdog timeout in ms and not in ticks, which is depending on the SoC type and the clock. Calculate the number of ticks per millisecond and provide two functions for the watchdog driver. Also return the ticks or millisecond the timer was set to in case the provided value was bigger than the max allowed value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 6e080f6..95c33a0 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -4,6 +4,7 @@ * * Copyright 2005, Broadcom Corporation * Copyright 2006, 2007, Michael Buesch + * Copyright 2012, Hauke Mehrtens * * Licensed under the GNU/GPL. See COPYING for details. */ @@ -12,6 +13,7 @@ #include #include #include +#include #include "ssb_private.h" @@ -306,6 +308,43 @@ static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc) return (1 << nb) - 1; } +u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) +{ + struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); + + if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) + return 0; + + return ssb_chipco_watchdog_timer_set(cc, ticks); +} + +u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) +{ + struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); + u32 ticks; + + if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) + return 0; + + ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); + return ticks / cc->ticks_per_ms; +} + +static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { + /* based on 32KHz ILP clock */ + return 32; + } else { + if (cc->dev->id.revision < 18) + return ssb_clockspeed(bus) / 1000; + else + return ssb_chipco_alp_clock(cc) / 1000; + } +} + void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) @@ -323,6 +362,11 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); calc_fast_powerup_delay(cc); + + if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) { + cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc); + cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; + } } void ssb_chipco_suspend(struct ssb_chipcommon *cc) @@ -421,7 +465,7 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc, } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) { u32 maxt; enum ssb_clkmode clkmode; @@ -441,6 +485,7 @@ void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) /* instant NMI */ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); } + return ticks; } void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 98b2915..03cc40a 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -3,6 +3,7 @@ #include #include +#include #define PFX "ssb: " @@ -212,4 +213,8 @@ extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc); +extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, + u32 ticks); +extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); + #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index c2b02a5..38339fd 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -591,6 +591,8 @@ struct ssb_chipcommon { /* Fast Powerup Delay constant */ u16 fast_pwrup_delay; struct ssb_chipcommon_pmu pmu; + u32 ticks_per_ms; + u32 max_timer_ms; }; static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) @@ -630,8 +632,7 @@ enum ssb_clkmode { extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, enum ssb_clkmode mode); -extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, - u32 ticks); +extern u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks); void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value); -- cgit v0.10.2 From 7280b51a29f8e6cc7d449d565182d1e1b6183907 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:06 +0100 Subject: ssb: extif: add check for max value before setting watchdog register Prevent the watchdog register on the extif core to be set to a too high value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index dc47f30..0aa4c2a 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -112,9 +112,10 @@ 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) +void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { + if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER) + ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER; extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); } diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 2604efa..b618188 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -152,6 +152,7 @@ /* watchdog */ #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ +#define SSB_EXTIF_WATCHDOG_MAX_TIMER ((1 << 28) - 1) #ifdef CONFIG_SSB_DRIVER_EXTIF -- cgit v0.10.2 From 9f640a6376e54fa9ae834c32cbe92cefeec970dc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:07 +0100 Subject: ssb: extif: add methods for watchdog driver The watchdog driver wants to set the watchdog timeout in ms and not in ticks, add a method converting ms to ticks before setting the watchdog register. Return the ticks or millisecond the timer was set to in case the provided value was bigger than the max allowed value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index 0aa4c2a..553227a 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -112,11 +112,30 @@ 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) +u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) +{ + struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt); + + return ssb_extif_watchdog_timer_set(extif, ticks); +} + +u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) +{ + struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt); + u32 ticks = (SSB_EXTIF_WATCHDOG_CLK / 1000) * ms; + + ticks = ssb_extif_watchdog_timer_set(extif, ticks); + + return (ticks * 1000) / SSB_EXTIF_WATCHDOG_CLK; +} + +u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER) ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER; extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); + + return ticks; } u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 03cc40a..50ea028 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -217,4 +217,19 @@ extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +#ifdef CONFIG_SSB_DRIVER_EXTIF +extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); +extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +#else +static inline u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, + u32 ticks) +{ + return 0; +} +static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, + u32 ms) +{ + return 0; +} +#endif #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index b618188..99511d0 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -153,6 +153,8 @@ #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ #define SSB_EXTIF_WATCHDOG_MAX_TIMER ((1 << 28) - 1) +#define SSB_EXTIF_WATCHDOG_MAX_TIMER_MS (SSB_EXTIF_WATCHDOG_MAX_TIMER \ + / (SSB_EXTIF_WATCHDOG_CLK / 1000)) #ifdef CONFIG_SSB_DRIVER_EXTIF @@ -172,8 +174,7 @@ 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); +extern u32 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); @@ -211,9 +212,9 @@ void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) } static inline -void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, - u32 ticks) +u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { + return 0; } static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) -- cgit v0.10.2 From bde327eff8a722df1198df9b14464f84f1adfb65 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:08 +0100 Subject: ssb: register watchdog driver Register the watchdog driver to the system if it is a SoC. Using the watchdog on a non SoC device, like a PCI card, will make the PCI card die when the timeout expired, but starting it again is not supported by ssb. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index 9ef124f..bb18d76 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -4,11 +4,13 @@ * * Copyright 2005-2008, Broadcom Corporation * Copyright 2006-2008, Michael Buesch + * Copyright 2012, Hauke Mehrtens * * Licensed under the GNU/GPL. See COPYING for details. */ #include +#include #include #include #include @@ -32,6 +34,39 @@ int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) } EXPORT_SYMBOL(ssb_watchdog_timer_set); +int ssb_watchdog_register(struct ssb_bus *bus) +{ + struct bcm47xx_wdt wdt = {}; + struct platform_device *pdev; + + if (ssb_chipco_available(&bus->chipco)) { + wdt.driver_data = &bus->chipco; + wdt.timer_set = ssb_chipco_watchdog_timer_set_wdt; + wdt.timer_set_ms = ssb_chipco_watchdog_timer_set_ms; + wdt.max_timer_ms = bus->chipco.max_timer_ms; + } else if (ssb_extif_available(&bus->extif)) { + wdt.driver_data = &bus->extif; + wdt.timer_set = ssb_extif_watchdog_timer_set_wdt; + wdt.timer_set_ms = ssb_extif_watchdog_timer_set_ms; + wdt.max_timer_ms = SSB_EXTIF_WATCHDOG_MAX_TIMER_MS; + } else { + return -ENODEV; + } + + pdev = platform_device_register_data(NULL, "bcm47xx-wdt", + bus->busnumber, &wdt, + sizeof(wdt)); + if (IS_ERR(pdev)) { + ssb_dprintk(KERN_INFO PFX + "can not register watchdog device, err: %li\n", + PTR_ERR(pdev)); + return PTR_ERR(pdev); + } + + bus->watchdog = pdev; + return 0; +} + u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask) { unsigned long flags; diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index df0f145..58c7da2 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -433,6 +434,11 @@ static void ssb_devices_unregister(struct ssb_bus *bus) if (sdev->dev) device_unregister(sdev->dev); } + +#ifdef CONFIG_SSB_EMBEDDED + if (bus->bustype == SSB_BUSTYPE_SSB) + platform_device_unregister(bus->watchdog); +#endif } void ssb_bus_unregister(struct ssb_bus *bus) @@ -561,6 +567,8 @@ static int __devinit ssb_attach_queued_buses(void) if (err) goto error; ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ssb_bus_may_powerdown(bus); err = ssb_devices_register(bus); diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 50ea028..8942db1 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -232,4 +232,14 @@ static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, return 0; } #endif + +#ifdef CONFIG_SSB_EMBEDDED +extern int ssb_watchdog_register(struct ssb_bus *bus); +#else /* CONFIG_SSB_EMBEDDED */ +static inline int ssb_watchdog_register(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_EMBEDDED */ + #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index bb674c0..1f64e3f 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -432,6 +433,7 @@ struct ssb_bus { #ifdef CONFIG_SSB_EMBEDDED /* Lock for GPIO register access. */ spinlock_t gpio_lock; + struct platform_device *watchdog; #endif /* EMBEDDED */ /* Internal-only stuff follows. Do not touch. */ -- cgit v0.10.2 From 9e2b29d0d6ae05fb1ead7df68a209eece9c7749a Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:26 -0500 Subject: rfkill: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Johannes Berg Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 865adb6..78fc093 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -213,7 +213,7 @@ static int rfkill_gpio_remove(struct platform_device *pdev) static struct platform_driver rfkill_gpio_driver = { .probe = rfkill_gpio_probe, - .remove = __devexit_p(rfkill_gpio_remove), + .remove = rfkill_gpio_remove, .driver = { .name = "rfkill_gpio", .owner = THIS_MODULE, diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c index 11da301..4b5ab21 100644 --- a/net/rfkill/rfkill-regulator.c +++ b/net/rfkill/rfkill-regulator.c @@ -55,7 +55,7 @@ struct rfkill_ops rfkill_regulator_ops = { .set_block = rfkill_regulator_set_block, }; -static int __devinit rfkill_regulator_probe(struct platform_device *pdev) +static int rfkill_regulator_probe(struct platform_device *pdev) { struct rfkill_regulator_platform_data *pdata = pdev->dev.platform_data; struct rfkill_regulator_data *rfkill_data; @@ -122,7 +122,7 @@ out: return ret; } -static int __devexit rfkill_regulator_remove(struct platform_device *pdev) +static int rfkill_regulator_remove(struct platform_device *pdev) { struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev); struct rfkill *rf_kill = rfkill_data->rf_kill; @@ -137,7 +137,7 @@ static int __devexit rfkill_regulator_remove(struct platform_device *pdev) static struct platform_driver rfkill_regulator_driver = { .probe = rfkill_regulator_probe, - .remove = __devexit_p(rfkill_regulator_remove), + .remove = rfkill_regulator_remove, .driver = { .name = "rfkill-regulator", .owner = THIS_MODULE, -- cgit v0.10.2 From 04bfffb8053c7206c3b63c25c0775b6ad7053270 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:27 -0500 Subject: wireless: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 154a496..3d339e0 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1761,7 +1761,7 @@ static const struct ieee80211_ops adm8211_ops = { .get_tsf = adm8211_get_tsft }; -static int __devinit adm8211_probe(struct pci_dev *pdev, +static int adm8211_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ieee80211_hw *dev; @@ -1935,7 +1935,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, } -static void __devexit adm8211_remove(struct pci_dev *pdev) +static void adm8211_remove(struct pci_dev *pdev) { struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv; @@ -1985,7 +1985,7 @@ static struct pci_driver adm8211_driver = { .name = "adm8211", .id_table = adm8211_pci_id_table, .probe = adm8211_probe, - .remove = __devexit_p(adm8211_remove), + .remove = adm8211_remove, #ifdef CONFIG_PM .suspend = adm8211_suspend, .resume = adm8211_resume, diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 57f7db1..5329541 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -78,7 +78,7 @@ static struct pci_driver airo_driver = { .name = DRV_NAME, .id_table = card_ids, .probe = airo_pci_probe, - .remove = __devexit_p(airo_pci_remove), + .remove = airo_pci_remove, .suspend = airo_pci_suspend, .resume = airo_pci_resume, }; @@ -5584,7 +5584,7 @@ static void timer_func( struct net_device *dev ) { } #ifdef CONFIG_PCI -static int __devinit airo_pci_probe(struct pci_dev *pdev, +static int airo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pent) { struct net_device *dev; @@ -5606,7 +5606,7 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, return 0; } -static void __devexit airo_pci_remove(struct pci_dev *pdev) +static void airo_pci_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); -- cgit v0.10.2 From e829cf961bfd3c2c5ef0a2c5a51734c1628ce77e Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:28 -0500 Subject: ath5k: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Jiri Slaby Cc: Nick Kossifidis Cc: Luis R. Rodriguez Cc: linux-wireless@vger.kernel.org Cc: ath5k-devel@lists.ath5k.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2fd5bab..3a5a61e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2435,7 +2435,7 @@ static const struct ieee80211_iface_combination if_comb = { .num_different_channels = 1, }; -int __devinit +int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = ah->hw; @@ -2861,7 +2861,7 @@ static void ath5k_reset_work(struct work_struct *work) mutex_unlock(&ah->lock); } -static int __devinit +static int ath5k_init(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index b9f708a..f77ef36 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -158,7 +158,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah) ath5k_unregister_led(&ah->tx_led); } -int __devinit ath5k_init_leds(struct ath5k_hw *ah) +int ath5k_init_leds(struct ath5k_hw *ah) { int ret = 0; struct ieee80211_hw *hw = ah->hw; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index dff48fb..859db7c 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -155,7 +155,7 @@ static const struct ath_bus_ops ath_pci_bus_ops = { * PCI Initialization * \********************/ -static int __devinit +static int ath5k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -285,7 +285,7 @@ err: return ret; } -static void __devexit +static void ath5k_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); @@ -336,7 +336,7 @@ static struct pci_driver ath5k_pci_driver = { .name = KBUILD_MODNAME, .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, - .remove = __devexit_p(ath5k_pci_remove), + .remove = ath5k_pci_remove, .driver.pm = ATH5K_PM_OPS, }; -- cgit v0.10.2 From 991683ca49908a78ff00942d6832523657e578b7 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:29 -0500 Subject: atmel: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c index 51e33b5..c1b159e 100644 --- a/drivers/net/wireless/atmel_pci.c +++ b/drivers/net/wireless/atmel_pci.c @@ -45,11 +45,11 @@ static struct pci_driver atmel_driver = { .name = "atmel", .id_table = card_ids, .probe = atmel_pci_probe, - .remove = __devexit_p(atmel_pci_remove), + .remove = atmel_pci_remove, }; -static int __devinit atmel_pci_probe(struct pci_dev *pdev, +static int atmel_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pent) { struct net_device *dev; @@ -69,7 +69,7 @@ static int __devinit atmel_pci_probe(struct pci_dev *pdev, return 0; } -static void __devexit atmel_pci_remove(struct pci_dev *pdev) +static void atmel_pci_remove(struct pci_dev *pdev) { stop_atmel_card(pci_get_drvdata(pdev)); } -- cgit v0.10.2 From 157c9436e6e740b0fb3f3c10da0e2f68731a8052 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:30 -0500 Subject: b43: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Stefano Brivio Cc: b43-dev@lists.infradead.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 714cad6..f2ea2ce 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -60,7 +60,7 @@ static int b43_pcmcia_resume(struct pcmcia_device *dev) # define b43_pcmcia_resume NULL #endif /* CONFIG_PM */ -static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) +static int b43_pcmcia_probe(struct pcmcia_device *dev) { struct ssb_bus *ssb; int err = -ENOMEM; @@ -110,7 +110,7 @@ out_error: return err; } -static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev) +static void b43_pcmcia_remove(struct pcmcia_device *dev) { struct ssb_bus *ssb = dev->priv; @@ -125,7 +125,7 @@ static struct pcmcia_driver b43_pcmcia_driver = { .name = "b43-pcmcia", .id_table = b43_pcmcia_tbl, .probe = b43_pcmcia_probe, - .remove = __devexit_p(b43_pcmcia_remove), + .remove = b43_pcmcia_remove, .suspend = b43_pcmcia_suspend, .resume = b43_pcmcia_resume, }; diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index a54fb2d..59a5218 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -93,7 +93,7 @@ void b43_sdio_free_irq(struct b43_wldev *dev) sdio->irq_handler = NULL; } -static int __devinit b43_sdio_probe(struct sdio_func *func, +static int b43_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct b43_sdio *sdio; @@ -171,7 +171,7 @@ out: return error; } -static void __devexit b43_sdio_remove(struct sdio_func *func) +static void b43_sdio_remove(struct sdio_func *func) { struct b43_sdio *sdio = sdio_get_drvdata(func); @@ -193,7 +193,7 @@ static struct sdio_driver b43_sdio_driver = { .name = "b43-sdio", .id_table = b43_sdio_ids, .probe = b43_sdio_probe, - .remove = __devexit_p(b43_sdio_remove), + .remove = b43_sdio_remove, }; int b43_sdio_init(void) -- cgit v0.10.2 From fcff0c0887f7286eda3ce47d8934acb3a78e1076 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:31 -0500 Subject: brcm80211: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Brett Rudley Cc: Roland Vossen Cc: Arend van Spriel Cc: Franky (Zhenhui) Lin Cc: Kan Yan Cc: brcm80211-dev-list@broadcom.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 85dbaf8..02d27ea 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1099,7 +1099,7 @@ fail: * * Perimeter lock is initialized in the course of this function. */ -static int __devinit brcms_bcma_probe(struct bcma_device *pdev) +static int brcms_bcma_probe(struct bcma_device *pdev) { struct brcms_info *wl; struct ieee80211_hw *hw; @@ -1165,7 +1165,7 @@ static struct bcma_driver brcms_bcma_driver = { .probe = brcms_bcma_probe, .suspend = brcms_suspend, .resume = brcms_resume, - .remove = __devexit_p(brcms_remove), + .remove = brcms_remove, .id_table = brcms_coreid_table, }; -- cgit v0.10.2 From eb9248eee600092dcd982ce12b964c90e30c075c Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:32 -0500 Subject: ipw2x00: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Stanislav Yakovlev Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 46938bc..d92b21a 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6410,7 +6410,7 @@ out: goto out; } -static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) +static void ipw2100_pci_remove_one(struct pci_dev *pci_dev) { struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); struct net_device *dev = priv->net_dev; @@ -6606,7 +6606,7 @@ static struct pci_driver ipw2100_pci_driver = { .name = DRV_NAME, .id_table = ipw2100_pci_id_table, .probe = ipw2100_pci_init_one, - .remove = __devexit_p(ipw2100_pci_remove_one), + .remove = ipw2100_pci_remove_one, #ifdef CONFIG_PM .suspend = ipw2100_suspend, .resume = ipw2100_resume, diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index b0879ad..844f201 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -10772,7 +10772,7 @@ static void ipw_bg_link_down(struct work_struct *work) mutex_unlock(&priv->mutex); } -static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) +static int ipw_setup_deferred_work(struct ipw_priv *priv) { int ret = 0; @@ -11726,7 +11726,7 @@ static const struct net_device_ops ipw_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __devinit ipw_pci_probe(struct pci_dev *pdev, +static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; @@ -11899,7 +11899,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, return err; } -static void __devexit ipw_pci_remove(struct pci_dev *pdev) +static void ipw_pci_remove(struct pci_dev *pdev) { struct ipw_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; @@ -12061,7 +12061,7 @@ static struct pci_driver ipw_driver = { .name = DRV_NAME, .id_table = card_ids, .probe = ipw_pci_probe, - .remove = __devexit_p(ipw_pci_remove), + .remove = ipw_pci_remove, #ifdef CONFIG_PM .suspend = ipw_pci_suspend, .resume = ipw_pci_resume, -- cgit v0.10.2 From a027cb88bf692b86948c5495650665a2a1d5535f Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:33 -0500 Subject: iwlegacy: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index e252acb..d604b40 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3794,7 +3794,7 @@ out: return err; } -static void __devexit +static void il3945_pci_remove(struct pci_dev *pdev) { struct il_priv *il = pci_get_drvdata(pdev); @@ -3884,7 +3884,7 @@ static struct pci_driver il3945_driver = { .name = DRV_NAME, .id_table = il3945_hw_card_ids, .probe = il3945_pci_probe, - .remove = __devexit_p(il3945_pci_remove), + .remove = il3945_pci_remove, .driver.pm = IL_LEGACY_PM_OPS, }; diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 07ffa57..c3fbf67 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -6664,7 +6664,7 @@ out: return err; } -static void __devexit +static void il4965_pci_remove(struct pci_dev *pdev) { struct il_priv *il = pci_get_drvdata(pdev); @@ -6772,7 +6772,7 @@ static struct pci_driver il4965_driver = { .name = DRV_NAME, .id_table = il4965_hw_card_ids, .probe = il4965_pci_probe, - .remove = __devexit_p(il4965_pci_remove), + .remove = il4965_pci_remove, .driver.pm = IL_LEGACY_PM_OPS, }; -- cgit v0.10.2 From d00064d4f775150017835f2c93905f05691e1649 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:34 -0500 Subject: iwlwifi: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Johannes Berg Cc: Wey-Yi Guy Cc: Intel Linux Wireless Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 956fe6c..2b7e8a0 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -293,7 +293,7 @@ out_free_trans: return -EFAULT; } -static void __devexit iwl_pci_remove(struct pci_dev *pdev) +static void iwl_pci_remove(struct pci_dev *pdev) { struct iwl_trans *trans = pci_get_drvdata(pdev); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -352,7 +352,7 @@ static struct pci_driver iwl_pci_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, .probe = iwl_pci_probe, - .remove = __devexit_p(iwl_pci_remove), + .remove = iwl_pci_remove, .driver.pm = IWL_PM_OPS, }; -- cgit v0.10.2 From fbdb7fcefe95cb77b9d692e6f9c7c02ecc846c10 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:35 -0500 Subject: libertas: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Dan Williams Cc: libertas-dev@lists.infradead.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 9604a1c..4bb6574 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1124,7 +1124,7 @@ static void if_spi_resume_worker(struct work_struct *work) } } -static int __devinit if_spi_probe(struct spi_device *spi) +static int if_spi_probe(struct spi_device *spi) { struct if_spi_card *card; struct lbs_private *priv = NULL; @@ -1226,7 +1226,7 @@ out: return err; } -static int __devexit libertas_spi_remove(struct spi_device *spi) +static int libertas_spi_remove(struct spi_device *spi) { struct if_spi_card *card = spi_get_drvdata(spi); struct lbs_private *priv = card->priv; @@ -1285,7 +1285,7 @@ static const struct dev_pm_ops if_spi_pm_ops = { static struct spi_driver libertas_spi_driver = { .probe = if_spi_probe, - .remove = __devexit_p(libertas_spi_remove), + .remove = libertas_spi_remove, .driver = { .name = "libertas_spi", .owner = THIS_MODULE, -- cgit v0.10.2 From 8dee5eef2ab313e519e6ce3c3bf9a16cfc6f5907 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:36 -0500 Subject: mwl8k: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Lennert Buytenhek Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 434d508..f221b95 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5258,7 +5258,7 @@ enum { #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) -static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { +static struct mwl8k_device_info mwl8k_info_tbl[] = { [MWL8363] = { .part_name = "88w8363", .helper_image = "mwl8k/helper_8363.fw", @@ -5756,7 +5756,7 @@ err_free_cookie: return rc; } -static int __devinit mwl8k_probe(struct pci_dev *pdev, +static int mwl8k_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static int printed_version; @@ -5873,7 +5873,7 @@ err_disable_device: return rc; } -static void __devexit mwl8k_remove(struct pci_dev *pdev) +static void mwl8k_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct mwl8k_priv *priv; @@ -5925,7 +5925,7 @@ static struct pci_driver mwl8k_driver = { .name = MWL8K_NAME, .id_table = mwl8k_pci_id_table, .probe = mwl8k_probe, - .remove = __devexit_p(mwl8k_remove), + .remove = mwl8k_remove, }; module_pci_driver(mwl8k_driver); -- cgit v0.10.2 From baa366cda6ec9bf033301a4f547c26c833bd5930 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:37 -0500 Subject: orinoco: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c index 326396b..d73fdf6 100644 --- a/drivers/net/wireless/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco/orinoco_nortel.c @@ -255,7 +255,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, return err; } -static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev) +static void orinoco_nortel_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); struct orinoco_pci_card *card = priv->card; @@ -288,7 +288,7 @@ static struct pci_driver orinoco_nortel_driver = { .name = DRIVER_NAME, .id_table = orinoco_nortel_id_table, .probe = orinoco_nortel_init_one, - .remove = __devexit_p(orinoco_nortel_remove_one), + .remove = orinoco_nortel_remove_one, .suspend = orinoco_pci_suspend, .resume = orinoco_pci_resume, }; diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index 6058c66..677bf14 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -199,7 +199,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, return err; } -static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) +static void orinoco_pci_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); @@ -228,7 +228,7 @@ static struct pci_driver orinoco_pci_driver = { .name = DRIVER_NAME, .id_table = orinoco_pci_id_table, .probe = orinoco_pci_init_one, - .remove = __devexit_p(orinoco_pci_remove_one), + .remove = orinoco_pci_remove_one, .suspend = orinoco_pci_suspend, .resume = orinoco_pci_resume, }; diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index 2bac824..2559dbd 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -294,7 +294,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, return err; } -static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) +static void orinoco_plx_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); struct orinoco_pci_card *card = priv->card; @@ -334,7 +334,7 @@ static struct pci_driver orinoco_plx_driver = { .name = DRIVER_NAME, .id_table = orinoco_plx_id_table, .probe = orinoco_plx_init_one, - .remove = __devexit_p(orinoco_plx_remove_one), + .remove = orinoco_plx_remove_one, .suspend = orinoco_pci_suspend, .resume = orinoco_pci_resume, }; diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 93159d6..42afeee 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -188,7 +188,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, return err; } -static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) +static void orinoco_tmd_remove_one(struct pci_dev *pdev) { struct orinoco_private *priv = pci_get_drvdata(pdev); struct orinoco_pci_card *card = priv->card; @@ -214,7 +214,7 @@ static struct pci_driver orinoco_tmd_driver = { .name = DRIVER_NAME, .id_table = orinoco_tmd_id_table, .probe = orinoco_tmd_init_one, - .remove = __devexit_p(orinoco_tmd_remove_one), + .remove = orinoco_tmd_remove_one, .suspend = orinoco_pci_suspend, .resume = orinoco_pci_resume, }; -- cgit v0.10.2 From 337b563f72f2e379f11411614f68f3ec73f30592 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:38 -0500 Subject: p54: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Christian Lamparter Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 810c343..933e5d9 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -540,7 +540,7 @@ out: pci_dev_put(pdev); } -static int __devinit p54p_probe(struct pci_dev *pdev, +static int p54p_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct p54p_priv *priv; @@ -639,7 +639,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, return err; } -static void __devexit p54p_remove(struct pci_dev *pdev) +static void p54p_remove(struct pci_dev *pdev) { struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct p54p_priv *priv; @@ -692,7 +692,7 @@ static struct pci_driver p54p_driver = { .name = "p54pci", .id_table = p54p_table, .probe = p54p_probe, - .remove = __devexit_p(p54p_remove), + .remove = p54p_remove, .driver.pm = P54P_PM_OPS, }; diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index f792990..4fd49a0 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -595,7 +595,7 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) cancel_work_sync(&priv->work); } -static int __devinit p54spi_probe(struct spi_device *spi) +static int p54spi_probe(struct spi_device *spi) { struct p54s_priv *priv = NULL; struct ieee80211_hw *hw; @@ -683,7 +683,7 @@ err_free: return ret; } -static int __devexit p54spi_remove(struct spi_device *spi) +static int p54spi_remove(struct spi_device *spi) { struct p54s_priv *priv = dev_get_drvdata(&spi->dev); @@ -710,7 +710,7 @@ static struct spi_driver p54spi_driver = { }, .probe = p54spi_probe, - .remove = __devexit_p(p54spi_remove), + .remove = p54spi_remove, }; static int __init p54spi_init(void) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index effb044..e71c702 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -986,7 +986,7 @@ static int p54u_load_firmware(struct ieee80211_hw *dev, return err; } -static int __devinit p54u_probe(struct usb_interface *intf, +static int p54u_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); @@ -1057,7 +1057,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, return err; } -static void __devexit p54u_disconnect(struct usb_interface *intf) +static void p54u_disconnect(struct usb_interface *intf) { struct ieee80211_hw *dev = usb_get_intfdata(intf); struct p54u_priv *priv; @@ -1131,7 +1131,7 @@ static struct usb_driver p54u_driver = { .name = "p54usb", .id_table = p54u_table, .probe = p54u_probe, - .disconnect = __devexit_p(p54u_disconnect), + .disconnect = p54u_disconnect, .pre_reset = p54u_pre_reset, .post_reset = p54u_post_reset, #ifdef CONFIG_PM -- cgit v0.10.2 From 692023597a5ec01fa2e5e3eec36948c7655009f6 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:39 -0500 Subject: rt2x00: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Ivo van Doorn Cc: Gertjan van Wingerde Cc: Helmut Schaa Cc: users@rt2x00.serialmonkey.com (moderated for non-subscribers) Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index e3a2d90..a2d2bc2 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1831,7 +1831,7 @@ static struct pci_driver rt2400pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2400pci_device_table, .probe = rt2400pci_probe, - .remove = __devexit_p(rt2x00pci_remove), + .remove = rt2x00pci_remove, .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 479d756..9bea10f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2122,7 +2122,7 @@ static struct pci_driver rt2500pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2500pci_device_table, .probe = rt2500pci_probe, - .remove = __devexit_p(rt2x00pci_remove), + .remove = rt2x00pci_remove, .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, }; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 27829e1..9224d87 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1176,7 +1176,7 @@ static struct platform_driver rt2800soc_driver = { .mod_name = KBUILD_MODNAME, }, .probe = rt2800soc_probe, - .remove = __devexit_p(rt2x00soc_remove), + .remove = rt2x00soc_remove, .suspend = rt2x00soc_suspend, .resume = rt2x00soc_resume, }; @@ -1193,7 +1193,7 @@ static struct pci_driver rt2800pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2800pci_device_table, .probe = rt2800pci_probe, - .remove = __devexit_p(rt2x00pci_remove), + .remove = rt2x00pci_remove, .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index d6582a2..f95792c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -3094,7 +3094,7 @@ static struct pci_driver rt61pci_driver = { .name = KBUILD_MODNAME, .id_table = rt61pci_device_table, .probe = rt61pci_probe, - .remove = __devexit_p(rt2x00pci_remove), + .remove = rt2x00pci_remove, .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, }; -- cgit v0.10.2 From fb4e899dea7ea5e540db1deb71442d37bb8100fc Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:40 -0500 Subject: rtl8187: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index b4218a5..1b3c284 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -901,7 +901,7 @@ static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) udelay(10); } -static int __devinit rtl8180_probe(struct pci_dev *pdev, +static int rtl8180_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ieee80211_hw *dev; @@ -1131,7 +1131,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, return err; } -static void __devexit rtl8180_remove(struct pci_dev *pdev) +static void rtl8180_remove(struct pci_dev *pdev) { struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct rtl8180_priv *priv; @@ -1170,7 +1170,7 @@ static struct pci_driver rtl8180_driver = { .name = KBUILD_MODNAME, .id_table = rtl8180_table, .probe = rtl8180_probe, - .remove = __devexit_p(rtl8180_remove), + .remove = rtl8180_remove, #ifdef CONFIG_PM .suspend = rtl8180_suspend, .resume = rtl8180_resume, -- cgit v0.10.2 From fd549f135c43d60b92aff7cfbbfdf4e79b6cc631 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:41 -0500 Subject: rtl8187: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Herton Ronaldo Krzesinski Cc: Hin-Tak Leung Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 52e6beb..4574bd2 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -1411,7 +1411,7 @@ static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom) udelay(10); } -static int __devinit rtl8187_probe(struct usb_interface *intf, +static int rtl8187_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); @@ -1639,7 +1639,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, return err; } -static void __devexit rtl8187_disconnect(struct usb_interface *intf) +static void rtl8187_disconnect(struct usb_interface *intf) { struct ieee80211_hw *dev = usb_get_intfdata(intf); struct rtl8187_priv *priv; @@ -1664,7 +1664,7 @@ static struct usb_driver rtl8187_driver = { .name = KBUILD_MODNAME, .id_table = rtl8187_table, .probe = rtl8187_probe, - .disconnect = __devexit_p(rtl8187_disconnect), + .disconnect = rtl8187_disconnect, .disable_hub_initiated_lpm = 1, }; -- cgit v0.10.2 From b74324d1048271240f65b2d91816d15e72dd80dd Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:42 -0500 Subject: wlcore/wl18xx/wl12xx: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Bill Pemberton Cc: Luciano Coelho Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index e2750a1..e57ee48 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -305,7 +305,7 @@ out_free_hw: return ret; } -static void __devexit wl1251_sdio_remove(struct sdio_func *func) +static void wl1251_sdio_remove(struct sdio_func *func) { struct wl1251 *wl = sdio_get_drvdata(func); struct wl1251_sdio *wl_sdio = wl->if_priv; @@ -347,7 +347,7 @@ static struct sdio_driver wl1251_sdio_driver = { .name = "wl1251_sdio", .id_table = wl1251_devices, .probe = wl1251_sdio_probe, - .remove = __devexit_p(wl1251_sdio_remove), + .remove = wl1251_sdio_remove, .drv.pm = &wl1251_sdio_pm_ops, }; diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 567660c..3b266d3 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -237,7 +237,7 @@ static const struct wl1251_if_operations wl1251_spi_ops = { .power = wl1251_spi_set_power, }; -static int __devinit wl1251_spi_probe(struct spi_device *spi) +static int wl1251_spi_probe(struct spi_device *spi) { struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; @@ -309,7 +309,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) return ret; } -static int __devexit wl1251_spi_remove(struct spi_device *spi) +static int wl1251_spi_remove(struct spi_device *spi) { struct wl1251 *wl = dev_get_drvdata(&spi->dev); @@ -326,7 +326,7 @@ static struct spi_driver wl1251_spi_driver = { }, .probe = wl1251_spi_probe, - .remove = __devexit_p(wl1251_spi_remove), + .remove = wl1251_spi_remove, }; static int __init wl1251_spi_init(void) diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index dadf1db..e5f5f8f 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1696,7 +1696,7 @@ static int wl12xx_setup(struct wl1271 *wl) return 0; } -static int __devinit wl12xx_probe(struct platform_device *pdev) +static int wl12xx_probe(struct platform_device *pdev) { struct wl1271 *wl; struct ieee80211_hw *hw; @@ -1725,7 +1725,7 @@ out: return ret; } -static const struct platform_device_id wl12xx_id_table[] __devinitconst = { +static const struct platform_device_id wl12xx_id_table[] = { { "wl12xx", 0 }, { } /* Terminating Entry */ }; @@ -1733,7 +1733,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table); static struct platform_driver wl12xx_driver = { .probe = wl12xx_probe, - .remove = __devexit_p(wlcore_remove), + .remove = wlcore_remove, .id_table = wl12xx_id_table, .driver = { .name = "wl12xx_driver", diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index a39682a..8d8c1f8 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1499,7 +1499,7 @@ static int wl18xx_setup(struct wl1271 *wl) return 0; } -static int __devinit wl18xx_probe(struct platform_device *pdev) +static int wl18xx_probe(struct platform_device *pdev) { struct wl1271 *wl; struct ieee80211_hw *hw; @@ -1528,7 +1528,7 @@ out: return ret; } -static const struct platform_device_id wl18xx_id_table[] __devinitconst = { +static const struct platform_device_id wl18xx_id_table[] = { { "wl18xx", 0 }, { } /* Terminating Entry */ }; @@ -1536,7 +1536,7 @@ MODULE_DEVICE_TABLE(platform, wl18xx_id_table); static struct platform_driver wl18xx_driver = { .probe = wl18xx_probe, - .remove = __devexit_p(wlcore_remove), + .remove = wlcore_remove, .id_table = wl18xx_id_table, .driver = { .name = "wl18xx_driver", diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 4f1a05b..ea9d8e0 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5660,7 +5660,7 @@ out: complete_all(&wl->nvs_loading_complete); } -int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) +int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) { int ret; @@ -5683,7 +5683,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) } EXPORT_SYMBOL_GPL(wlcore_probe); -int __devexit wlcore_remove(struct platform_device *pdev) +int wlcore_remove(struct platform_device *pdev) { struct wl1271 *wl = platform_get_drvdata(pdev); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 73ace4b..646f703 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -54,7 +54,7 @@ struct wl12xx_sdio_glue { struct platform_device *core; }; -static const struct sdio_device_id wl1271_devices[] __devinitconst = { +static const struct sdio_device_id wl1271_devices[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, {} }; @@ -214,7 +214,7 @@ static struct wl1271_if_operations sdio_ops = { .set_block_size = wl1271_sdio_set_block_size, }; -static int __devinit wl1271_probe(struct sdio_func *func, +static int wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct wl12xx_platform_data *wlan_data; @@ -319,7 +319,7 @@ out: return ret; } -static void __devexit wl1271_remove(struct sdio_func *func) +static void wl1271_remove(struct sdio_func *func) { struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); @@ -384,7 +384,7 @@ static struct sdio_driver wl1271_sdio_driver = { .name = "wl1271_sdio", .id_table = wl1271_devices, .probe = wl1271_probe, - .remove = __devexit_p(wl1271_remove), + .remove = wl1271_remove, #ifdef CONFIG_PM .drv = { .pm = &wl1271_sdio_pm_ops, diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index a519bc3..f06f477 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -324,7 +324,7 @@ static struct wl1271_if_operations spi_ops = { .set_block_size = NULL, }; -static int __devinit wl1271_probe(struct spi_device *spi) +static int wl1271_probe(struct spi_device *spi) { struct wl12xx_spi_glue *glue; struct wl12xx_platform_data *pdata; @@ -403,7 +403,7 @@ out: return ret; } -static int __devexit wl1271_remove(struct spi_device *spi) +static int wl1271_remove(struct spi_device *spi) { struct wl12xx_spi_glue *glue = spi_get_drvdata(spi); @@ -422,7 +422,7 @@ static struct spi_driver wl1271_spi_driver = { }, .probe = wl1271_probe, - .remove = __devexit_p(wl1271_remove), + .remove = wl1271_remove, }; static int __init wl1271_init(void) diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 68584aa..c388493 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -414,8 +414,8 @@ struct wl1271 { struct completion nvs_loading_complete; }; -int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); -int __devexit wlcore_remove(struct platform_device *pdev); +int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); +int wlcore_remove(struct platform_device *pdev); struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size); int wlcore_free_hw(struct wl1271 *wl); int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, -- cgit v0.10.2 From 9e2ff36beae4bedbad2a69d458f9404f35fcb528 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 3 Dec 2012 09:56:43 -0500 Subject: rtlwifi: remove __dev* attributes CONFIG_HOTPLUG is going away as an option. As result the __dev* markings will be going away. Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst, and __devexit. Signed-off-by: Greg Kroah-Hartman Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 086140c..3deacaf 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1756,7 +1756,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, return true; } -int __devinit rtl_pci_probe(struct pci_dev *pdev, +int rtl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ieee80211_hw *hw = NULL; diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 7ea50a3..65b08f5 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -236,7 +236,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw); extern struct rtl_intf_ops rtl_pci_ops; -int __devinit rtl_pci_probe(struct pci_dev *pdev, +int rtl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtl_pci_disconnect(struct pci_dev *pdev); #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index e17f670..03c6d18 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -352,7 +352,7 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, }; -static struct pci_device_id rtl92de_pci_ids[] __devinitdata = { +static struct pci_device_id rtl92de_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8193, rtl92de_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x002B, rtl92de_hal_cfg)}, {}, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 45c3443..cecc377 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -400,7 +400,7 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, }; -static struct pci_device_id rtl92se_pci_ids[] __devinitdata = { +static struct pci_device_id rtl92se_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)}, diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index e3ea4b3..29f0969 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -940,7 +940,7 @@ static struct rtl_intf_ops rtl_usb_ops = { .waitq_insert = rtl_usb_tx_chk_waitq_insert, }; -int __devinit rtl_usb_probe(struct usb_interface *intf, +int rtl_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { int err; diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index 43846b3..5235136 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h @@ -156,7 +156,7 @@ struct rtl_usb_priv { -int __devinit rtl_usb_probe(struct usb_interface *intf, +int rtl_usb_probe(struct usb_interface *intf, const struct usb_device_id *id); void rtl_usb_disconnect(struct usb_interface *intf); int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message); -- cgit v0.10.2