Commit 6a3be6e6 authored by Roland Vossen's avatar Roland Vossen Committed by Greg Kroah-Hartman

staging: brcm80211: bugfix for softmac crash on multi cpu configurations

Solved a locking issue that resulted in driver crashes with the 43224 and 43225
chips. The problem has been reported on several fora. Root cause was two fold:
hardware was being manipulated by two unsynchronized threads, and a scan
operation could interfere with an ongoing dynamic calibration process. Fix was
to invoke a lock on wl_ops_config() operation and to set internal flags when a
scan operation is started and stopped.

Please add this to the staging-linus branch.
Reviewed-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarRoland Vossen <rvossen@broadcom.com>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 454f1419
...@@ -263,9 +263,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, ...@@ -263,9 +263,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
switch (type) { switch (type) {
case NL80211_CHAN_HT20: case NL80211_CHAN_HT20:
case NL80211_CHAN_NO_HT: case NL80211_CHAN_NO_HT:
WL_LOCK(wl);
err = wlc_set(wl->wlc, WLC_SET_CHANNEL, chan->hw_value); err = wlc_set(wl->wlc, WLC_SET_CHANNEL, chan->hw_value);
WL_UNLOCK(wl);
break; break;
case NL80211_CHAN_HT40MINUS: case NL80211_CHAN_HT40MINUS:
case NL80211_CHAN_HT40PLUS: case NL80211_CHAN_HT40PLUS:
...@@ -285,6 +283,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) ...@@ -285,6 +283,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
int err = 0; int err = 0;
int new_int; int new_int;
WL_LOCK(wl);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
WL_NONE("%s: Setting listen interval to %d\n", WL_NONE("%s: Setting listen interval to %d\n",
__func__, conf->listen_interval); __func__, conf->listen_interval);
...@@ -341,6 +340,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) ...@@ -341,6 +340,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
} }
config_out: config_out:
WL_UNLOCK(wl);
return err; return err;
} }
...@@ -459,13 +459,21 @@ wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) ...@@ -459,13 +459,21 @@ wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) static void wl_ops_sw_scan_start(struct ieee80211_hw *hw)
{ {
struct wl_info *wl = hw->priv;
WL_NONE("Scan Start\n"); WL_NONE("Scan Start\n");
WL_LOCK(wl);
wlc_scan_start(wl->wlc);
WL_UNLOCK(wl);
return; return;
} }
static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw)
{ {
struct wl_info *wl = hw->priv;
WL_NONE("Scan Complete\n"); WL_NONE("Scan Complete\n");
WL_LOCK(wl);
wlc_scan_stop(wl->wlc);
WL_UNLOCK(wl);
return; return;
} }
......
...@@ -8461,3 +8461,16 @@ static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh, ...@@ -8461,3 +8461,16 @@ static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh,
kfree(qi); kfree(qi);
} }
/*
* Flag 'scan in progress' to withold dynamic phy calibration
*/
void wlc_scan_start(struct wlc_info *wlc)
{
wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
}
void wlc_scan_stop(struct wlc_info *wlc)
{
wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
}
...@@ -570,6 +570,8 @@ extern void wlc_enable_mac(struct wlc_info *wlc); ...@@ -570,6 +570,8 @@ extern void wlc_enable_mac(struct wlc_info *wlc);
extern u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate); extern u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate);
extern u32 wlc_get_rspec_history(struct wlc_bsscfg *cfg); extern u32 wlc_get_rspec_history(struct wlc_bsscfg *cfg);
extern u32 wlc_get_current_highest_rate(struct wlc_bsscfg *cfg); extern u32 wlc_get_current_highest_rate(struct wlc_bsscfg *cfg);
extern void wlc_scan_start(struct wlc_info *wlc);
extern void wlc_scan_stop(struct wlc_info *wlc);
static inline int wlc_iovar_getuint(struct wlc_info *wlc, const char *name, static inline int wlc_iovar_getuint(struct wlc_info *wlc, const char *name,
uint *arg) uint *arg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment