Sorry. It should be "wifi: mwifiex: ...". I will submit correct one later. > From: David Lin <yu-hao.lin@xxxxxxx> > Sent: Wednesday, October 9, 2024 2:07 PM > To: linux-wireless@xxxxxxxxxxxxxxx > Cc: linux-kernel@xxxxxxxxxxxxxxx; briannorris@xxxxxxxxxxxx; > kvalo@xxxxxxxxxx; francesco@xxxxxxxxxx; Pete Hsieh > <tsung-hsien.hsieh@xxxxxxx>; s.hauer@xxxxxxxxxxxxxx; David Lin > <yu-hao.lin@xxxxxxx> > Subject: [PATCH v2] wifi: nxpwifi: fix firmware crash for AP DFS mode > > When AP mode is running on DFS channel and radar detection happened > during or after CAC, firmware will crash due to the code of mwifiex is too old > to handle DFS process. This patch fixes above issue and had been tested with > IW416. > > Signed-off-by: David Lin <yu-hao.lin@xxxxxxx> > --- > > v2: > - remove clean up for adapter (from priv->adapter to adapter). > - remove useless check of netif_carrier_ok(). > - just return directly for mwifiex_cfg80211_change_beacon(). > - remove debugfs file "fake_radar_detect". > > --- > drivers/net/wireless/marvell/mwifiex/11h.c | 49 ++++++++++++++++--- > .../net/wireless/marvell/mwifiex/cfg80211.c | 49 +++++++------------ > .../net/wireless/marvell/mwifiex/cfg80211.h | 4 +- > drivers/net/wireless/marvell/mwifiex/decl.h | 1 + > drivers/net/wireless/marvell/mwifiex/main.h | 1 + > 5 files changed, 66 insertions(+), 38 deletions(-) > > diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c > b/drivers/net/wireless/marvell/mwifiex/11h.c > index 032b93a41d99..3d8f6c610bca 100644 > --- a/drivers/net/wireless/marvell/mwifiex/11h.c > +++ b/drivers/net/wireless/marvell/mwifiex/11h.c > @@ -7,7 +7,7 @@ > > #include "main.h" > #include "fw.h" > - > +#include "cfg80211.h" > > void mwifiex_init_11h_params(struct mwifiex_private *priv) { @@ -221,8 > +221,11 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private > *priv, > cancel_delayed_work_sync(&priv->dfs_cac_work); > cfg80211_cac_event(priv->netdev, > &priv->dfs_chandef, > - NL80211_RADAR_DETECTED, > + NL80211_RADAR_CAC_ABORTED, > GFP_KERNEL, 0); > + cfg80211_radar_event(priv->adapter->wiphy, > + &priv->dfs_chandef, > + GFP_KERNEL); > } > break; > default: > @@ -245,9 +248,16 @@ int mwifiex_11h_handle_radar_detected(struct > mwifiex_private *priv, > > mwifiex_dbg(priv->adapter, MSG, > "radar detected; indicating kernel\n"); > - if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) > - mwifiex_dbg(priv->adapter, ERROR, > - "Failed to stop CAC in FW\n"); > + > + if (priv->wdev.links[0].cac_started) { > + if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) > + mwifiex_dbg(priv->adapter, ERROR, > + "Failed to stop CAC in FW\n"); > + cancel_delayed_work_sync(&priv->dfs_cac_work); > + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, > + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0); > + } > + > cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, > GFP_KERNEL); > mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n", @@ -268,8 > +278,12 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct > *work) > struct mwifiex_uap_bss_param *bss_cfg; > struct delayed_work *delayed_work = to_delayed_work(work); > struct mwifiex_private *priv = > - container_of(delayed_work, struct mwifiex_private, > - dfs_chan_sw_work); > + container_of(delayed_work, struct mwifiex_private, > + dfs_chan_sw_work); > + > + if (mwifiex_del_mgmt_ies(priv)) > + mwifiex_dbg(priv->adapter, ERROR, > + "Failed to delete mgmt IEs!\n"); > > bss_cfg = &priv->bss_cfg; > if (!bss_cfg->beacon_period) { > @@ -278,6 +292,21 @@ void mwifiex_dfs_chan_sw_work_queue(struct > work_struct *work) > return; > } > > + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, > + HostCmd_ACT_GEN_SET, 0, NULL, true)) { > + mwifiex_dbg(priv->adapter, ERROR, > + "channel switch: Failed to stop the BSS\n"); > + return; > + } > + > + if (mwifiex_cfg80211_change_beacon_data(priv->adapter->wiphy, > + priv->netdev, > + &priv->beacon_after)) { > + mwifiex_dbg(priv->adapter, ERROR, > + "channel switch: Failed to set beacon\n"); > + return; > + } > + > mwifiex_uap_set_channel(priv, bss_cfg, priv->dfs_chandef); > > if (mwifiex_config_start_uap(priv, bss_cfg)) { @@ -291,4 +320,10 @@ > void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) > wiphy_lock(priv->wdev.wiphy); > cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0); > wiphy_unlock(priv->wdev.wiphy); > + > + if (priv->uap_stop_tx) { > + netif_carrier_on(priv->netdev); > + mwifiex_wake_up_net_dev_queue(priv->netdev, priv->adapter); > + priv->uap_stop_tx = false; > + } > } > diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c > b/drivers/net/wireless/marvell/mwifiex/cfg80211.c > index fca3eea7ee84..40f51e62b2e7 100644 > --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c > +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c > @@ -1858,16 +1858,12 @@ static int > mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, > return 0; > } > > -/* cfg80211 operation handler for change_beacon. > - * Function retrieves and sets modified management IEs to FW. > - */ > -static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, > - struct net_device *dev, > - struct cfg80211_ap_update *params) > +int mwifiex_cfg80211_change_beacon_data(struct wiphy *wiphy, > + struct net_device *dev, > + struct cfg80211_beacon_data *data) > { > struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); > struct mwifiex_adapter *adapter = priv->adapter; > - struct cfg80211_beacon_data *data = ¶ms->beacon; > > mwifiex_cancel_scan(adapter); > > @@ -1877,12 +1873,6 @@ static int mwifiex_cfg80211_change_beacon(struct > wiphy *wiphy, > return -EINVAL; > } > > - if (!priv->bss_started) { > - mwifiex_dbg(priv->adapter, ERROR, > - "%s: bss not started\n", __func__); > - return -EINVAL; > - } > - > if (mwifiex_set_mgmt_ies(priv, data)) { > mwifiex_dbg(priv->adapter, ERROR, > "%s: setting mgmt ies failed\n", __func__); @@ -1892,6 > +1882,16 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy > *wiphy, > return 0; > } > > +/* cfg80211 operation handler for change_beacon. > + * Function retrieves and sets modified management IEs to FW. > + */ > +static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, > + struct net_device *dev, > + struct cfg80211_ap_update *params) { > + return mwifiex_cfg80211_change_beacon_data(wiphy, dev, > +¶ms->beacon); } > + > /* cfg80211 operation handler for del_station. > * Function deauthenticates station which value is provided in mac > parameter. > * If mac is NULL/broadcast, all stations in associated station list are @@ > -4027,10 +4027,8 @@ static int mwifiex_cfg80211_channel_switch(struct > wiphy *wiphy, struct net_device *dev, > struct cfg80211_csa_settings *params) { > - struct ieee_types_header *chsw_ie; > - struct ieee80211_channel_sw_ie *channel_sw; > - int chsw_msec; > struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); > + int chsw_msec; > > if (priv->adapter->scan_processing) { > mwifiex_dbg(priv->adapter, ERROR, > @@ -4045,20 +4043,10 @@ mwifiex_cfg80211_channel_switch(struct wiphy > *wiphy, struct net_device *dev, > &priv->dfs_chandef)) > return -EINVAL; > > - chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, > - params->beacon_csa.tail, > - params->beacon_csa.tail_len); > - if (!chsw_ie) { > - mwifiex_dbg(priv->adapter, ERROR, > - "Could not parse channel switch announcement IE\n"); > - return -EINVAL; > - } > - > - channel_sw = (void *)(chsw_ie + 1); > - if (channel_sw->mode) { > - if (netif_carrier_ok(priv->netdev)) > - netif_carrier_off(priv->netdev); > + if (params->block_tx) { > + netif_carrier_off(priv->netdev); > mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); > + priv->uap_stop_tx = true; > } > > if (mwifiex_del_mgmt_ies(priv)) > @@ -4075,7 +4063,7 @@ mwifiex_cfg80211_channel_switch(struct wiphy > *wiphy, struct net_device *dev, > memcpy(&priv->beacon_after, ¶ms->beacon_after, > sizeof(priv->beacon_after)); > > - chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, > 100); > + chsw_msec = max(params->count * priv->bss_cfg.beacon_period, 100); > queue_delayed_work(priv->dfs_chan_sw_workqueue, > &priv->dfs_chan_sw_work, > msecs_to_jiffies(chsw_msec)); > return 0; > @@ -4814,6 +4802,7 @@ int mwifiex_register_cfg80211(struct > mwifiex_adapter *adapter) > WIPHY_FLAG_HAS_CHANNEL_SWITCH | > WIPHY_FLAG_NETNS_OK | > WIPHY_FLAG_PS_ON_BY_DEFAULT; > + wiphy->max_num_csa_counters = MWIFIEX_MAX_CSA_COUNTERS; > > if (adapter->host_mlme_enabled) > wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS; diff --git > a/drivers/net/wireless/marvell/mwifiex/cfg80211.h > b/drivers/net/wireless/marvell/mwifiex/cfg80211.h > index 50f7001f5ef0..0a12437f89f2 100644 > --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.h > +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.h > @@ -13,5 +13,7 @@ > #include "main.h" > > int mwifiex_register_cfg80211(struct mwifiex_adapter *); > - > +int mwifiex_cfg80211_change_beacon_data(struct wiphy *wiphy, > + struct net_device *dev, > + struct cfg80211_beacon_data *data); > #endif > diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h > b/drivers/net/wireless/marvell/mwifiex/decl.h > index 84603f1e7f6e..9ece61743b9c 100644 > --- a/drivers/net/wireless/marvell/mwifiex/decl.h > +++ b/drivers/net/wireless/marvell/mwifiex/decl.h > @@ -19,6 +19,7 @@ > > #define MWIFIEX_BSS_COEX_COUNT 2 > #define MWIFIEX_MAX_BSS_NUM (3) > +#define MWIFIEX_MAX_CSA_COUNTERS 5 > > #define MWIFIEX_DMA_ALIGN_SZ 64 > #define MWIFIEX_RX_HEADROOM 64 > diff --git a/drivers/net/wireless/marvell/mwifiex/main.h > b/drivers/net/wireless/marvell/mwifiex/main.h > index 566adce3413c..58e8a3daba4a 100644 > --- a/drivers/net/wireless/marvell/mwifiex/main.h > +++ b/drivers/net/wireless/marvell/mwifiex/main.h > @@ -678,6 +678,7 @@ struct mwifiex_private { > struct delayed_work dfs_cac_work; > struct workqueue_struct *dfs_chan_sw_workqueue; > struct delayed_work dfs_chan_sw_work; > + bool uap_stop_tx; > struct cfg80211_beacon_data beacon_after; > struct mwifiex_11h_intf_state state_11h; > struct mwifiex_ds_mem_rw mem_rw; > > base-commit: 5a4d42c1688c88f3be6aef46b0ea6c32694cd2b8 > -- > 2.34.1