diff --git a/package/kernel/ath10k-ct/patches/100-api_update.patch b/package/kernel/ath10k-ct/patches/100-api_update.patch deleted file mode 100644 index 5343c29eb..000000000 --- a/package/kernel/ath10k-ct/patches/100-api_update.patch +++ /dev/null @@ -1,618 +0,0 @@ ---- a/ath10k-5.15/mac.c -+++ b/ath10k-5.15/mac.c -@@ -788,7 +788,7 @@ int ath10k_mac_vif_chan(struct ieee80211 - struct ieee80211_chanctx_conf *conf; - - rcu_read_lock(); -- conf = rcu_dereference(vif->chanctx_conf); -+ conf = rcu_dereference(vif->bss_conf.chanctx_conf); - if (!conf) { - rcu_read_unlock(); - return -ENOENT; -@@ -1764,8 +1764,8 @@ static int ath10k_vdev_start_restart(str - arg.channel.chan_radar = - !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); - } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { -- arg.ssid = arvif->vif->bss_conf.ssid; -- arg.ssid_len = arvif->vif->bss_conf.ssid_len; -+ arg.ssid = arvif->vif->cfg.ssid; -+ arg.ssid_len = arvif->vif->cfg.ssid_len; - } - - ath10k_dbg(ar, ATH10K_DBG_MAC, -@@ -1890,7 +1890,7 @@ static int ath10k_mac_setup_bcn_tmpl(str - arvif->vdev_type != WMI_VDEV_TYPE_IBSS) - return 0; - -- bcn = ieee80211_beacon_get_template(hw, vif, &offs); -+ bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); - if (!bcn) { - ath10k_warn(ar, "failed to get beacon template from mac80211\n"); - return -EPERM; -@@ -2083,8 +2083,7 @@ static void ath10k_control_beaconing(str - } - - static void ath10k_control_ibss(struct ath10k_vif *arvif, -- struct ieee80211_bss_conf *info, -- const u8 self_peer[ETH_ALEN]) -+ struct ieee80211_vif *vif) - { - struct ath10k *ar = arvif->ar; - u32 vdev_param; -@@ -2092,7 +2091,7 @@ static void ath10k_control_ibss(struct a - - lockdep_assert_held(&arvif->ar->conf_mutex); - -- if (!info->ibss_joined) { -+ if (!vif->cfg.ibss_joined) { - if (is_zero_ether_addr(arvif->bssid)) - return; - -@@ -2298,7 +2297,7 @@ static void ath10k_mac_vif_ap_csa_count_ - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) - return; - -- if (!vif->csa_active) -+ if (!vif->bss_conf.csa_active) - return; - - if (!arvif->is_up) -@@ -2433,7 +2432,7 @@ static void ath10k_peer_assoc_h_basic(st - lockdep_assert_held(&ar->conf_mutex); - - if (vif->type == NL80211_IFTYPE_STATION) -- aid = vif->bss_conf.aid; -+ aid = vif->cfg.aid; - else - aid = sta->aid; - -@@ -2463,7 +2462,8 @@ static void ath10k_peer_assoc_h_crypto(s - return; - - bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, -- info->ssid_len ? info->ssid : NULL, info->ssid_len, -+ vif->cfg.ssid_len ? vif->cfg.ssid : NULL, -+ vif->cfg.ssid_len, - IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (bss) { - const struct cfg80211_bss_ies *ies; -@@ -2521,7 +2521,7 @@ static void ath10k_peer_assoc_h_rates(st - - band = def.chan->band; - sband = ar->hw->wiphy->bands[band]; -- ratemask = sta->supp_rates[band]; -+ ratemask = sta->deflink.supp_rates[band]; - ratemask &= arvif->bitrate_mask.control[band].legacy; - rates = sband->bitrates; - -@@ -2770,7 +2770,7 @@ static void ath10k_peer_assoc_h_ht(struc - struct ieee80211_sta *sta, - struct wmi_peer_assoc_complete_arg *arg) - { -- const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; -+ const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; - struct ath10k_vif *arvif = (void *)vif->drv_priv; - struct cfg80211_chan_def def; - enum nl80211_band band; -@@ -2814,7 +2814,7 @@ static void ath10k_peer_assoc_h_ht(struc - if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) - arg->peer_flags |= ar->wmi.peer_flags->ldbc; - -- if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { -+ if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) { - arg->peer_flags |= ar->wmi.peer_flags->bw40; - arg->peer_rate_caps |= WMI_RC_CW40_FLAG; - } -@@ -2883,7 +2883,7 @@ static void ath10k_peer_assoc_h_ht(struc - arg->peer_ht_rates.rates[i] = i; - } else { - arg->peer_ht_rates.num_rates = n; -- arg->peer_num_spatial_streams = min(sta->rx_nss, max_nss); -+ arg->peer_num_spatial_streams = min(sta->deflink.rx_nss, max_nss); - } - - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", -@@ -3045,7 +3045,7 @@ static void ath10k_peer_assoc_h_vht(stru - struct ieee80211_sta *sta, - struct wmi_peer_assoc_complete_arg *arg) - { -- const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; -+ const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; - struct ath10k_vif *arvif = (void *)vif->drv_priv; - struct ath10k_hw_params *hw = &ar->hw_params; - struct cfg80211_chan_def def; -@@ -3087,10 +3087,10 @@ static void ath10k_peer_assoc_h_vht(stru - (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR + - ampdu_factor)) - 1); - -- if (sta->bandwidth == IEEE80211_STA_RX_BW_80) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) - arg->peer_flags |= ar->wmi.peer_flags->bw80; - -- if (sta->bandwidth == IEEE80211_STA_RX_BW_160) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) - arg->peer_flags |= ar->wmi.peer_flags->bw160; - - /* Calculate peer NSS capability from VHT capabilities if STA -@@ -3104,7 +3104,7 @@ static void ath10k_peer_assoc_h_vht(stru - vht_mcs_mask[i]) - max_nss = i + 1; - } -- arg->peer_num_spatial_streams = min(sta->rx_nss, max_nss); -+ arg->peer_num_spatial_streams = min(sta->deflink.rx_nss, max_nss); - arg->peer_vht_rates.rx_max_rate = - __le16_to_cpu(vht_cap->vht_mcs.rx_highest); - arg->peer_vht_rates.rx_mcs_set = -@@ -3266,7 +3266,7 @@ static bool ath10k_mac_sta_has_ofdm_only - { - struct ath10k_vif *arvif = (void *)vif->drv_priv; - u32 msk = arvif->bitrate_mask.control[NL80211_BAND_2GHZ].legacy & -- sta->supp_rates[NL80211_BAND_2GHZ]; -+ sta->deflink.supp_rates[NL80211_BAND_2GHZ]; - /* We have 12 bits of legacy rates, first 4 are /b (CCK) rates. */ - return (msk & 0xff0) && !(msk & 0xf); - } -@@ -3276,7 +3276,7 @@ static bool ath10k_mac_sta_has_ofdm_and_ - { - struct ath10k_vif *arvif = (void *)vif->drv_priv; - u32 msk = arvif->bitrate_mask.control[NL80211_BAND_2GHZ].legacy & -- sta->supp_rates[NL80211_BAND_2GHZ]; -+ sta->deflink.supp_rates[NL80211_BAND_2GHZ]; - /* We have 12 bits of legacy rates, first 4 are /b (CCK) rates. */ - return ((msk & 0xf) && (msk & 0xff0)); - } -@@ -3284,8 +3284,10 @@ static bool ath10k_mac_sta_has_ofdm_and_ - static enum wmi_phy_mode ath10k_mac_get_phymode_vht(struct ath10k *ar, - struct ieee80211_sta *sta) - { -- if (sta->bandwidth == IEEE80211_STA_RX_BW_160) { -- switch (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { -+ struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; -+ -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) { -+ switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { - case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: - return MODE_11AC_VHT160; - case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: -@@ -3296,13 +3298,13 @@ static enum wmi_phy_mode ath10k_mac_get_ - } - } - -- if (sta->bandwidth == IEEE80211_STA_RX_BW_80) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) - return MODE_11AC_VHT80; - -- if (sta->bandwidth == IEEE80211_STA_RX_BW_40) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) - return MODE_11AC_VHT40; - -- if (sta->bandwidth == IEEE80211_STA_RX_BW_20) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) - return MODE_11AC_VHT20; - - return MODE_UNKNOWN; -@@ -3329,15 +3331,15 @@ static void ath10k_peer_assoc_h_phymode( - - switch (band) { - case NL80211_BAND_2GHZ: -- if (sta->vht_cap.vht_supported && -+ if (sta->deflink.vht_cap.vht_supported && - !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) { -- if (sta->bandwidth == IEEE80211_STA_RX_BW_40) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) - phymode = MODE_11AC_VHT40; - else - phymode = MODE_11AC_VHT20; -- } else if (sta->ht_cap.ht_supported && -+ } else if (sta->deflink.ht_cap.ht_supported && - !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) { -- if (sta->bandwidth == IEEE80211_STA_RX_BW_40) -+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) - phymode = MODE_11NG_HT40; - else - phymode = MODE_11NG_HT20; -@@ -3354,12 +3356,12 @@ static void ath10k_peer_assoc_h_phymode( - /* - * Check VHT first. - */ -- if (sta->vht_cap.vht_supported && -+ if (sta->deflink.vht_cap.vht_supported && - !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) { - phymode = ath10k_mac_get_phymode_vht(ar, sta); -- } else if (sta->ht_cap.ht_supported && -+ } else if (sta->deflink.ht_cap.ht_supported && - !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) { -- if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) -+ if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) - phymode = MODE_11NA_HT40; - else - phymode = MODE_11NA_HT20; -@@ -3373,8 +3375,8 @@ static void ath10k_peer_assoc_h_phymode( - } - - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s legacy-supp-rates: 0x%x arvif-legacy-rates: 0x%x vht-supp: %d\n", -- sta->addr, ath10k_wmi_phymode_str(phymode), sta->supp_rates[band], -- arvif->bitrate_mask.control[band].legacy, sta->vht_cap.vht_supported); -+ sta->addr, ath10k_wmi_phymode_str(phymode), sta->deflink.supp_rates[band], -+ arvif->bitrate_mask.control[band].legacy, sta->deflink.vht_cap.vht_supported); - - arg->peer_phymode = phymode; - WARN_ON(phymode == MODE_UNKNOWN); -@@ -3677,8 +3679,8 @@ static void ath10k_bss_assoc(struct ieee - /* ap_sta must be accessed only within rcu section which must be left - * before calling ath10k_setup_peer_smps() which might sleep. - */ -- ht_cap = ap_sta->ht_cap; -- vht_cap = ap_sta->vht_cap; -+ ht_cap = ap_sta->deflink.ht_cap; -+ vht_cap = ap_sta->deflink.vht_cap; - - ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg); - if (ret) { -@@ -3713,11 +3715,11 @@ static void ath10k_bss_assoc(struct ieee - - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac vdev %d up (associated) bssid %pM aid %d bandwidth %d\n", -- arvif->vdev_id, bss_conf->bssid, bss_conf->aid, ap_sta->bandwidth); -+ arvif->vdev_id, bss_conf->bssid, vif->cfg.aid, ap_sta->deflink.bandwidth); - - WARN_ON(arvif->is_up); - -- arvif->aid = bss_conf->aid; -+ arvif->aid = vif->cfg.aid; - ether_addr_copy(arvif->bssid, bss_conf->bssid); - - ret = ath10k_wmi_pdev_set_param(ar, -@@ -4022,7 +4024,7 @@ static int ath10k_station_assoc(struct a - */ - if (!reassoc) { - ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, -- &sta->ht_cap); -+ &sta->deflink.ht_cap); - if (ret) { - ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n", - arvif->vdev_id, ret); -@@ -6916,7 +6918,7 @@ static void ath10k_recalculate_mgmt_rate - static void ath10k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, -- u32 changed) -+ u64 changed) - { - struct ath10k *ar = hw->priv; - struct ath10k_vif *arvif = (void *)vif->drv_priv; -@@ -6930,7 +6932,7 @@ static void ath10k_bss_info_changed(stru - mutex_lock(&ar->conf_mutex); - - if (changed & BSS_CHANGED_IBSS) -- ath10k_control_ibss(arvif, info, vif->addr); -+ ath10k_control_ibss(arvif, vif); - - if (changed & BSS_CHANGED_BEACON_INT) { - arvif->beacon_interval = info->beacon_int; -@@ -6995,9 +6997,9 @@ static void ath10k_bss_info_changed(stru - - if (changed & BSS_CHANGED_SSID && - vif->type == NL80211_IFTYPE_AP) { -- arvif->u.ap.ssid_len = info->ssid_len; -- if (info->ssid_len) -- memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len); -+ arvif->u.ap.ssid_len = vif->cfg.ssid_len; -+ if (vif->cfg.ssid_len) -+ memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); - arvif->u.ap.hidden_ssid = info->hidden_ssid; - } - -@@ -7074,7 +7076,7 @@ static void ath10k_bss_info_changed(stru - } - - if (changed & BSS_CHANGED_ASSOC) { -- if (info->assoc) { -+ if (vif->cfg.assoc) { - /* Workaround: Make sure monitor vdev is not running - * when associating to prevent some firmware revisions - * (e.g. 10.1 and 10.2) from crashing. -@@ -7099,7 +7101,7 @@ static void ath10k_bss_info_changed(stru - } - - if (changed & BSS_CHANGED_PS) { -- arvif->ps = vif->bss_conf.ps; -+ arvif->ps = vif->cfg.ps; - - ret = ath10k_config_ps(ar); - if (ret) -@@ -7699,7 +7701,7 @@ static void ath10k_sta_rc_update_wk(stru - - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_STA, "mac update sta %pM supp rates, bandwidth: %d\n", -- sta->addr, sta->bandwidth); -+ sta->addr, sta->deflink.bandwidth); - - err = ath10k_station_assoc(ar, arvif->vif, sta, true); - if (err) -@@ -7751,10 +7753,10 @@ static int ath10k_sta_set_txpwr(struct i - int ret = 0; - s16 txpwr; - -- if (sta->txpwr.type == NL80211_TX_POWER_AUTOMATIC) { -+ if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) { - txpwr = 0; - } else { -- txpwr = sta->txpwr.power; -+ txpwr = sta->deflink.txpwr.power; - if (!txpwr) - return -EINVAL; - } -@@ -7874,26 +7876,29 @@ static int ath10k_mac_validate_rate_mask - struct ieee80211_sta *sta, - u32 rate_ctrl_flag, u8 nss) - { -- if (nss > sta->rx_nss) { -+ struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; -+ struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; -+ -+ if (nss > sta->deflink.rx_nss) { - ath10k_warn(ar, "Invalid nss field, configured %u limit %u\n", -- nss, sta->rx_nss); -+ nss, sta->deflink.rx_nss); - return -EINVAL; - } - - if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_VHT) { -- if (!sta->vht_cap.vht_supported) { -+ if (!vht_cap->vht_supported) { - ath10k_warn(ar, "Invalid VHT rate for sta %pM\n", - sta->addr); - return -EINVAL; - } - } else if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_HT) { -- if (!sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) { -+ if (!ht_cap->ht_supported || vht_cap->vht_supported) { - ath10k_warn(ar, "Invalid HT rate for sta %pM\n", - sta->addr); - return -EINVAL; - } - } else { -- if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) -+ if (ht_cap->ht_supported || vht_cap->vht_supported) - return -EINVAL; - } - -@@ -8567,7 +8572,7 @@ static int ath10k_sta_state(struct ieee8 - * New association. - */ - ath10k_dbg(ar, ATH10K_DBG_STA, "mac sta %pM associated, bandwidth: %d\n", -- sta->addr, sta->bandwidth); -+ sta->addr, sta->deflink.bandwidth); - - ret = ath10k_station_assoc(ar, vif, sta, false); - if (ret) -@@ -8580,7 +8585,7 @@ static int ath10k_sta_state(struct ieee8 - * Tdls station authorized. - */ - ath10k_dbg(ar, ATH10K_DBG_STA, "mac tdls sta %pM authorized, bandwidth: %d\n", -- sta->addr, sta->bandwidth); -+ sta->addr, sta->deflink.bandwidth); - - ret = ath10k_station_assoc(ar, vif, sta, false); - if (ret) { -@@ -8721,8 +8726,8 @@ exit: - return ret; - } - --static int ath10k_conf_tx(struct ieee80211_hw *hw, -- struct ieee80211_vif *vif, u16 ac, -+static int ath10k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ unsigned int link_id, u16 ac, - const struct ieee80211_tx_queue_params *params) - { - struct ath10k *ar = hw->priv; -@@ -9308,7 +9313,7 @@ static bool ath10k_mac_set_vht_bitrate_m - u8 rate = arvif->vht_pfr; - - /* skip non vht and multiple rate peers */ -- if (!sta->vht_cap.vht_supported || arvif->vht_num_rates != 1) -+ if (!sta->deflink.vht_cap.vht_supported || arvif->vht_num_rates != 1) - return false; - - err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, -@@ -9349,7 +9354,7 @@ static void ath10k_mac_clr_bitrate_mask_ - int err; - - /* clear vht peers only */ -- if (arsta->arvif != arvif || !sta->vht_cap.vht_supported) -+ if (arsta->arvif != arvif || !sta->deflink.vht_cap.vht_supported) - return; - - err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, -@@ -9534,13 +9539,13 @@ static void ath10k_sta_rc_update(struct - - ath10k_dbg(ar, ATH10K_DBG_STA, - "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", -- sta->addr, changed, sta->bandwidth, sta->rx_nss, -- sta->smps_mode); -+ sta->addr, changed, sta->deflink.bandwidth, sta->deflink.rx_nss, -+ sta->deflink.smps_mode); - - if (changed & IEEE80211_RC_BW_CHANGED) { - bw = WMI_PEER_CHWIDTH_20MHZ; - -- switch (sta->bandwidth) { -+ switch (sta->deflink.bandwidth) { - case IEEE80211_STA_RX_BW_20: - bw = WMI_PEER_CHWIDTH_20MHZ; - break; -@@ -9555,7 +9560,7 @@ static void ath10k_sta_rc_update(struct - break; - default: - ath10k_warn(ar, "Invalid bandwidth %d in rc update for %pM\n", -- sta->bandwidth, sta->addr); -+ sta->deflink.bandwidth, sta->addr); - bw = WMI_PEER_CHWIDTH_20MHZ; - break; - } -@@ -9564,12 +9569,12 @@ static void ath10k_sta_rc_update(struct - } - - if (changed & IEEE80211_RC_NSS_CHANGED) -- arsta->nss = sta->rx_nss; -+ arsta->nss = sta->deflink.rx_nss; - - if (changed & IEEE80211_RC_SMPS_CHANGED) { - smps = WMI_PEER_SMPS_PS_NONE; - -- switch (sta->smps_mode) { -+ switch (sta->deflink.smps_mode) { - case IEEE80211_SMPS_AUTOMATIC: - case IEEE80211_SMPS_OFF: - smps = WMI_PEER_SMPS_PS_NONE; -@@ -9582,7 +9587,7 @@ static void ath10k_sta_rc_update(struct - break; - case IEEE80211_SMPS_NUM_MODES: - ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n", -- sta->smps_mode, sta->addr); -+ sta->deflink.smps_mode, sta->addr); - smps = WMI_PEER_SMPS_PS_NONE; - break; - } -@@ -9896,7 +9901,7 @@ ath10k_mac_change_chanctx_cnt_iter(void - { - struct ath10k_mac_change_chanctx_arg *arg = data; - -- if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx) -+ if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) - return; - - arg->n_vifs++; -@@ -9909,7 +9914,7 @@ ath10k_mac_change_chanctx_fill_iter(void - struct ath10k_mac_change_chanctx_arg *arg = data; - struct ieee80211_chanctx_conf *ctx; - -- ctx = rcu_access_pointer(vif->chanctx_conf); -+ ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); - if (ctx != arg->ctx) - return; - -@@ -9982,6 +9987,7 @@ unlock: - static int - ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, -+ struct ieee80211_bss_conf *link_conf, - struct ieee80211_chanctx_conf *ctx) - { - struct ath10k *ar = hw->priv; -@@ -10061,6 +10067,7 @@ err: - static void - ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, -+ struct ieee80211_bss_conf *link_conf, - struct ieee80211_chanctx_conf *ctx) - { - struct ath10k *ar = hw->priv; ---- a/ath10k-5.15/txrx.c -+++ b/ath10k-5.15/txrx.c -@@ -260,7 +260,7 @@ int ath10k_txrx_tx_unref(struct ath10k_h - nf = ar->debug.nf_sum[0]; - #endif - info->status.ack_signal = nf + tx_done->ack_rssi; -- info->status.is_valid_ack_signal = true; -+ info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; - } - - if (tx_done->tx_rate_code || tx_done->tx_rate_flags || ar->ok_tx_rate_status) { ---- a/ath10k-5.15/wmi.c -+++ b/ath10k-5.15/wmi.c -@@ -2587,7 +2587,7 @@ wmi_process_mgmt_tx_comp(struct ath10k * - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ath10k_get_noisefloor(0, ar) + - param->ack_rssi; -- info->status.is_valid_ack_signal = true; -+ info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; - } - - ieee80211_tx_status_irqsafe(ar->hw, msdu); -@@ -4258,13 +4258,13 @@ void ath10k_wmi_event_host_swba(struct a - * Once CSA counter is completed stop sending beacons until - * actual channel switch is done - */ -- if (arvif->vif->csa_active && -+ if (arvif->vif->bss_conf.csa_active && - ieee80211_beacon_cntdwn_is_complete(arvif->vif)) { - ieee80211_csa_finish(arvif->vif); - continue; - } - -- bcn = ieee80211_beacon_get(ar->hw, arvif->vif); -+ bcn = ieee80211_beacon_get(ar->hw, arvif->vif, 0); - if (!bcn) { - ath10k_warn(ar, "could not get mac80211 beacon, vdev_id: %i addr: %pM\n", - arvif->vdev_id, arvif->vif->addr); ---- a/ath10k-5.15/htt_rx.c -+++ b/ath10k-5.15/htt_rx.c -@@ -4017,7 +4017,7 @@ ath10k_update_per_peer_tx_stats(struct a - switch (txrate.flags) { - case WMI_RATE_PREAMBLE_OFDM: - if (arsta->arvif && arsta->arvif->vif) -- conf = rcu_dereference(arsta->arvif->vif->chanctx_conf); -+ conf = rcu_dereference(arsta->arvif->vif->bss_conf.chanctx_conf); - if (conf && conf->def.chan->band == NL80211_BAND_5GHZ) - arsta->tx_info.status.rates[0].idx = rate_idx - 4; - break; ---- a/ath10k-5.15/wmi-tlv.c -+++ b/ath10k-5.15/wmi-tlv.c -@@ -205,7 +205,7 @@ static int ath10k_wmi_tlv_event_bcn_tx_s - } - - arvif = ath10k_get_arvif(ar, vdev_id); -- if (arvif && arvif->is_up && arvif->vif->csa_active) -+ if (arvif && arvif->is_up && arvif->vif->bss_conf.csa_active) - ieee80211_queue_work(ar->hw, &arvif->ap_csa_work); - - kfree(tb); ---- a/ath10k-5.15/core.c -+++ b/ath10k-5.15/core.c -@@ -4081,7 +4081,7 @@ static int ath10k_core_probe_fw(struct a - ath10k_debug_print_board_info(ar); - } - -- device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr)); -+ device_get_mac_address(ar->dev, ar->mac_addr); - - /* Try to get mac address from device node (from nvmem cell) */ - of_get_mac_address(ar->dev->of_node, ar->mac_addr); ---- a/ath10k-5.15/pci.c -+++ b/ath10k-5.15/pci.c -@@ -3547,8 +3547,7 @@ static void ath10k_pci_free_irq(struct a - - void ath10k_pci_init_napi(struct ath10k *ar) - { -- netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll, -- ATH10K_NAPI_BUDGET); -+ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll); - } - - static int ath10k_pci_init_irq(struct ath10k *ar) ---- a/ath10k-5.15/sdio.c -+++ b/ath10k-5.15/sdio.c -@@ -2531,8 +2531,7 @@ static int ath10k_sdio_probe(struct sdio - return -ENOMEM; - } - -- netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll, -- ATH10K_NAPI_BUDGET); -+ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll); - - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", ---- a/ath10k-5.15/snoc.c -+++ b/ath10k-5.15/snoc.c -@@ -1242,8 +1242,7 @@ static int ath10k_snoc_napi_poll(struct - - static void ath10k_snoc_init_napi(struct ath10k *ar) - { -- netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, -- ATH10K_NAPI_BUDGET); -+ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll); - } - - static int ath10k_snoc_request_irq(struct ath10k *ar) diff --git a/package/kernel/ath10k-ct/patches/202-ath10k-use-tpt-trigger-by-default.patch b/package/kernel/ath10k-ct/patches/202-ath10k-use-tpt-trigger-by-default.patch index 18c793020..fb8468b9c 100644 --- a/package/kernel/ath10k-ct/patches/202-ath10k-use-tpt-trigger-by-default.patch +++ b/package/kernel/ath10k-ct/patches/202-ath10k-use-tpt-trigger-by-default.patch @@ -42,7 +42,7 @@ Signed-off-by: Mathias Kresin if (ret) --- a/ath10k-5.15/mac.c +++ b/ath10k-5.15/mac.c -@@ -11551,7 +11551,7 @@ int ath10k_mac_register(struct ath10k *a +@@ -11544,7 +11544,7 @@ int ath10k_mac_register(struct ath10k *a ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; #ifdef CPTCFG_MAC80211_LEDS diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index b0e944745..7e9e5d1c9 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -10,11 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 -PKG_VERSION:=6.1-rc8 +PKG_VERSION:=5.15.33-1 PKG_RELEASE:=2 -# PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.58/ -PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/ -PKG_HASH:=7f3d96c2573183cd79d6a3ebe5e1b7b73c19d1326d443c85b69c4181f14e6e2b +PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.33/ +PKG_HASH:=1b6b3bded4c81814ebebe2d194c2f8966d2399005b85ebb0557285b6e73f5422 PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION) @@ -307,7 +306,6 @@ define Build/Prepare $(PKG_BUILD_DIR)/include/linux/crc8.h \ $(PKG_BUILD_DIR)/include/linux/eeprom_93cx6.h \ $(PKG_BUILD_DIR)/include/linux/wl12xx.h \ - $(PKG_BUILD_DIR)/include/linux/mhi.h \ $(PKG_BUILD_DIR)/include/net/ieee80211.h \ $(PKG_BUILD_DIR)/backport-include/linux/bcm47xx_nvram.h diff --git a/package/kernel/mac80211/ath.mk b/package/kernel/mac80211/ath.mk index a13db4eaf..d9623da14 100644 --- a/package/kernel/mac80211/ath.mk +++ b/package/kernel/mac80211/ath.mk @@ -13,7 +13,6 @@ PKG_CONFIG_DEPENDS += \ CONFIG_ATH9K_TX99 \ CONFIG_ATH10K_LEDS \ CONFIG_ATH10K_THERMAL \ - CONFIG_ATH11K_THERMAL \ CONFIG_ATH11K_MEM_PROFILE_512MB \ CONFIG_ATH11K_MEM_PROFILE_1GB \ CONFIG_ATH_USER_REGD @@ -58,7 +57,6 @@ config-$(CONFIG_ATH9K_TX99) += ATH9K_TX99 config-$(CONFIG_ATH9K_UBNTHSR) += ATH9K_UBNTHSR config-$(CONFIG_ATH10K_LEDS) += ATH10K_LEDS config-$(CONFIG_ATH10K_THERMAL) += ATH10K_THERMAL -config-$(CONFIG_ATH11K_THERMAL) += ATH11K_THERMA config-$(CONFIG_ATH11K_MEM_PROFILE_512MB) += ATH11K_MEM_PROFILE_512MB config-$(CONFIG_ATH11K_MEM_PROFILE_1GB) += ATH11K_MEM_PROFILE_1GB @@ -206,7 +204,7 @@ define KernelPackage/ath9k-common TITLE:=Atheros 802.11n wireless devices (common code for ath9k and ath9k_htc) URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k HIDDEN:=1 - DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ath79 +kmod-ath +@DRIVER_11N_SUPPORT +kmod-random-core + DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ath79 +kmod-ath +@DRIVER_11N_SUPPORT FILES:= \ $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_common.ko \ $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_hw.ko diff --git a/package/kernel/mac80211/broadcom.mk b/package/kernel/mac80211/broadcom.mk index e1abfca0b..9ae0b617b 100644 --- a/package/kernel/mac80211/broadcom.mk +++ b/package/kernel/mac80211/broadcom.mk @@ -413,7 +413,7 @@ define KernelPackage/brcmfmac $(call KernelPackage/mac80211/Default) TITLE:=Broadcom IEEE802.11n USB FullMAC WLAN driver URL:=https://wireless.wiki.kernel.org/en/users/drivers/brcm80211 - DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT \ + DEPENDS+= @USB_SUPPORT +kmod-mac80211 +kmod-cfg80211 +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT \ +kmod-brcmutil +BRCMFMAC_SDIO:kmod-mmc @!TARGET_uml \ +BRCMFMAC_USB:kmod-usb-core +BRCMFMAC_USB:brcmfmac-firmware-usb FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index afc901129..7dae1af71 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -1,7 +1,6 @@ #!/bin/sh . /lib/netifd/netifd-wireless.sh . /lib/netifd/hostapd.sh -. /lib/functions/system.sh init_wireless_driver "$@" @@ -51,8 +50,6 @@ drv_mac80211_init_device_config() { rx_antenna_pattern \ tx_antenna_pattern \ he_spr_sr_control \ - he_spr_psr_enabled \ - he_bss_color_enabled \ he_twt_required config_add_int \ beamformer_antennas \ @@ -416,14 +413,12 @@ mac80211_hostapd_setup_base() { if [ "$enable_ax" != "0" ]; then json_get_vars \ he_su_beamformer:1 \ - he_su_beamformee:1 \ + he_su_beamformee:0 \ he_mu_beamformer:1 \ he_twt_required:0 \ - he_spr_sr_control:3 \ - he_spr_psr_enabled:0 \ - he_spr_non_srg_obss_pd_max_offset:0 \ - he_bss_color:128 \ - he_bss_color_enabled:1 + he_spr_sr_control:0 \ + he_spr_non_srg_obss_pd_max_offset:1 \ + he_bss_color he_phy_cap=$(iw phy "$phy" info | sed -n '/HE Iftypes: AP/,$p' | awk -F "[()]" '/HE PHY Capabilities/ { print $2 }' | head -1) he_phy_cap=${he_phy_cap:2} @@ -431,6 +426,16 @@ mac80211_hostapd_setup_base() { he_mac_cap=${he_mac_cap:2} append base_cfg "ieee80211ax=1" "$N" + + if [ -n "$he_bss_color" ]; then + append base_cfg "he_bss_color=$he_bss_color" "$N" + else + he_bss_color=$(head -1 /dev/urandom | tr -dc '0-9' | head -c2) + he_bss_color=$(($he_bss_color % 63)) + he_bss_color=$(($he_bss_color + 1)) + append base_cfg "he_bss_color=$he_bss_color" "$N" + fi + [ "$hwmode" = "a" ] && { append base_cfg "he_oper_chwidth=$vht_oper_chwidth" "$N" append base_cfg "he_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N" @@ -440,21 +445,10 @@ mac80211_hostapd_setup_base() { he_su_beamformer:${he_phy_cap:6:2}:0x80:$he_su_beamformer \ he_su_beamformee:${he_phy_cap:8:2}:0x1:$he_su_beamformee \ he_mu_beamformer:${he_phy_cap:8:2}:0x2:$he_mu_beamformer \ - he_spr_psr_enabled:${he_phy_cap:14:2}:0x1:$he_spr_psr_enabled \ + he_spr_sr_control:${he_phy_cap:14:2}:0x1:$he_spr_sr_control \ he_twt_required:${he_mac_cap:0:2}:0x6:$he_twt_required - if [ "$he_bss_color_enabled" -gt 0 ]; then - append base_cfg "he_bss_color=$he_bss_color" "$N" - [ "$he_spr_non_srg_obss_pd_max_offset" -gt 0 ] && { \ - append base_cfg "he_spr_non_srg_obss_pd_max_offset=$he_spr_non_srg_obss_pd_max_offset" "$N" - he_spr_sr_control=$((he_spr_sr_control | (1 << 2))) - } - [ "$he_spr_psr_enabled" -gt 0 ] || he_spr_sr_control=$((he_spr_sr_control | (1 << 0))) - append base_cfg "he_spr_sr_control=$he_spr_sr_control" "$N" - else - append base_cfg "he_bss_color_disabled=1" "$N" - fi - + [ "$he_spr_sr_control" -gt 0 ] && append base_cfg "he_spr_non_srg_obss_pd_max_offset=$he_spr_non_srg_obss_pd_max_offset" "$N" append base_cfg "he_default_pe_duration=4" "$N" append base_cfg "he_rts_threshold=1023" "$N" @@ -680,12 +674,10 @@ mac80211_prepare_vif() { json_select .. - if [ -z "$macaddr" ]; then + [ -n "$macaddr" ] || { macaddr="$(mac80211_generate_mac $phy)" macidx="$(($macidx + 1))" - elif [ "$macaddr" = 'random' ]; then - macaddr="$(macaddr_random)" - fi + } json_add_object data json_add_string ifname "$ifname" diff --git a/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch b/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch index fd29fb372..514cfd9e5 100644 --- a/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch +++ b/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch @@ -82,7 +82,7 @@ help --- a/local-symbols +++ b/local-symbols -@@ -110,6 +110,7 @@ ADM8211= +@@ -83,6 +83,7 @@ ADM8211= ATH_COMMON= WLAN_VENDOR_ATH= ATH_DEBUG= diff --git a/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch b/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch index 8d83921a3..c8eef504c 100644 --- a/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch +++ b/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch @@ -1,6 +1,6 @@ --- a/net/wireless/reg.c +++ b/net/wireless/reg.c -@@ -3370,6 +3370,8 @@ void regulatory_hint_country_ie(struct w +@@ -3304,6 +3304,8 @@ void regulatory_hint_country_ie(struct w enum environment_cap env = ENVIRON_ANY; struct regulatory_request *request = NULL, *lr; @@ -9,7 +9,7 @@ /* IE len must be evenly divisible by 2 */ if (country_ie_len & 0x01) return; -@@ -3621,6 +3623,7 @@ static bool is_wiphy_all_set_reg_flag(en +@@ -3555,6 +3557,7 @@ static bool is_wiphy_all_set_reg_flag(en void regulatory_hint_disconnect(void) { diff --git a/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch b/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch index 6723721a4..088833199 100644 --- a/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch +++ b/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch @@ -8,7 +8,7 @@ FRANCE_RES = 0x31, FCC3_FCCA = 0x3A, FCC3_WORLD = 0x3B, -@@ -173,6 +174,7 @@ static struct reg_dmn_pair_mapping regDo +@@ -172,6 +173,7 @@ static struct reg_dmn_pair_mapping regDo {FCC2_WORLD, CTL_FCC, CTL_ETSI}, {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, {FCC3_FCCA, CTL_FCC, CTL_FCC}, @@ -16,7 +16,7 @@ {FCC3_WORLD, CTL_FCC, CTL_ETSI}, {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, {FCC4_FCCA, CTL_FCC, CTL_FCC}, -@@ -486,6 +488,7 @@ static struct country_code_to_enum_rd al +@@ -483,6 +485,7 @@ static struct country_code_to_enum_rd al {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, diff --git a/package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch b/package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch index f89083b98..de6f9d9bb 100644 --- a/package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch +++ b/package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch @@ -37,7 +37,7 @@ void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); --- a/local-symbols +++ b/local-symbols -@@ -169,6 +169,7 @@ ATH10K_SNOC= +@@ -142,6 +142,7 @@ ATH10K_SNOC= ATH10K_DEBUG= ATH10K_DEBUGFS= ATH10K_SPECTRAL= diff --git a/package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch b/package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch new file mode 100644 index 000000000..c02485091 --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch @@ -0,0 +1,69 @@ +From 2587d5198aa5adcbd8896aae4a2404dc13d48637 Mon Sep 17 00:00:00 2001 +From: Sergey Ryazanov +Date: Wed, 18 May 2022 10:27:26 +0300 +Subject: ath10k: improve tx status reporting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We use ieee80211_tx_status() to report each completed tx frame. +Internally, this function calls sta_info_get_by_addrs(), what has a +couple of drawbacks: +1. additional station lookup causes a performance degradation; +2. mac80211 can not properly account Ethernet encapsulated frames due + to the inability to properly determine the destination (station) MAC + address since ieee80211_tx_status() assumes the frame has a 802.11 + header. + +The latter is especially destructive if we want to use hardware frames +encapsulation. + +To fix both of these issues, replace ieee80211_tx_status() with +ieee80211_tx_status_ext() call and feed it station pointer from the tx +queue associated with the transmitted frame. + +Tested-on: QCA9888 hw2.0 PCI 10.4-3.9.0.2-00131 +Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00157-QCARMSWPZ-1 + +Signed-off-by: Sergey Ryazanov +Tested-by: Oldřich Jedlička # TP-Link Archer C7 v4 & v5 (QCA9563 + QCA9880) +Tested-by: Edward Matijevic # TP-Link Archer C2600 (IPQ8064 + QCA9980 10.4.1.00030-1) +Tested-by: Edward Matijevic # QCA9377 PCI in Sta mode +Tested-by: Zhijun You # NETGEAR R7800 (QCA9984 10.4-3.9.0.2-00159) +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220516032519.29831-2-ryazanov.s.a@gmail.com +--- + drivers/net/wireless/ath/ath10k/txrx.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath10k/txrx.c ++++ b/drivers/net/wireless/ath/ath10k/txrx.c +@@ -43,6 +43,7 @@ out: + int ath10k_txrx_tx_unref(struct ath10k_htt *htt, + const struct htt_tx_done *tx_done) + { ++ struct ieee80211_tx_status status; + struct ath10k *ar = htt->ar; + struct device *dev = ar->dev; + struct ieee80211_tx_info *info; +@@ -128,7 +129,19 @@ int ath10k_txrx_tx_unref(struct ath10k_h + info->status.is_valid_ack_signal = true; + } + +- ieee80211_tx_status(htt->ar->hw, msdu); ++ memset(&status, 0, sizeof(status)); ++ status.skb = msdu; ++ status.info = info; ++ ++ rcu_read_lock(); ++ ++ if (txq) ++ status.sta = txq->sta; ++ ++ ieee80211_tx_status_ext(htt->ar->hw, &status); ++ ++ rcu_read_unlock(); ++ + /* we do not own the msdu anymore */ + + return 0; diff --git a/package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch b/package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch new file mode 100644 index 000000000..e67281552 --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch @@ -0,0 +1,74 @@ +From a09740548275a74b897654b3aca5af589289b57a Mon Sep 17 00:00:00 2001 +From: Sergey Ryazanov +Date: Mon, 16 May 2022 13:26:00 +0300 +Subject: ath10k: turn rawmode into frame_mode + +Turn boolean rawmode module param into integer frame_mode param that +contains value from ath10k_hw_txrx_mode enum. As earlier the default +param value is non-RAW (native Wi-Fi) encapsulation. The param name +is selected to be consistent with the similar ath11k param. + +This is a preparation step for upcoming encapsulation offloading +support. + +Signed-off-by: Sergey Ryazanov +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220516032519.29831-4-ryazanov.s.a@gmail.com +--- + drivers/net/wireless/ath/ath10k/core.c | 11 +++++++---- + drivers/net/wireless/ath/ath10k/core.h | 1 + + 2 files changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -32,9 +32,11 @@ EXPORT_SYMBOL(ath10k_debug_mask); + static unsigned int ath10k_cryptmode_param; + static bool uart_print; + static bool skip_otp; +-static bool rawmode; + static bool fw_diag_log; + ++/* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ ++unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; ++ + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); + +@@ -43,15 +45,16 @@ module_param_named(debug_mask, ath10k_de + module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); + module_param(uart_print, bool, 0644); + module_param(skip_otp, bool, 0644); +-module_param(rawmode, bool, 0644); + module_param(fw_diag_log, bool, 0644); ++module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); + MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); +-MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); ++MODULE_PARM_DESC(frame_mode, ++ "Datapath frame mode (0: raw, 1: native wifi (default))"); + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + +@@ -2487,7 +2490,7 @@ static int ath10k_core_init_firmware_fea + ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT; + ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT; + +- if (rawmode) { ++ if (ath10k_frame_mode == ATH10K_HW_TXRX_RAW) { + if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, + fw_file->fw_features)) { + ath10k_err(ar, "rawmode = 1 requires support from firmware"); +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -1311,6 +1311,7 @@ static inline bool ath10k_peer_stats_ena + return false; + } + ++extern unsigned int ath10k_frame_mode; + extern unsigned long ath10k_coredump_mask; + + void ath10k_core_napi_sync_disable(struct ath10k *ar); diff --git a/package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch b/package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch new file mode 100644 index 000000000..a669c77fe --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch @@ -0,0 +1,163 @@ +From 70f119fb82af7f7417dc659faf02c91e1f853739 Mon Sep 17 00:00:00 2001 +From: Sergey Ryazanov +Date: Mon, 16 May 2022 13:26:00 +0300 +Subject: ath10k: htt_tx: do not interpret Eth frames as WiFi + +The xmit path for the Ethernet encapsulated frames become more or less +usable since d740d8fd2439 ("ath10k: unify tx mode and dispatch"). This +change reorganize the xmit path in a manageable way to properly support +various tx modes, but misses that the Ethernet encapsulated frame is a +special case. We do not have an IEEE 802.11 header at the begining of +them. But the HTT Tx handler still interprets first bytes of each frame +as an IEEE 802.11 Frame Control field. + +Than this code was copied by e62ee5c381c5 ("ath10k: Add support for +htt_data_tx_desc_64 descriptor") and a2097d6444c3 ("ath10k: htt: High +latency TX support") to another handlers. In fact the issue in the high +latency (HL) handler was introduced by 83ac260151e7 ("ath10k: add mic +bytes for pmf management packet"). + +Ethernet encapsulated frame tx mode stay unused until 75d85fd9993c +("ath10k: introduce basic tdls functionality") started using it for TDLS +frames to avoid key selection issue in some firmwares. + +Trying to interpret the begining of an Ethernet encapsulated frame as an +IEEE 802.11 header was not hurt us noticeably since we need to meet two +conditions: (1) xmit should be performed towards a TDLS peer, and (2) +the TDLS peer should have a specific OUI part of its MAC address. Looks +like that the rareness in TDLS communications of OUIs that can be +interpreted as an 802.11 management frame saves users from facing this +issue earlier. + +Improve Ethernet tx mode support in the HTT Tx handler by avoiding +interpreting its first bytes as an IEEE 802.11 header. While at it, make +the ieee80211_hdr variable local to the code block that is guarded by +!is_eth check. In this way, we clarify in which cases a frame can be +interpreted as IEEE 802.11, and saves us from similar issues in the +future. + +Credits: this change as part of xmit encapsulation offloading support +was originally made by QCA and then submitted for inclusion by John +Crispin [1]. But the whole work was not accepted due to the lack of a +part for 64-bits descriptors [2]. Zhijun You then pointed this out to me +in a reply to my initial RFC patch series. And I made this slightly +reworked version that covered all the HTT Tx handler variants. + +1. https://lore.kernel.org/all/20191216092207.31032-1-john@phrozen.org/ +2. https://patchwork.kernel.org/project/linux-wireless/patch/20191216092207.31032-1-john@phrozen.org/ + +Reported-by: Zhijun You +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: John Crispin +Signed-off-by: Sergey Ryazanov +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220516032519.29831-3-ryazanov.s.a@gmail.com +--- + drivers/net/wireless/ath/ath10k/htt_tx.c | 61 ++++++++++++++++++-------------- + 1 file changed, 35 insertions(+), 26 deletions(-) + +--- a/drivers/net/wireless/ath/ath10k/htt_tx.c ++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c +@@ -1295,7 +1295,6 @@ static int ath10k_htt_tx_hl(struct ath10 + struct ath10k *ar = htt->ar; + int res, data_len; + struct htt_cmd_hdr *cmd_hdr; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; + struct htt_data_tx_desc *tx_desc; + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); + struct sk_buff *tmp_skb; +@@ -1306,11 +1305,15 @@ static int ath10k_htt_tx_hl(struct ath10 + u16 flags1 = 0; + u16 msdu_id = 0; + +- if ((ieee80211_is_action(hdr->frame_control) || +- ieee80211_is_deauth(hdr->frame_control) || +- ieee80211_is_disassoc(hdr->frame_control)) && +- ieee80211_has_protected(hdr->frame_control)) { +- skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ if (!is_eth) { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ ++ if ((ieee80211_is_action(hdr->frame_control) || ++ ieee80211_is_deauth(hdr->frame_control) || ++ ieee80211_is_disassoc(hdr->frame_control)) && ++ ieee80211_has_protected(hdr->frame_control)) { ++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ } + } + + data_len = msdu->len; +@@ -1407,7 +1410,6 @@ static int ath10k_htt_tx_32(struct ath10 + { + struct ath10k *ar = htt->ar; + struct device *dev = ar->dev; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); + struct ath10k_hif_sg_item sg_items[2]; +@@ -1439,15 +1441,19 @@ static int ath10k_htt_tx_32(struct ath10 + txbuf_paddr = htt->txbuf.paddr + + (sizeof(struct ath10k_htt_txbuf_32) * msdu_id); + +- if ((ieee80211_is_action(hdr->frame_control) || +- ieee80211_is_deauth(hdr->frame_control) || +- ieee80211_is_disassoc(hdr->frame_control)) && +- ieee80211_has_protected(hdr->frame_control)) { +- skb_put(msdu, IEEE80211_CCMP_MIC_LEN); +- } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && +- txmode == ATH10K_HW_TXRX_RAW && +- ieee80211_has_protected(hdr->frame_control)) { +- skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ if (!is_eth) { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ ++ if ((ieee80211_is_action(hdr->frame_control) || ++ ieee80211_is_deauth(hdr->frame_control) || ++ ieee80211_is_disassoc(hdr->frame_control)) && ++ ieee80211_has_protected(hdr->frame_control)) { ++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && ++ txmode == ATH10K_HW_TXRX_RAW && ++ ieee80211_has_protected(hdr->frame_control)) { ++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ } + } + + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, +@@ -1609,7 +1615,6 @@ static int ath10k_htt_tx_64(struct ath10 + { + struct ath10k *ar = htt->ar; + struct device *dev = ar->dev; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); + struct ath10k_hif_sg_item sg_items[2]; +@@ -1641,15 +1646,19 @@ static int ath10k_htt_tx_64(struct ath10 + txbuf_paddr = htt->txbuf.paddr + + (sizeof(struct ath10k_htt_txbuf_64) * msdu_id); + +- if ((ieee80211_is_action(hdr->frame_control) || +- ieee80211_is_deauth(hdr->frame_control) || +- ieee80211_is_disassoc(hdr->frame_control)) && +- ieee80211_has_protected(hdr->frame_control)) { +- skb_put(msdu, IEEE80211_CCMP_MIC_LEN); +- } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && +- txmode == ATH10K_HW_TXRX_RAW && +- ieee80211_has_protected(hdr->frame_control)) { +- skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ if (!is_eth) { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ ++ if ((ieee80211_is_action(hdr->frame_control) || ++ ieee80211_is_deauth(hdr->frame_control) || ++ ieee80211_is_disassoc(hdr->frame_control)) && ++ ieee80211_has_protected(hdr->frame_control)) { ++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && ++ txmode == ATH10K_HW_TXRX_RAW && ++ ieee80211_has_protected(hdr->frame_control)) { ++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN); ++ } + } + + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, diff --git a/package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch b/package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch new file mode 100644 index 000000000..cb02dede6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch @@ -0,0 +1,194 @@ +From af6d8265c47e46881b80c6b073f53c8c4af52d28 Mon Sep 17 00:00:00 2001 +From: Sergey Ryazanov +Date: Mon, 16 May 2022 13:26:00 +0300 +Subject: ath10k: add encapsulation offloading support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Frame encapsulation from Ethernet into the IEEE 802.11 frame format +takes a considerable host CPU time on the xmit path. The firmware is +able to do this operation for us, so enable encapsulation offloading for +AP and Sta interface types to improve overall system performance. + +The driver is almost ready for encapsulation offloading support. There +are only a few places where the driver assumes the frame format is IEEE +802.11 that need to be fixed. + +Encapsulation offloading is currently disabled by default and the driver +utilizes mac80211 encapsulation support. To activate offloading, the +frame_mode=2 parameter should be passed during module loading. + +On a QCA9563+QCA9888-based access point in bridged mode, encapsulation +offloading increases TCP 16-streams DL throughput from 365 to 396 mbps +(+8%) and UDP DL throughput from 436 to 483 mbps (+11%). + +Tested-on: QCA9888 hw2.0 PCI 10.4-3.9.0.2-00131 +Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00157-QCARMSWPZ-1 +Signed-off-by: Sergey Ryazanov +Tested-by: Oldřich Jedlička # TP-Link Archer C7 v4 & v5 (QCA9563 + QCA9880) +Tested-by: Edward Matijevic # TP-Link Archer C2600 (IPQ8064 + QCA9980 10.4.1.00030-1) +Tested-by: Edward Matijevic # QCA9377 PCI in Sta mode +Tested-by: Zhijun You # NETGEAR R7800 (QCA9984 10.4-3.9.0.2-00159) +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220516032519.29831-5-ryazanov.s.a@gmail.com +--- + drivers/net/wireless/ath/ath10k/core.c | 2 +- + drivers/net/wireless/ath/ath10k/mac.c | 67 +++++++++++++++++++++++++++------- + 2 files changed, 55 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -54,7 +54,7 @@ MODULE_PARM_DESC(uart_print, "Uart targe + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); + MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); + MODULE_PARM_DESC(frame_mode, +- "Datapath frame mode (0: raw, 1: native wifi (default))"); ++ "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)"); + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -3710,6 +3710,9 @@ ath10k_mac_tx_h_get_txmode(struct ath10k + const struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); + __le16 fc = hdr->frame_control; + ++ if (IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ++ return ATH10K_HW_TXRX_ETHERNET; ++ + if (!vif || vif->type == NL80211_IFTYPE_MONITOR) + return ATH10K_HW_TXRX_RAW; + +@@ -3870,6 +3873,12 @@ static void ath10k_mac_tx_h_fill_cb(stru + bool noack = false; + + cb->flags = 0; ++ ++ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { ++ cb->flags |= ATH10K_SKB_F_QOS; /* Assume data frames are QoS */ ++ goto finish_cb_fill; ++ } ++ + if (!ath10k_tx_h_use_hwcrypto(vif, skb)) + cb->flags |= ATH10K_SKB_F_NO_HWCRYPT; + +@@ -3908,6 +3917,7 @@ static void ath10k_mac_tx_h_fill_cb(stru + cb->flags |= ATH10K_SKB_F_RAW_TX; + } + ++finish_cb_fill: + cb->vif = vif; + cb->txq = txq; + cb->airtime_est = airtime; +@@ -4031,7 +4041,11 @@ static int ath10k_mac_tx(struct ath10k * + ath10k_tx_h_seq_no(vif, skb); + break; + case ATH10K_HW_TXRX_ETHERNET: +- ath10k_tx_h_8023(skb); ++ /* Convert 802.11->802.3 header only if the frame was erlier ++ * encapsulated to 802.11 by mac80211. Otherwise pass it as is. ++ */ ++ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) ++ ath10k_tx_h_8023(skb); + break; + case ATH10K_HW_TXRX_RAW: + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags) && +@@ -4643,12 +4657,10 @@ static void ath10k_mac_op_tx(struct ieee + struct ieee80211_vif *vif = info->control.vif; + struct ieee80211_sta *sta = control->sta; + struct ieee80211_txq *txq = NULL; +- struct ieee80211_hdr *hdr = (void *)skb->data; + enum ath10k_hw_txrx_mode txmode; + enum ath10k_mac_tx_path txpath; + bool is_htt; + bool is_mgmt; +- bool is_presp; + int ret; + u16 airtime; + +@@ -4662,8 +4674,14 @@ static void ath10k_mac_op_tx(struct ieee + is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT); + + if (is_htt) { ++ bool is_presp = false; ++ + spin_lock_bh(&ar->htt.tx_lock); +- is_presp = ieee80211_is_probe_resp(hdr->frame_control); ++ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) { ++ struct ieee80211_hdr *hdr = (void *)skb->data; ++ ++ is_presp = ieee80211_is_probe_resp(hdr->frame_control); ++ } + + ret = ath10k_htt_tx_inc_pending(htt); + if (ret) { +@@ -5447,6 +5465,30 @@ static int ath10k_mac_set_txbf_conf(stru + ar->wmi.vdev_param->txbf, value); + } + ++static void ath10k_update_vif_offload(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif) ++{ ++ struct ath10k_vif *arvif = (void *)vif->drv_priv; ++ struct ath10k *ar = hw->priv; ++ u32 vdev_param; ++ int ret; ++ ++ if (ath10k_frame_mode != ATH10K_HW_TXRX_ETHERNET || ++ ar->wmi.vdev_param->tx_encap_type == WMI_VDEV_PARAM_UNSUPPORTED || ++ (vif->type != NL80211_IFTYPE_STATION && ++ vif->type != NL80211_IFTYPE_AP)) ++ vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ ++ vdev_param = ar->wmi.vdev_param->tx_encap_type; ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ ATH10K_HW_TXRX_NATIVE_WIFI); ++ /* 10.X firmware does not support this VDEV parameter. Do not warn */ ++ if (ret && ret != -EOPNOTSUPP) { ++ ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n", ++ arvif->vdev_id, ret); ++ } ++} ++ + /* + * TODO: + * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, +@@ -5656,15 +5698,7 @@ static int ath10k_add_interface(struct i + + arvif->def_wep_key_idx = -1; + +- vdev_param = ar->wmi.vdev_param->tx_encap_type; +- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, +- ATH10K_HW_TXRX_NATIVE_WIFI); +- /* 10.X firmware does not support this VDEV parameter. Do not warn */ +- if (ret && ret != -EOPNOTSUPP) { +- ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n", +- arvif->vdev_id, ret); +- goto err_vdev_delete; +- } ++ ath10k_update_vif_offload(hw, vif); + + /* Configuring number of spatial stream for monitor interface is causing + * target assert in qca9888 and qca6174. +@@ -9352,6 +9386,7 @@ static const struct ieee80211_ops ath10k + .stop = ath10k_stop, + .config = ath10k_config, + .add_interface = ath10k_add_interface, ++ .update_vif_offload = ath10k_update_vif_offload, + .remove_interface = ath10k_remove_interface, + .configure_filter = ath10k_configure_filter, + .bss_info_changed = ath10k_bss_info_changed, +@@ -10021,6 +10056,12 @@ int ath10k_mac_register(struct ath10k *a + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) + ieee80211_hw_set(ar->hw, SUPPORTS_TDLS_BUFFER_STA); + ++ if (ath10k_frame_mode == ATH10K_HW_TXRX_ETHERNET) { ++ if (ar->wmi.vdev_param->tx_encap_type != ++ WMI_VDEV_PARAM_UNSUPPORTED) ++ ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ } ++ + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + ar->hw->wiphy->max_remain_on_channel_duration = 5000; diff --git a/package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch b/package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch new file mode 100644 index 000000000..7ef418e50 --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch @@ -0,0 +1,65 @@ +From f2a7064a78b22f2b68b9fcbc8a6f4c5e61c5ba64 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sun, 10 Oct 2021 00:17:11 +0200 +Subject: [PATCH] ath10k: support bus and device specific API 1 BDF selection + +Some ath10k IPQ40xx devices like the MikroTik hAP ac2 and ac3 require the +BDF-s to be extracted from the device storage instead of shipping packaged +API 2 BDF-s. + +This is required as MikroTik has started shipping boards that require BDF-s +to be updated, as otherwise their WLAN performance really suffers. +This is however impossible as the devices that require this are release +under the same revision and its not possible to differentiate them from +devices using the older BDF-s. + +In OpenWrt we are extracting the calibration data during runtime and we are +able to extract the BDF-s in the same manner, however we cannot package the +BDF-s to API 2 format on the fly and can only use API 1 to provide BDF-s on +the fly. +This is an issue as the ath10k driver explicitly looks only for the +board.bin file and not for something like board-bus-device.bin like it does +for pre-cal data. +Due to this we have no way of providing correct BDF-s on the fly, so lets +extend the ath10k driver to first look for BDF-s in the +board-bus-device.bin format, for example: board-ahb-a800000.wifi.bin +If that fails, look for the default board file name as defined previously. + +Signed-off-by: Robert Marko +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211009221711.2315352-1-robimarko@gmail.com +--- + drivers/net/wireless/ath/ath10k/core.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -1202,6 +1202,7 @@ success: + static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) + { + const struct firmware *fw; ++ char boardname[100]; + + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + if (!ar->hw_params.fw.board) { +@@ -1209,9 +1210,19 @@ static int ath10k_core_fetch_board_data_ + return -EINVAL; + } + ++ scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin", ++ ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); ++ + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, +- ar->hw_params.fw.board); ++ boardname); ++ if (IS_ERR(ar->normal_mode_fw.board)) { ++ fw = ath10k_fetch_fw_file(ar, ++ ar->hw_params.fw.dir, ++ ar->hw_params.fw.board); ++ ar->normal_mode_fw.board = fw; ++ } ++ + if (IS_ERR(ar->normal_mode_fw.board)) + return PTR_ERR(ar->normal_mode_fw.board); + diff --git a/package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch b/package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch new file mode 100644 index 000000000..c7a00b7e4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch @@ -0,0 +1,162 @@ +From e2333703373e8b81294da5d1c73c30154f75b082 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Fri, 15 Oct 2021 18:56:33 +0200 +Subject: [PATCH] ath10k: fetch (pre-)calibration data via nvmem subsystem + +On most embedded ath10k devices (like range extenders, +routers, accesspoints, ...) the calibration data is +stored in a easily accessible MTD partitions named +"ART", "caldata", "calibration", etc... + +Since commit 4b361cfa8624 ("mtd: core: add OTP nvmem provider support"): +MTD partitions and portions of them can be specified +as potential nvmem-cells which are accessible through +the nvmem subsystem. + +This feature - together with an nvmem cell definition either +in the platform data or via device-tree allows drivers to get +the (pre-)calibration data which is required for initializing +the WIFI. + +Tested with Netgear EX6150v2 (IPQ4018) + +Cc: Robert Marko +Cc: Thibaut Varene +Signed-off-by: Christian Lamparter +--- +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + + #include "core.h" +@@ -955,7 +956,8 @@ static int ath10k_core_get_board_id_from + } + + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || +- ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) ++ ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE || ++ ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM) + bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; + else + bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; +@@ -1757,7 +1759,8 @@ static int ath10k_download_and_run_otp(s + + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || +- ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) ++ ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE || ++ ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); +@@ -1884,6 +1887,39 @@ out_free: + return ret; + } + ++static int ath10k_download_cal_nvmem(struct ath10k *ar, const char *cell_name) ++{ ++ struct nvmem_cell *cell; ++ void *buf; ++ size_t len; ++ int ret; ++ ++ cell = devm_nvmem_cell_get(ar->dev, cell_name); ++ if (IS_ERR(cell)) { ++ ret = PTR_ERR(cell); ++ return ret; ++ } ++ ++ buf = nvmem_cell_read(cell, &len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ ++ if (ar->hw_params.cal_data_len != len) { ++ kfree(buf); ++ ath10k_warn(ar, "invalid calibration data length in nvmem-cell '%s': %zu != %u\n", ++ cell_name, len, ar->hw_params.cal_data_len); ++ return -EMSGSIZE; ++ } ++ ++ ret = ath10k_download_board_data(ar, buf, len); ++ kfree(buf); ++ if (ret) ++ ath10k_warn(ar, "failed to download calibration data from nvmem-cell '%s': %d\n", ++ cell_name, ret); ++ ++ return ret; ++} ++ + int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name, + struct ath10k_fw_file *fw_file) + { +@@ -2118,6 +2154,18 @@ static int ath10k_core_pre_cal_download( + { + int ret; + ++ ret = ath10k_download_cal_nvmem(ar, "pre-calibration"); ++ if (ret == 0) { ++ ar->cal_mode = ATH10K_PRE_CAL_MODE_NVMEM; ++ goto success; ++ } else if (ret == -EPROBE_DEFER) { ++ return ret; ++ } ++ ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot did not find a pre-calibration nvmem-cell, try file next: %d\n", ++ ret); ++ + ret = ath10k_download_cal_file(ar, ar->pre_cal_file); + if (ret == 0) { + ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE; +@@ -2184,6 +2232,18 @@ static int ath10k_download_cal_data(stru + "pre cal download procedure failed, try cal file: %d\n", + ret); + ++ ret = ath10k_download_cal_nvmem(ar, "calibration"); ++ if (ret == 0) { ++ ar->cal_mode = ATH10K_CAL_MODE_NVMEM; ++ goto done; ++ } else if (ret == -EPROBE_DEFER) { ++ return ret; ++ } ++ ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "boot did not find a calibration nvmem-cell, try file next: %d\n", ++ ret); ++ + ret = ath10k_download_cal_file(ar, ar->cal_file); + if (ret == 0) { + ar->cal_mode = ATH10K_CAL_MODE_FILE; +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -877,8 +877,10 @@ enum ath10k_cal_mode { + ATH10K_CAL_MODE_FILE, + ATH10K_CAL_MODE_OTP, + ATH10K_CAL_MODE_DT, ++ ATH10K_CAL_MODE_NVMEM, + ATH10K_PRE_CAL_MODE_FILE, + ATH10K_PRE_CAL_MODE_DT, ++ ATH10K_PRE_CAL_MODE_NVMEM, + ATH10K_CAL_MODE_EEPROM, + }; + +@@ -898,10 +900,14 @@ static inline const char *ath10k_cal_mod + return "otp"; + case ATH10K_CAL_MODE_DT: + return "dt"; ++ case ATH10K_CAL_MODE_NVMEM: ++ return "nvmem"; + case ATH10K_PRE_CAL_MODE_FILE: + return "pre-cal-file"; + case ATH10K_PRE_CAL_MODE_DT: + return "pre-cal-dt"; ++ case ATH10K_PRE_CAL_MODE_NVMEM: ++ return "pre-cal-nvmem"; + case ATH10K_CAL_MODE_EEPROM: + return "eeprom"; + } diff --git a/package/kernel/mac80211/patches/ath10k/921-ath10k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/ath10k/921-ath10k_init_devices_synchronously.patch index 781983568..e47fb012f 100644 --- a/package/kernel/mac80211/patches/ath10k/921-ath10k_init_devices_synchronously.patch +++ b/package/kernel/mac80211/patches/ath10k/921-ath10k_init_devices_synchronously.patch @@ -14,7 +14,7 @@ Signed-off-by: Sven Eckelmann --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -3500,6 +3500,16 @@ int ath10k_core_register(struct ath10k * +@@ -3443,6 +3443,16 @@ int ath10k_core_register(struct ath10k * queue_work(ar->workqueue, &ar->register_work); diff --git a/package/kernel/mac80211/patches/ath10k/930-ath10k_add_tpt_led_trigger.patch b/package/kernel/mac80211/patches/ath10k/930-ath10k_add_tpt_led_trigger.patch index e8beed17e..9cbc52b88 100644 --- a/package/kernel/mac80211/patches/ath10k/930-ath10k_add_tpt_led_trigger.patch +++ b/package/kernel/mac80211/patches/ath10k/930-ath10k_add_tpt_led_trigger.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c -@@ -9909,6 +9909,21 @@ static int ath10k_mac_init_rd(struct ath +@@ -9878,6 +9878,21 @@ static int ath10k_mac_init_rd(struct ath return 0; } @@ -22,7 +22,7 @@ int ath10k_mac_register(struct ath10k *ar) { static const u32 cipher_suites[] = { -@@ -10267,6 +10282,12 @@ int ath10k_mac_register(struct ath10k *a +@@ -10236,6 +10251,12 @@ int ath10k_mac_register(struct ath10k *a ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; diff --git a/package/kernel/mac80211/patches/ath10k/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch b/package/kernel/mac80211/patches/ath10k/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch index 823696658..f1e7f5ecc 100644 --- a/package/kernel/mac80211/patches/ath10k/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch +++ b/package/kernel/mac80211/patches/ath10k/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch @@ -114,7 +114,7 @@ v13: ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o --- a/local-symbols +++ b/local-symbols -@@ -170,6 +170,7 @@ ATH10K_DEBUG= +@@ -143,6 +143,7 @@ ATH10K_DEBUG= ATH10K_DEBUGFS= ATH10K_SPECTRAL= ATH10K_THERMAL= @@ -140,7 +140,7 @@ v13: .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, -@@ -144,6 +146,7 @@ static const struct ath10k_hw_params ath +@@ -138,6 +140,7 @@ static const struct ath10k_hw_params ath .dev_id = QCA9887_1_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca9887 hw1.0", @@ -148,7 +148,7 @@ v13: .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, -@@ -379,6 +382,7 @@ static const struct ath10k_hw_params ath +@@ -355,6 +358,7 @@ static const struct ath10k_hw_params ath .dev_id = QCA99X0_2_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca99x0 hw2.0", @@ -156,7 +156,7 @@ v13: .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .otp_exe_param = 0x00000700, -@@ -424,6 +428,7 @@ static const struct ath10k_hw_params ath +@@ -397,6 +401,7 @@ static const struct ath10k_hw_params ath .dev_id = QCA9984_1_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca9984/qca9994 hw1.0", @@ -164,7 +164,7 @@ v13: .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, -@@ -476,6 +481,7 @@ static const struct ath10k_hw_params ath +@@ -446,6 +451,7 @@ static const struct ath10k_hw_params ath .dev_id = QCA9888_2_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca9888 hw2.0", @@ -172,7 +172,7 @@ v13: .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, -@@ -3215,6 +3221,10 @@ int ath10k_core_start(struct ath10k *ar, +@@ -3158,6 +3164,10 @@ int ath10k_core_start(struct ath10k *ar, goto err_hif_stop; } @@ -183,7 +183,7 @@ v13: return 0; err_hif_stop: -@@ -3473,9 +3483,18 @@ static void ath10k_core_register_work(st +@@ -3416,9 +3426,18 @@ static void ath10k_core_register_work(st goto err_spectral_destroy; } @@ -202,7 +202,7 @@ v13: err_spectral_destroy: ath10k_spectral_destroy(ar); err_debug_destroy: -@@ -3521,6 +3540,8 @@ void ath10k_core_unregister(struct ath10 +@@ -3464,6 +3483,8 @@ void ath10k_core_unregister(struct ath10 if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) return; @@ -221,7 +221,7 @@ v13: #include "htt.h" #include "htc.h" -@@ -1253,6 +1254,13 @@ struct ath10k { +@@ -1256,6 +1257,13 @@ struct ath10k { } testmode; struct { @@ -237,7 +237,7 @@ v13: u32 fw_crash_counter; --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h -@@ -519,6 +519,7 @@ struct ath10k_hw_params { +@@ -517,6 +517,7 @@ struct ath10k_hw_params { const char *name; u32 patch_load_addr; int uart_pin; diff --git a/package/kernel/mac80211/patches/ath10k/975-ath10k-use-tpt-trigger-by-default.patch b/package/kernel/mac80211/patches/ath10k/975-ath10k-use-tpt-trigger-by-default.patch index 4c1f9aa81..4c1b73b1c 100644 --- a/package/kernel/mac80211/patches/ath10k/975-ath10k-use-tpt-trigger-by-default.patch +++ b/package/kernel/mac80211/patches/ath10k/975-ath10k-use-tpt-trigger-by-default.patch @@ -16,7 +16,7 @@ Signed-off-by: Mathias Kresin --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h -@@ -1309,6 +1309,10 @@ struct ath10k { +@@ -1312,6 +1312,10 @@ struct ath10k { s32 tx_power_2g_limit; s32 tx_power_5g_limit; @@ -42,7 +42,7 @@ Signed-off-by: Mathias Kresin if (ret) --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c -@@ -10284,7 +10284,7 @@ int ath10k_mac_register(struct ath10k *a +@@ -10253,7 +10253,7 @@ int ath10k_mac_register(struct ath10k *a ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; #ifdef CPTCFG_MAC80211_LEDS diff --git a/package/kernel/mac80211/patches/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch b/package/kernel/mac80211/patches/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch index 3626debf1..a45addf11 100644 --- a/package/kernel/mac80211/patches/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch +++ b/package/kernel/mac80211/patches/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch @@ -28,7 +28,7 @@ Forwarded: no --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c -@@ -1028,6 +1028,40 @@ static inline int ath10k_vdev_setup_sync +@@ -1021,6 +1021,40 @@ static inline int ath10k_vdev_setup_sync return ar->last_wmi_vdev_start_status; } @@ -69,7 +69,7 @@ Forwarded: no static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = NULL; -@@ -1060,7 +1094,8 @@ static int ath10k_monitor_vdev_start(str +@@ -1053,7 +1087,8 @@ static int ath10k_monitor_vdev_start(str arg.channel.min_power = 0; arg.channel.max_power = channel->max_power * 2; arg.channel.max_reg_power = channel->max_reg_power * 2; @@ -79,7 +79,7 @@ Forwarded: no reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_delete_done); -@@ -1506,7 +1541,8 @@ static int ath10k_vdev_start_restart(str +@@ -1499,7 +1534,8 @@ static int ath10k_vdev_start_restart(str arg.channel.min_power = 0; arg.channel.max_power = chandef->chan->max_power * 2; arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; @@ -89,7 +89,7 @@ Forwarded: no if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; -@@ -3437,7 +3473,8 @@ static int ath10k_update_channel_list(st +@@ -3427,7 +3463,8 @@ static int ath10k_update_channel_list(st ch->min_power = 0; ch->max_power = channel->max_power * 2; ch->max_reg_power = channel->max_reg_power * 2; diff --git a/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch b/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch index d7187bad8..80da07de8 100644 --- a/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch +++ b/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch @@ -26,9 +26,9 @@ Signed-off-by: Ansuel Smith #include #include #include -@@ -3391,6 +3392,8 @@ static int ath10k_core_probe_fw(struct a +@@ -3334,6 +3335,8 @@ static int ath10k_core_probe_fw(struct a - device_get_mac_address(ar->dev, ar->mac_addr); + device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr)); + of_get_mac_address(ar->dev->of_node, ar->mac_addr); + diff --git a/package/kernel/mac80211/patches/ath10k/991-ath10k-5.19.patch b/package/kernel/mac80211/patches/ath10k/991-ath10k-5.19.patch new file mode 100644 index 000000000..e5270799d --- /dev/null +++ b/package/kernel/mac80211/patches/ath10k/991-ath10k-5.19.patch @@ -0,0 +1,14 @@ +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -3333,7 +3333,11 @@ static int ath10k_core_probe_fw(struct a + ath10k_debug_print_board_info(ar); + } + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr)); ++#else ++ device_get_mac_address(ar->dev, ar->mac_addr); ++#endif + + of_get_mac_address(ar->dev->of_node, ar->mac_addr); + diff --git a/package/kernel/mac80211/patches/ath11k/0001-ath11k-fix-4-addr-tx-failure-for-AP-and-STA-modes.patch b/package/kernel/mac80211/patches/ath11k/0001-ath11k-fix-4-addr-tx-failure-for-AP-and-STA-modes.patch new file mode 100644 index 000000000..69e6b43ee --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0001-ath11k-fix-4-addr-tx-failure-for-AP-and-STA-modes.patch @@ -0,0 +1,151 @@ +From 34c67dc366419e06129dad0f32f521842bdff9bc Mon Sep 17 00:00:00 2001 +From: Sathishkumar Muruganandam +Date: Wed, 21 Jul 2021 00:31:46 +0300 +Subject: [PATCH] ath11k: fix 4-addr tx failure for AP and STA modes + +Ath11k FW requires peer parameter WMI_PEER_USE_4ADDR to be set for +4-addr peers allowing 4-address frame transmission to those peers. + +Add ath11k driver callback for sta_set_4addr() to queue new workq +set_4addr_wk only once based on new boolean, use_4addr_set. + +sta_set_4addr() will be called during 4-addr STA association cases +applicable for both AP and STA modes. + +In ath11k_sta_set_4addr_wk(), + +AP mode: + WMI_PEER_USE_4ADDR will be set for the corresponding + associated 4-addr STA(s) + +STA mode: + WMI_PEER_USE_4ADDR will be set for the AP to which the + 4-addr STA got associated. + +Tested-on: IPQ8074 WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720213147.90042-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 3 ++ + drivers/net/wireless/ath/ath11k/mac.c | 48 ++++++++++++++++++++++++-- + 2 files changed, 49 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -368,6 +368,7 @@ struct ath11k_sta { + enum hal_pn_type pn_type; + + struct work_struct update_wk; ++ struct work_struct set_4addr_wk; + struct rate_info txrate; + struct rate_info last_txrate; + u64 rx_duration; +@@ -380,6 +381,8 @@ struct ath11k_sta { + /* protected by conf_mutex */ + bool aggr_mode; + #endif ++ ++ bool use_4addr_set; + }; + + #define ATH11K_MIN_5G_FREQ 4150 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3161,6 +3161,31 @@ static void ath11k_sta_rc_update_wk(stru + mutex_unlock(&ar->conf_mutex); + } + ++static void ath11k_sta_set_4addr_wk(struct work_struct *wk) ++{ ++ struct ath11k *ar; ++ struct ath11k_vif *arvif; ++ struct ath11k_sta *arsta; ++ struct ieee80211_sta *sta; ++ int ret = 0; ++ ++ arsta = container_of(wk, struct ath11k_sta, set_4addr_wk); ++ sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); ++ arvif = arsta->arvif; ++ ar = arvif->ar; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "setting USE_4ADDR for peer %pM\n", sta->addr); ++ ++ ret = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_USE_4ADDR, 1); ++ ++ if (ret) ++ ath11k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n", ++ sta->addr, ret); ++} ++ + static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif, + struct ieee80211_sta *sta) + { +@@ -3240,11 +3265,13 @@ static int ath11k_mac_station_add(struct + } + + if (ieee80211_vif_is_mesh(vif)) { ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "setting USE_4ADDR for mesh STA %pM\n", sta->addr); + ret = ath11k_wmi_set_peer_param(ar, sta->addr, + arvif->vdev_id, + WMI_PEER_USE_4ADDR, 1); + if (ret) { +- ath11k_warn(ab, "failed to STA %pM 4addr capability: %d\n", ++ ath11k_warn(ab, "failed to set mesh STA %pM 4addr capability: %d\n", + sta->addr, ret); + goto free_tx_stats; + } +@@ -3297,8 +3324,10 @@ static int ath11k_mac_op_sta_state(struc + + /* cancel must be done outside the mutex to avoid deadlock */ + if ((old_state == IEEE80211_STA_NONE && +- new_state == IEEE80211_STA_NOTEXIST)) ++ new_state == IEEE80211_STA_NOTEXIST)) { + cancel_work_sync(&arsta->update_wk); ++ cancel_work_sync(&arsta->set_4addr_wk); ++ } + + mutex_lock(&ar->conf_mutex); + +@@ -3307,6 +3336,7 @@ static int ath11k_mac_op_sta_state(struc + memset(arsta, 0, sizeof(*arsta)); + arsta->arvif = arvif; + INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk); ++ INIT_WORK(&arsta->set_4addr_wk, ath11k_sta_set_4addr_wk); + + ret = ath11k_mac_station_add(ar, vif, sta); + if (ret) +@@ -3401,6 +3431,19 @@ out: + return ret; + } + ++static void ath11k_mac_op_sta_set_4addr(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, bool enabled) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; ++ ++ if (enabled && !arsta->use_4addr_set) { ++ ieee80211_queue_work(ar->hw, &arsta->set_4addr_wk); ++ arsta->use_4addr_set = true; ++ } ++} ++ + static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -6190,6 +6233,7 @@ static const struct ieee80211_ops ath11k + .cancel_hw_scan = ath11k_mac_op_cancel_hw_scan, + .set_key = ath11k_mac_op_set_key, + .sta_state = ath11k_mac_op_sta_state, ++ .sta_set_4addr = ath11k_mac_op_sta_set_4addr, + .sta_set_txpwr = ath11k_mac_op_sta_set_txpwr, + .sta_rc_update = ath11k_mac_op_sta_rc_update, + .conf_tx = ath11k_mac_op_conf_tx, diff --git a/package/kernel/mac80211/patches/ath11k/0001-wifi-ath11k-stop-tx-queues-immediately-upon-firmware.patch b/package/kernel/mac80211/patches/ath11k/0001-wifi-ath11k-stop-tx-queues-immediately-upon-firmware.patch deleted file mode 100644 index ae8920c62..000000000 --- a/package/kernel/mac80211/patches/ath11k/0001-wifi-ath11k-stop-tx-queues-immediately-upon-firmware.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 81e60b2dfb2744ab6642c4aa62534b4f711fdc5d Mon Sep 17 00:00:00 2001 -From: Aditya Kumar Singh -Date: Tue, 27 Sep 2022 09:18:54 +0300 -Subject: [PATCH] wifi: ath11k: stop tx queues immediately upon firmware exit - -Currently, recovery flag is set immediately upon firmware -exit but tx queues are stopped once firmware arrives back -and is ready which is during ath11k_core_restart. Once -ieee80211 hw restart is completed, tx queues are resumed. -If during the time delta between firmware exit and firmware -ready, mac80211 send packets, currently ath11k will drop it -since recovery flag will be set. But warning prints will -come - - "ath11k c000000.wifi: failed to transmit frame -108" - -If more tx packets are there, this could lead to flooding -of above print. - -However, actually tx queues should be stopped immediately -when firmware leaves. This will prevent packets to get -dropped when firmware is recovering. - -Add fix to stop tx queues immediately after firmware exit. - -Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 - -Signed-off-by: Aditya Kumar Singh -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20220923170235.18873-1-quic_adisi@quicinc.com ---- - drivers/net/wireless/ath/ath11k/core.c | 5 +---- - drivers/net/wireless/ath/ath11k/core.h | 1 + - drivers/net/wireless/ath/ath11k/qmi.c | 3 +++ - 3 files changed, 5 insertions(+), 4 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/core.c -+++ b/drivers/net/wireless/ath/ath11k/core.c -@@ -1641,7 +1641,7 @@ static void ath11k_update_11d(struct wor - } - } - --static void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab) -+void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab) - { - struct ath11k *ar; - struct ath11k_pdev *pdev; -@@ -1730,9 +1730,6 @@ static void ath11k_core_restart(struct w - struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); - int ret; - -- if (!ab->is_reset) -- ath11k_core_pre_reconfigure_recovery(ab); -- - ret = ath11k_core_reconfigure_on_crash(ab); - if (ret) { - ath11k_err(ab, "failed to reconfigure driver on crash recovery\n"); ---- a/drivers/net/wireless/ath/ath11k/core.h -+++ b/drivers/net/wireless/ath/ath11k/core.h -@@ -1157,6 +1157,7 @@ int ath11k_core_check_smbios(struct ath1 - void ath11k_core_halt(struct ath11k *ar); - int ath11k_core_resume(struct ath11k_base *ab); - int ath11k_core_suspend(struct ath11k_base *ab); -+void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab); - - const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, - const char *filename); ---- a/drivers/net/wireless/ath/ath11k/qmi.c -+++ b/drivers/net/wireless/ath/ath11k/qmi.c -@@ -3158,6 +3158,9 @@ static void ath11k_qmi_driver_event_work - case ATH11K_QMI_EVENT_SERVER_EXIT: - set_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags); - set_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); -+ -+ if (!ab->is_reset) -+ ath11k_core_pre_reconfigure_recovery(ab); - break; - case ATH11K_QMI_EVENT_REQUEST_MEM: - ret = ath11k_qmi_event_mem_request(qmi); diff --git a/package/kernel/mac80211/patches/ath11k/0002-ath11k-fix-4addr-multicast-packet-tx.patch b/package/kernel/mac80211/patches/ath11k/0002-ath11k-fix-4addr-multicast-packet-tx.patch new file mode 100644 index 000000000..dba737ef7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0002-ath11k-fix-4addr-multicast-packet-tx.patch @@ -0,0 +1,123 @@ +From e20cfa3b62aeb1b5fc5ffa86a007af97f9954767 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 21 Jul 2021 00:31:47 +0300 +Subject: [PATCH] ath11k: fix 4addr multicast packet tx + +In 4addr, AP wired backbone to STA wired backbone ping fails due to ARP +request not getting answered. Here 4addr ARP multicast packet is sent in +3addr, so that 4addr STA not honouring the 3addr ARP multicast packet. +Fix this issue by sending out multicast packet in 4addr format, firmware +expects peer meta flag instead of vdev meta flag in Tx descriptor. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01641-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720213147.90042-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/dp_tx.c | 12 ++++++++++-- + drivers/net/wireless/ath/ath11k/dp_tx.h | 2 +- + drivers/net/wireless/ath/ath11k/mac.c | 6 +++++- + drivers/net/wireless/ath/ath11k/peer.c | 11 +++++++++++ + 5 files changed, 28 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -383,6 +383,7 @@ struct ath11k_sta { + #endif + + bool use_4addr_set; ++ u16 tcl_metadata; + }; + + #define ATH11K_MIN_5G_FREQ 4150 +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -78,7 +78,7 @@ enum hal_encrypt_type ath11k_dp_tx_get_e + } + + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, +- struct sk_buff *skb) ++ struct ath11k_sta *arsta, struct sk_buff *skb) + { + struct ath11k_base *ab = ar->ab; + struct ath11k_dp *dp = &ab->dp; +@@ -145,7 +145,15 @@ tcl_ring_sel: + FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) | + FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id); + ti.encap_type = ath11k_dp_tx_get_encap_type(arvif, skb); +- ti.meta_data_flags = arvif->tcl_metadata; ++ ++ if (ieee80211_has_a4(hdr->frame_control) && ++ is_multicast_ether_addr(hdr->addr3) && arsta && ++ arsta->use_4addr_set) { ++ ti.meta_data_flags = arsta->tcl_metadata; ++ ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TO_FW, 1); ++ } else { ++ ti.meta_data_flags = arvif->tcl_metadata; ++ } + + if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { + if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { +--- a/drivers/net/wireless/ath/ath11k/dp_tx.h ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.h +@@ -17,7 +17,7 @@ struct ath11k_dp_htt_wbm_tx_status { + + int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab); + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, +- struct sk_buff *skb); ++ struct ath11k_sta *arsta, struct sk_buff *skb); + void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id); + int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid, + enum hal_reo_cmd_type type, +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4366,6 +4366,7 @@ static void ath11k_mac_op_tx(struct ieee + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_key_conf *key = info->control.hw_key; ++ struct ath11k_sta *arsta = NULL; + u32 info_flags = info->flags; + bool is_prb_rsp; + int ret; +@@ -4391,7 +4392,10 @@ static void ath11k_mac_op_tx(struct ieee + return; + } + +- ret = ath11k_dp_tx(ar, arvif, skb); ++ if (control->sta) ++ arsta = (struct ath11k_sta *)control->sta->drv_priv; ++ ++ ret = ath11k_dp_tx(ar, arvif, arsta, skb); + if (ret) { + ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret); + ieee80211_free_txskb(ar->hw, skb); +--- a/drivers/net/wireless/ath/ath11k/peer.c ++++ b/drivers/net/wireless/ath/ath11k/peer.c +@@ -251,6 +251,7 @@ int ath11k_peer_create(struct ath11k *ar + struct ieee80211_sta *sta, struct peer_create_params *param) + { + struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; + int ret; + + lockdep_assert_held(&ar->conf_mutex); +@@ -319,6 +320,16 @@ int ath11k_peer_create(struct ath11k *ar + peer->sec_type = HAL_ENCRYPT_TYPE_OPEN; + peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN; + ++ if (sta) { ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) | ++ FIELD_PREP(HTT_TCL_META_DATA_PEER_ID, ++ peer->peer_id); ++ ++ /* set HTT extension valid bit to 0 by default */ ++ arsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT; ++ } ++ + ar->num_peers++; + + spin_unlock_bh(&ar->ab->base_lock); diff --git a/package/kernel/mac80211/patches/ath11k/0002-wifi-ath11k-Don-t-exit-on-wakeup-failure.patch b/package/kernel/mac80211/patches/ath11k/0002-wifi-ath11k-Don-t-exit-on-wakeup-failure.patch deleted file mode 100644 index 47385e045..000000000 --- a/package/kernel/mac80211/patches/ath11k/0002-wifi-ath11k-Don-t-exit-on-wakeup-failure.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 45d2e268369b0c768d5a644f319758bcfd370521 Mon Sep 17 00:00:00 2001 -From: Baochen Qiang -Date: Wed, 28 Sep 2022 09:51:40 +0800 -Subject: [PATCH] wifi: ath11k: Don't exit on wakeup failure - -Currently, ath11k_pcic_read() returns an error if wakeup() -fails, this makes firmware crash debug quite hard because we can -get nothing. - -Change to go ahead on wakeup failure, in that case we still may -get something valid to check. There should be no mislead due -to incorrect content because we are aware of the failure with the -log printed. - -Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 - -Signed-off-by: Baochen Qiang -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20220928015140.5431-1-quic_bqiang@quicinc.com ---- - drivers/net/wireless/ath/ath11k/pcic.c | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/pcic.c -+++ b/drivers/net/wireless/ath/ath11k/pcic.c -@@ -218,9 +218,16 @@ int ath11k_pcic_read(struct ath11k_base - if (wakeup_required && ab->pci.ops->wakeup) { - ret = ab->pci.ops->wakeup(ab); - if (ret) { -- ath11k_warn(ab, "failed to wakeup for read from 0x%x: %d\n", -- start, ret); -- return ret; -+ ath11k_warn(ab, -+ "wakeup failed, data may be invalid: %d", -+ ret); -+ /* Even though wakeup() failed, continue processing rather -+ * than returning because some parts of the data may still -+ * be valid and useful in some cases, e.g. could give us -+ * some clues on firmware crash. -+ * Mislead due to invalid data could be avoided because we -+ * are aware of the wakeup failure. -+ */ - } - } - diff --git a/package/kernel/mac80211/patches/ath11k/0003-ath11k-Rename-atf_config-to-flag1-in-target_resource.patch b/package/kernel/mac80211/patches/ath11k/0003-ath11k-Rename-atf_config-to-flag1-in-target_resource.patch new file mode 100644 index 000000000..30ea23cb6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0003-ath11k-Rename-atf_config-to-flag1-in-target_resource.patch @@ -0,0 +1,41 @@ +From 7e9fb2418a4c092a363d23e97973c9624150e5b2 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Wed, 21 Jul 2021 00:49:20 +0300 +Subject: [PATCH] ath11k: Rename atf_config to flag1 in target_resource_config + +The flag's purpose is not only meant for ATF configs. Rename atf_config +to flag1, so it can be used for future purposes. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01228-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720214922.118078-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + drivers/net/wireless/ath/ath11k/wmi.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -3497,7 +3497,7 @@ ath11k_wmi_copy_resource_config(struct w + wmi_cfg->bpf_instruction_size = tg_cfg->bpf_instruction_size; + wmi_cfg->max_bssid_rx_filters = tg_cfg->max_bssid_rx_filters; + wmi_cfg->use_pdev_id = tg_cfg->use_pdev_id; +- wmi_cfg->flag1 = tg_cfg->atf_config; ++ wmi_cfg->flag1 = tg_cfg->flag1; + wmi_cfg->peer_map_unmap_v2_support = tg_cfg->peer_map_unmap_v2_support; + wmi_cfg->sched_params = tg_cfg->sched_params; + wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5015,7 +5015,7 @@ struct target_resource_config { + u32 vo_minfree; + u32 rx_batchmode; + u32 tt_support; +- u32 atf_config; ++ u32 flag1; + u32 iphdr_pad_config; + u32 qwrap_config:16, + alloc_frag_desc_for_data_pkt:16; diff --git a/package/kernel/mac80211/patches/ath11k/0003-wifi-ath11k-fix-warning-in-dma_free_coherent-of-memo.patch b/package/kernel/mac80211/patches/ath11k/0003-wifi-ath11k-fix-warning-in-dma_free_coherent-of-memo.patch deleted file mode 100644 index 661f4bbfb..000000000 --- a/package/kernel/mac80211/patches/ath11k/0003-wifi-ath11k-fix-warning-in-dma_free_coherent-of-memo.patch +++ /dev/null @@ -1,139 +0,0 @@ -From f74878433d5ade360447da5d92e9c2e535780d80 Mon Sep 17 00:00:00 2001 -From: Wen Gong -Date: Wed, 28 Sep 2022 03:38:32 -0400 -Subject: [PATCH] wifi: ath11k: fix warning in dma_free_coherent() of memory - chunks while recovery - -Commit 26f3a021b37c ("ath11k: allocate smaller chunks of memory for -firmware") and commit f6f92968e1e5 ("ath11k: qmi: try to allocate a -big block of DMA memory first") change ath11k to allocate the memory -chunks for target twice while wlan load. It fails for the 1st time -because of large memory and then changed to allocate many small chunks -for the 2nd time sometimes as below log. - -1st time failed: -[10411.640620] ath11k_pci 0000:05:00.0: qmi firmware request memory request -[10411.640625] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 6881280 -[10411.640630] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 3784704 -[10411.640658] ath11k_pci 0000:05:00.0: qmi dma allocation failed (6881280 B type 1), will try later with small size -[10411.640671] ath11k_pci 0000:05:00.0: qmi delays mem_request 2 -[10411.640677] ath11k_pci 0000:05:00.0: qmi respond memory request delayed 1 -2nd time success: -[10411.642004] ath11k_pci 0000:05:00.0: qmi firmware request memory request -[10411.642008] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642012] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642014] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642016] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642018] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642020] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642022] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642024] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642027] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642029] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 -[10411.642031] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 458752 -[10411.642033] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 131072 -[10411.642035] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 524288 -[10411.642037] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 524288 -[10411.642039] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 524288 -[10411.642041] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 524288 -[10411.642043] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 524288 -[10411.642045] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 524288 -[10411.642047] ath11k_pci 0000:05:00.0: qmi mem seg type 4 size 491520 -[10411.642049] ath11k_pci 0000:05:00.0: qmi mem seg type 1 size 524288 - -And then commit 5962f370ce41 ("ath11k: Reuse the available memory after -firmware reload") skip the ath11k_qmi_free_resource() which frees the -memory chunks while recovery, after that, when run recovery test on -WCN6855, a warning happened every time as below and finally leads fail -for recovery. - -[ 159.570318] BUG: Bad page state in process kworker/u16:5 pfn:33300 -[ 159.570320] page:0000000096ffdbb9 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x33300 -[ 159.570324] flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff) -[ 159.570329] raw: 000fffffc0000000 0000000000000000 dead000000000122 0000000000000000 -[ 159.570332] raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000 -[ 159.570334] page dumped because: nonzero _refcount -[ 159.570440] firewire_ohci syscopyarea sysfillrect psmouse sdhci_pci ahci sysimgblt firewire_core fb_sys_fops libahci crc_itu_t cqhci drm sdhci e1000e wmi video -[ 159.570460] CPU: 2 PID: 217 Comm: kworker/u16:5 Kdump: loaded Tainted: G B 5.19.0-rc1-wt-ath+ #3 -[ 159.570465] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 -[ 159.570467] Workqueue: qmi_msg_handler qmi_data_ready_work [qmi_helpers] -[ 159.570475] Call Trace: -[ 159.570476] -[ 159.570478] dump_stack_lvl+0x49/0x5f -[ 159.570486] dump_stack+0x10/0x12 -[ 159.570493] bad_page+0xab/0xf0 -[ 159.570502] check_free_page_bad+0x66/0x70 -[ 159.570511] __free_pages_ok+0x530/0x9a0 -[ 159.570517] ? __dev_printk+0x58/0x6b -[ 159.570525] ? _dev_printk+0x56/0x72 -[ 159.570534] ? qmi_decode+0x119/0x470 [qmi_helpers] -[ 159.570543] __free_pages+0x91/0xd0 -[ 159.570548] dma_free_contiguous+0x50/0x60 -[ 159.570556] dma_direct_free+0xe5/0x140 -[ 159.570564] dma_free_attrs+0x35/0x50 -[ 159.570570] ath11k_qmi_msg_mem_request_cb+0x2ae/0x3c0 [ath11k] -[ 159.570620] qmi_invoke_handler+0xac/0xe0 [qmi_helpers] -[ 159.570630] qmi_handle_message+0x6d/0x180 [qmi_helpers] -[ 159.570643] qmi_data_ready_work+0x2ca/0x440 [qmi_helpers] -[ 159.570656] process_one_work+0x227/0x440 -[ 159.570667] worker_thread+0x31/0x3d0 -[ 159.570676] ? process_one_work+0x440/0x440 -[ 159.570685] kthread+0xfe/0x130 -[ 159.570692] ? kthread_complete_and_exit+0x20/0x20 -[ 159.570701] ret_from_fork+0x22/0x30 -[ 159.570712] - -The reason is because when wlan start to recovery, the type, size and -count is not same for the 1st and 2nd QMI_WLFW_REQUEST_MEM_IND message, -Then it leads the parameter size is not correct for the dma_free_coherent(). -For the chunk[1], the actual dma size is 524288 which allocate in the -2nd time of the initial wlan load phase, and the size which pass to -dma_free_coherent() is 3784704 which is got in the 1st time of recovery -phase, then warning above happened. - -Change to use prev_size of struct target_mem_chunk for the paramter of -dma_free_coherent() since prev_size is the real size of last load/recovery. -Also change to check both type and size of struct target_mem_chunk to -reuse the memory to avoid mismatch buffer size for target. Then the -warning disappear and recovery success. When the 1st QMI_WLFW_REQUEST_MEM_IND -for recovery arrived, the trunk[0] is freed in ath11k_qmi_alloc_target_mem_chunk() -and then dma_alloc_coherent() failed caused by large size, and then -trunk[1] is freed in ath11k_qmi_free_target_mem_chunk(), the left 18 -trunks will be reuse for the 2nd QMI_WLFW_REQUEST_MEM_IND message. - -Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 - -Fixes: 5962f370ce41 ("ath11k: Reuse the available memory after firmware reload") -Signed-off-by: Wen Gong -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20220928073832.16251-1-quic_wgong@quicinc.com ---- - drivers/net/wireless/ath/ath11k/qmi.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/qmi.c -+++ b/drivers/net/wireless/ath/ath11k/qmi.c -@@ -1961,7 +1961,7 @@ static void ath11k_qmi_free_target_mem_c - continue; - - dma_free_coherent(ab->dev, -- ab->qmi.target_mem[i].size, -+ ab->qmi.target_mem[i].prev_size, - ab->qmi.target_mem[i].vaddr, - ab->qmi.target_mem[i].paddr); - ab->qmi.target_mem[i].vaddr = NULL; -@@ -1982,12 +1982,12 @@ static int ath11k_qmi_alloc_target_mem_c - * in such case, no need to allocate memory for FW again. - */ - if (chunk->vaddr) { -- if (chunk->prev_type == chunk->type || -+ if (chunk->prev_type == chunk->type && - chunk->prev_size == chunk->size) - continue; - - /* cannot reuse the existing chunk */ -- dma_free_coherent(ab->dev, chunk->size, -+ dma_free_coherent(ab->dev, chunk->prev_size, - chunk->vaddr, chunk->paddr); - chunk->vaddr = NULL; - } diff --git a/package/kernel/mac80211/patches/ath11k/0004-ath11k-add-support-in-survey-dump-with-bss_chan_info.patch b/package/kernel/mac80211/patches/ath11k/0004-ath11k-add-support-in-survey-dump-with-bss_chan_info.patch new file mode 100644 index 000000000..e2a824558 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0004-ath11k-add-support-in-survey-dump-with-bss_chan_info.patch @@ -0,0 +1,51 @@ +From 9b4dd38b46cf24d8cb3ab433661cdc23a35160d0 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Wed, 21 Jul 2021 00:49:21 +0300 +Subject: [PATCH] ath11k: add support in survey dump with bss_chan_info + +Survey dump statistics is not displaying channel rx and tx time because +the service flag is not enabled. Enable the service flag "bss_chan_info" +in wmi_resource_config to fetch and print the stats for the specific +pdev. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01228-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Ritesh Singh +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720214922.118078-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/hw.c | 2 ++ + drivers/net/wireless/ath/ath11k/wmi.h | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -97,6 +97,7 @@ static void ath11k_init_wmi_config_qca63 + config->num_multicast_filter_entries = 0x20; + config->num_wow_filters = 0x16; + config->num_keep_alive_pattern = 0; ++ config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; + } + + static void ath11k_hw_ipq8074_reo_setup(struct ath11k_base *ab) +@@ -197,6 +198,7 @@ static void ath11k_init_wmi_config_ipq80 + config->peer_map_unmap_v2_support = 1; + config->twt_ap_pdev_count = ab->num_radios; + config->twt_ap_sta_count = 1000; ++ config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; + } + + static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2244,6 +2244,8 @@ struct wmi_init_cmd { + u32 num_host_mem_chunks; + } __packed; + ++#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) ++ + struct wmi_resource_config { + u32 tlv_header; + u32 num_vdevs; diff --git a/package/kernel/mac80211/patches/ath11k/0005-wifi-ath11k-Fix-spelling-mistake-chnange-change.patch b/package/kernel/mac80211/patches/ath11k/0005-wifi-ath11k-Fix-spelling-mistake-chnange-change.patch deleted file mode 100644 index 4b52252ef..000000000 --- a/package/kernel/mac80211/patches/ath11k/0005-wifi-ath11k-Fix-spelling-mistake-chnange-change.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a797f479bf3e02c6d179c2e6aeace7f9b22b0acd Mon Sep 17 00:00:00 2001 -From: Colin Ian King -Date: Wed, 28 Sep 2022 15:38:34 +0100 -Subject: [PATCH] wifi: ath11k: Fix spelling mistake "chnange" -> "change" - -There is a spelling mistake in an ath11k_dbg debug message. Fix it. - -Signed-off-by: Colin Ian King -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20220928143834.35189-1-colin.i.king@gmail.com ---- - drivers/net/wireless/ath/ath11k/wmi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/wireless/ath/ath11k/wmi.c -+++ b/drivers/net/wireless/ath/ath11k/wmi.c -@@ -6829,7 +6829,7 @@ static void ath11k_wmi_event_peer_sta_ps - } - - ath11k_dbg(ab, ATH11K_DBG_WMI, -- "peer sta ps chnange ev addr %pM state %u sup_bitmap %x ps_valid %u ts %u\n", -+ "peer sta ps change ev addr %pM state %u sup_bitmap %x ps_valid %u ts %u\n", - ev->peer_macaddr.addr, ev->peer_ps_state, - ev->ps_supported_bitmap, ev->peer_ps_valid, - ev->peer_ps_timestamp); diff --git a/package/kernel/mac80211/patches/ath11k/0006-ath11k-move-static-function-ath11k_mac_vdev_setup_sy.patch b/package/kernel/mac80211/patches/ath11k/0006-ath11k-move-static-function-ath11k_mac_vdev_setup_sy.patch new file mode 100644 index 000000000..56c221ab3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0006-ath11k-move-static-function-ath11k_mac_vdev_setup_sy.patch @@ -0,0 +1,65 @@ +From d37b4862312c980d1f6843d11a14ad4eda242c8d Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 21 Sep 2021 16:39:29 +0300 +Subject: [PATCH] ath11k: move static function ath11k_mac_vdev_setup_sync to + top + +This is to prepare for monitor mode clean up. +No functional changes are done. + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Co-developed-by: Vasanthakumar Thiagarajan +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721162053.46290-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 28 +++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -732,6 +732,20 @@ static int ath11k_monitor_vdev_up(struct + return 0; + } + ++static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar) ++{ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) ++ return -ESHUTDOWN; ++ ++ if (!wait_for_completion_timeout(&ar->vdev_setup_done, ++ ATH11K_VDEV_SETUP_TIMEOUT_HZ)) ++ return -ETIMEDOUT; ++ ++ return ar->last_wmi_vdev_start_status ? -EINVAL : 0; ++} ++ + static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) + { + /* mac80211 requires this op to be present and that's why +@@ -5175,20 +5189,6 @@ static void ath11k_mac_op_remove_chanctx + mutex_unlock(&ar->conf_mutex); + } + +-static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar) +-{ +- lockdep_assert_held(&ar->conf_mutex); +- +- if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) +- return -ESHUTDOWN; +- +- if (!wait_for_completion_timeout(&ar->vdev_setup_done, +- ATH11K_VDEV_SETUP_TIMEOUT_HZ)) +- return -ETIMEDOUT; +- +- return ar->last_wmi_vdev_start_status ? -EINVAL : 0; +-} +- + static int + ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, + const struct cfg80211_chan_def *chandef, diff --git a/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch b/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch deleted file mode 100644 index f4fedb46c..000000000 --- a/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 3ff51d7416ee1ea2d771051a0ffa1ec8be054768 Mon Sep 17 00:00:00 2001 -From: Aditya Kumar Singh -Date: Wed, 5 Oct 2022 15:24:30 +0530 -Subject: [PATCH 6/9] wifi: ath11k: fix firmware assert during bandwidth change - for peer sta - -Currently, ath11k sends peer assoc command for each peer to -firmware when bandwidth changes. Peer assoc command is a -bulky command and if many clients are connected, this could -lead to firmware buffer getting overflowed leading to a firmware -assert. - -However, during bandwidth change, only phymode and bandwidth -also can be updated by WMI set peer param command. This makes -the overall command light when compared to peer assoc and for -multi-client cases, firmware buffer overflow also does not -occur. - -Remove sending peer assoc command during sta bandwidth change -and instead add sending WMI set peer param command for phymode -and bandwidth. - -Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 - -Fixes: f187fe8e3bc65 ("ath11k: fix firmware crash during channel switch") -Signed-off-by: Aditya Kumar Singh -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221005095430.19890-1-quic_adisi@quicinc.com ---- - drivers/net/wireless/ath/ath11k/core.h | 2 + - drivers/net/wireless/ath/ath11k/mac.c | 122 +++++++++++++++++-------- - 2 files changed, 87 insertions(+), 37 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/core.h -+++ b/drivers/net/wireless/ath/ath11k/core.h -@@ -505,6 +505,8 @@ struct ath11k_sta { - u64 ps_start_jiffies; - u64 ps_total_duration; - bool peer_current_ps_valid; -+ -+ u32 bw_prev; - }; - - #define ATH11K_MIN_5G_FREQ 4150 ---- a/drivers/net/wireless/ath/ath11k/mac.c -+++ b/drivers/net/wireless/ath/ath11k/mac.c -@@ -4215,10 +4215,11 @@ static void ath11k_sta_rc_update_wk(stru - const u8 *ht_mcs_mask; - const u16 *vht_mcs_mask; - const u16 *he_mcs_mask; -- u32 changed, bw, nss, smps; -+ u32 changed, bw, nss, smps, bw_prev; - int err, num_vht_rates, num_he_rates; - const struct cfg80211_bitrate_mask *mask; - struct peer_assoc_params peer_arg; -+ enum wmi_phy_mode peer_phymode; - - arsta = container_of(wk, struct ath11k_sta, update_wk); - sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); -@@ -4239,6 +4240,7 @@ static void ath11k_sta_rc_update_wk(stru - arsta->changed = 0; - - bw = arsta->bw; -+ bw_prev = arsta->bw_prev; - nss = arsta->nss; - smps = arsta->smps; - -@@ -4252,26 +4254,57 @@ static void ath11k_sta_rc_update_wk(stru - ath11k_mac_max_he_nss(he_mcs_mask))); - - if (changed & IEEE80211_RC_BW_CHANGED) { -- /* Send peer assoc command before set peer bandwidth param to -- * avoid the mismatch between the peer phymode and the peer -- * bandwidth. -- */ -- ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); -+ /* Get the peer phymode */ -+ ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); -+ peer_phymode = peer_arg.peer_phymode; -+ -+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n", -+ sta->addr, bw, peer_phymode); -+ -+ if (bw > bw_prev) { -+ /* BW is upgraded. In this case we send WMI_PEER_PHYMODE -+ * followed by WMI_PEER_CHWIDTH -+ */ -+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n", -+ sta->addr, bw, bw_prev); -+ -+ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, -+ WMI_PEER_PHYMODE, peer_phymode); -+ -+ if (err) { -+ ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n", -+ sta->addr, peer_phymode, err); -+ goto err_rc_bw_changed; -+ } - -- peer_arg.is_assoc = false; -- err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); -- if (err) { -- ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n", -- sta->addr, arvif->vdev_id, err); -- } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { - err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, - WMI_PEER_CHWIDTH, bw); -+ - if (err) - ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", - sta->addr, bw, err); - } else { -- ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", -- sta->addr, arvif->vdev_id); -+ /* BW is downgraded. In this case we send WMI_PEER_CHWIDTH -+ * followed by WMI_PEER_PHYMODE -+ */ -+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d,old BW %d\n", -+ sta->addr, bw, bw_prev); -+ -+ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, -+ WMI_PEER_CHWIDTH, bw); -+ -+ if (err) { -+ ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", -+ sta->addr, bw, err); -+ goto err_rc_bw_changed; -+ } -+ -+ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, -+ WMI_PEER_PHYMODE, peer_phymode); -+ -+ if (err) -+ ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n", -+ sta->addr, peer_phymode, err); - } - } - -@@ -4352,6 +4385,7 @@ static void ath11k_sta_rc_update_wk(stru - } - } - -+err_rc_bw_changed: - mutex_unlock(&ar->conf_mutex); - } - -@@ -4505,6 +4539,34 @@ exit: - return ret; - } - -+static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, -+ struct ieee80211_sta *sta) -+{ -+ u32 bw = WMI_PEER_CHWIDTH_20MHZ; -+ -+ switch (sta->deflink.bandwidth) { -+ case IEEE80211_STA_RX_BW_20: -+ bw = WMI_PEER_CHWIDTH_20MHZ; -+ break; -+ case IEEE80211_STA_RX_BW_40: -+ bw = WMI_PEER_CHWIDTH_40MHZ; -+ break; -+ case IEEE80211_STA_RX_BW_80: -+ bw = WMI_PEER_CHWIDTH_80MHZ; -+ break; -+ case IEEE80211_STA_RX_BW_160: -+ bw = WMI_PEER_CHWIDTH_160MHZ; -+ break; -+ default: -+ ath11k_warn(ar->ab, "Invalid bandwidth %d for %pM\n", -+ sta->deflink.bandwidth, sta->addr); -+ bw = WMI_PEER_CHWIDTH_20MHZ; -+ break; -+ } -+ -+ return bw; -+} -+ - static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, -@@ -4590,6 +4652,12 @@ static int ath11k_mac_op_sta_state(struc - if (ret) - ath11k_warn(ar->ab, "Failed to associate station: %pM\n", - sta->addr); -+ -+ spin_lock_bh(&ar->data_lock); -+ /* Set arsta bw and prev bw */ -+ arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); -+ arsta->bw_prev = arsta->bw; -+ spin_unlock_bh(&ar->data_lock); - } else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTHORIZED) { - spin_lock_bh(&ar->ab->base_lock); -@@ -4713,28 +4781,8 @@ static void ath11k_mac_op_sta_rc_update( - spin_lock_bh(&ar->data_lock); - - if (changed & IEEE80211_RC_BW_CHANGED) { -- bw = WMI_PEER_CHWIDTH_20MHZ; -- -- switch (sta->deflink.bandwidth) { -- case IEEE80211_STA_RX_BW_20: -- bw = WMI_PEER_CHWIDTH_20MHZ; -- break; -- case IEEE80211_STA_RX_BW_40: -- bw = WMI_PEER_CHWIDTH_40MHZ; -- break; -- case IEEE80211_STA_RX_BW_80: -- bw = WMI_PEER_CHWIDTH_80MHZ; -- break; -- case IEEE80211_STA_RX_BW_160: -- bw = WMI_PEER_CHWIDTH_160MHZ; -- break; -- default: -- ath11k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n", -- sta->deflink.bandwidth, sta->addr); -- bw = WMI_PEER_CHWIDTH_20MHZ; -- break; -- } -- -+ bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); -+ arsta->bw_prev = arsta->bw; - arsta->bw = bw; - } - diff --git a/package/kernel/mac80211/patches/ath11k/0007-ath11k-add-separate-APIs-for-monitor-mode.patch b/package/kernel/mac80211/patches/ath11k/0007-ath11k-add-separate-APIs-for-monitor-mode.patch new file mode 100644 index 000000000..51944e6e6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0007-ath11k-add-separate-APIs-for-monitor-mode.patch @@ -0,0 +1,442 @@ +From 64e06b78a92744d43d3993ba623d2686d8f937e7 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 21 Sep 2021 16:39:29 +0300 +Subject: [PATCH] ath11k: add separate APIs for monitor mode + +Add separate APIs for monitor_vdev_create/monitor_vdev_delete +and monitor_vdev_start/monitor_vdev_stop. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01725-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Co-developed-by: Vasanthakumar Thiagarajan +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721162053.46290-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 5 +- + drivers/net/wireless/ath/ath11k/mac.c | 371 ++++++++++++++++++++++++- + 2 files changed, 370 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -200,6 +200,9 @@ enum ath11k_dev_flags { + + enum ath11k_monitor_flags { + ATH11K_FLAG_MONITOR_ENABLED, ++ ATH11K_FLAG_MONITOR_CONF_ENABLED, ++ ATH11K_FLAG_MONITOR_STARTED, ++ ATH11K_FLAG_MONITOR_VDEV_CREATED, + }; + + struct ath11k_vif { +@@ -494,7 +497,6 @@ struct ath11k { + u32 chan_tx_pwr; + u32 num_stations; + u32 max_num_stations; +- bool monitor_present; + /* To synchronize concurrent synchronous mac80211 callback operations, + * concurrent debugfs configuration and concurrent FW statistics events. + */ +@@ -569,6 +571,7 @@ struct ath11k { + struct ath11k_per_peer_tx_stats cached_stats; + u32 last_ppdu_id; + u32 cached_ppdu_id; ++ int monitor_vdev_id; + #ifdef CPTCFG_ATH11K_DEBUGFS + struct ath11k_debug debug; + #endif +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -746,14 +746,370 @@ static inline int ath11k_mac_vdev_setup_ + return ar->last_wmi_vdev_start_status ? -EINVAL : 0; + } + +-static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) ++static void ++ath11k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *conf, ++ void *data) + { +- /* mac80211 requires this op to be present and that's why +- * there's an empty function, this can be extended when +- * required. +- */ ++ struct cfg80211_chan_def **def = data; ++ ++ *def = &conf->def; ++} ++ ++static int ath11k_mac_monitor_vdev_start(struct ath11k *ar, int vdev_id, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct ieee80211_channel *channel; ++ struct wmi_vdev_start_req_arg arg = {}; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ channel = chandef->chan; ++ ++ arg.vdev_id = vdev_id; ++ arg.channel.freq = channel->center_freq; ++ arg.channel.band_center_freq1 = chandef->center_freq1; ++ arg.channel.band_center_freq2 = chandef->center_freq2; ++ ++ arg.channel.mode = ath11k_phymodes[chandef->chan->band][chandef->width]; ++ arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); ++ ++ arg.channel.min_power = 0; ++ arg.channel.max_power = channel->max_power * 2; ++ arg.channel.max_reg_power = channel->max_reg_power * 2; ++ arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ++ ++ arg.pref_tx_streams = ar->num_tx_chains; ++ arg.pref_rx_streams = ar->num_rx_chains; ++ ++ arg.channel.passive = !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); ++ ++ reinit_completion(&ar->vdev_setup_done); ++ reinit_completion(&ar->vdev_delete_done); ++ ++ ret = ath11k_wmi_vdev_start(ar, &arg, false); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request monitor vdev %i start: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_mac_vdev_setup_sync(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to synchronize setup for monitor vdev %i start: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", ++ vdev_id, ret); ++ goto vdev_stop; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n", ++ vdev_id); + + return 0; ++ ++vdev_stop: ++ reinit_completion(&ar->vdev_setup_done); ++ ++ ret = ath11k_wmi_vdev_stop(ar, vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor vdev %i after start failure: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_mac_vdev_setup_sync(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to synchronize setup for vdev %i stop: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ return -EIO; ++} ++ ++static int ath11k_mac_monitor_vdev_stop(struct ath11k *ar) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ reinit_completion(&ar->vdev_setup_done); ++ ++ ret = ath11k_wmi_vdev_stop(ar, ar->monitor_vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request monitor vdev %i stop: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_mac_vdev_setup_sync(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to synchronize monitor vdev %i stop: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_wmi_vdev_down(ar, ar->monitor_vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to put down monitor vdev %i: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i stopped\n", ++ ar->monitor_vdev_id); ++ ++ return 0; ++} ++ ++static int ath11k_mac_monitor_vdev_create(struct ath11k *ar) ++{ ++ struct ath11k_pdev *pdev = ar->pdev; ++ struct vdev_create_params param = {}; ++ int bit, ret; ++ u8 tmp_addr[6] = {0}; ++ u16 nss; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) ++ return 0; ++ ++ if (ar->ab->free_vdev_map == 0) { ++ ath11k_warn(ar->ab, "failed to find free vdev id for monitor vdev\n"); ++ return -ENOMEM; ++ } ++ ++ bit = __ffs64(ar->ab->free_vdev_map); ++ ++ ar->monitor_vdev_id = bit; ++ ++ param.if_id = ar->monitor_vdev_id; ++ param.type = WMI_VDEV_TYPE_MONITOR; ++ param.subtype = WMI_VDEV_SUBTYPE_NONE; ++ param.pdev_id = pdev->pdev_id; ++ ++ if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) { ++ param.chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains; ++ param.chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains; ++ } ++ if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) { ++ param.chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains; ++ param.chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains; ++ } ++ ++ ret = ath11k_wmi_vdev_create(ar, tmp_addr, ¶m); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request monitor vdev %i creation: %d\n", ++ ar->monitor_vdev_id, ret); ++ ar->monitor_vdev_id = -1; ++ return ret; ++ } ++ ++ nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1; ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, ar->monitor_vdev_id, ++ WMI_VDEV_PARAM_NSS, nss); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n", ++ ar->monitor_vdev_id, ar->cfg_tx_chainmask, nss, ret); ++ goto err_vdev_del; ++ } ++ ++ ret = ath11k_mac_txpower_recalc(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to recalc txpower for monitor vdev %d: %d\n", ++ ar->monitor_vdev_id, ret); ++ goto err_vdev_del; ++ } ++ ++ ar->allocated_vdev_map |= 1LL << ar->monitor_vdev_id; ++ ar->ab->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); ++ ar->num_created_vdevs++; ++ set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %d created\n", ++ ar->monitor_vdev_id); ++ ++ return 0; ++ ++err_vdev_del: ++ ath11k_wmi_vdev_delete(ar, ar->monitor_vdev_id); ++ ar->monitor_vdev_id = -1; ++ return ret; ++} ++ ++static int ath11k_mac_monitor_vdev_delete(struct ath11k *ar) ++{ ++ int ret; ++ unsigned long time_left; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (!test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) ++ return 0; ++ ++ reinit_completion(&ar->vdev_delete_done); ++ ++ ret = ath11k_wmi_vdev_delete(ar, ar->monitor_vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request wmi monitor vdev %i removal: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ time_left = wait_for_completion_timeout(&ar->vdev_delete_done, ++ ATH11K_VDEV_DELETE_TIMEOUT_HZ); ++ if (time_left == 0) { ++ ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n"); ++ } else { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %d deleted\n", ++ ar->monitor_vdev_id); ++ ++ ar->allocated_vdev_map &= ~(1LL << ar->monitor_vdev_id); ++ ar->ab->free_vdev_map |= 1LL << (ar->monitor_vdev_id); ++ ar->num_created_vdevs--; ++ ar->monitor_vdev_id = -1; ++ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ } ++ ++ return ret; ++} ++ ++static int ath11k_mac_monitor_start(struct ath11k *ar) ++{ ++ struct cfg80211_chan_def *chandef = NULL; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ++ return 0; ++ ++ ieee80211_iter_chan_contexts_atomic(ar->hw, ++ ath11k_mac_get_any_chandef_iter, ++ &chandef); ++ if (!chandef) ++ return 0; ++ ++ ret = ath11k_mac_monitor_vdev_start(ar, ar->monitor_vdev_id, chandef); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor vdev: %d\n", ret); ++ ath11k_mac_monitor_vdev_delete(ar); ++ return ret; ++ } ++ ++ set_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); ++ ++ ar->num_started_vdevs++; ++ ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, false); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to configure htt monitor mode ring during start: %d", ++ ret); ++ return ret; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor started\n"); ++ ++ return 0; ++} ++ ++static int ath11k_mac_monitor_stop(struct ath11k *ar) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (!test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ++ return 0; ++ ++ ret = ath11k_mac_monitor_vdev_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor vdev: %d\n", ret); ++ return ret; ++ } ++ ++ clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); ++ ar->num_started_vdevs--; ++ ++ ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, true); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to configure htt monitor mode ring during stop: %d", ++ ret); ++ return ret; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor stopped ret %d\n", ret); ++ ++ return 0; ++} ++ ++static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ieee80211_conf *conf = &hw->conf; ++ int ret = 0; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ++ if (conf->flags & IEEE80211_CONF_MONITOR) { ++ set_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, ++ &ar->monitor_flags)) ++ goto out; ++ ++ ret = ath11k_mac_monitor_vdev_create(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to create monitor vdev: %d", ++ ret); ++ goto out; ++ } ++ ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor: %d", ++ ret); ++ goto err_mon_del; ++ } ++ } else { ++ clear_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags); ++ ++ if (!test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, ++ &ar->monitor_flags)) ++ goto out; ++ ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor: %d", ++ ret); ++ goto out; ++ } ++ ++ ret = ath11k_mac_monitor_vdev_delete(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to delete monitor vdev: %d", ++ ret); ++ goto out; ++ } ++ } ++ } ++ ++out: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++ ++err_mon_del: ++ ath11k_mac_monitor_vdev_delete(ar); ++ mutex_unlock(&ar->conf_mutex); ++ return ret; + } + + static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +@@ -6781,7 +7137,12 @@ int ath11k_mac_allocate(struct ath11k_ba + + INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); ++ + clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); ++ clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); ++ ++ ar->monitor_vdev_id = -1; ++ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); + } + + return 0; diff --git a/package/kernel/mac80211/patches/ath11k/0007-wifi-ath11k-suppress-add-interface-error.patch b/package/kernel/mac80211/patches/ath11k/0007-wifi-ath11k-suppress-add-interface-error.patch deleted file mode 100644 index fbef0abb8..000000000 --- a/package/kernel/mac80211/patches/ath11k/0007-wifi-ath11k-suppress-add-interface-error.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 638b26652b0438563a76ec90014c8cba34db982b Mon Sep 17 00:00:00 2001 -From: Karthikeyan Periyasamy -Date: Thu, 6 Oct 2022 06:28:42 +0530 -Subject: [PATCH 7/9] wifi: ath11k: suppress add interface error - -In the VIF (other than monitor type) creation request, we should not -throw the error code when the monitor VIF creation fails, since the -actual VIF creation succeeds. If we throw the error code from driver -then the actual VIF creation get fail. So suppress the monitor VIF -creation error by throwing warning message instead of error code. - -Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.6.0.1-00760-QCAHKSWPL_SILICONZ-1 - -Signed-off-by: Karthikeyan Periyasamy -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221006005842.8599-1-quic_periyasa@quicinc.com ---- - drivers/net/wireless/ath/ath11k/mac.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/mac.c -+++ b/drivers/net/wireless/ath/ath11k/mac.c -@@ -6421,18 +6421,16 @@ static int ath11k_mac_op_add_interface(s - - ath11k_dp_vdev_tx_attach(ar, arvif); - -+ ath11k_debugfs_add_interface(arvif); -+ - if (vif->type != NL80211_IFTYPE_MONITOR && - test_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags)) { - ret = ath11k_mac_monitor_vdev_create(ar); -- if (ret) { -+ if (ret) - ath11k_warn(ar->ab, "failed to create monitor vdev during add interface: %d", - ret); -- goto err_peer_del; -- } - } - -- ath11k_debugfs_add_interface(arvif); -- - mutex_unlock(&ar->conf_mutex); - - return 0; -@@ -6457,7 +6455,6 @@ err_vdev_del: - spin_unlock_bh(&ar->data_lock); - - err: -- ath11k_debugfs_remove_interface(arvif); - mutex_unlock(&ar->conf_mutex); - - return ret; diff --git a/package/kernel/mac80211/patches/ath11k/0008-ath11k-monitor-mode-clean-up-to-use-separate-APIs.patch b/package/kernel/mac80211/patches/ath11k/0008-ath11k-monitor-mode-clean-up-to-use-separate-APIs.patch new file mode 100644 index 000000000..b241aacc0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0008-ath11k-monitor-mode-clean-up-to-use-separate-APIs.patch @@ -0,0 +1,370 @@ +From 689a5e6fff75229ac7c2af7a9c51dc2d3ca1882b Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 21 Sep 2021 16:39:30 +0300 +Subject: [PATCH] ath11k: monitor mode clean up to use separate APIs + +If monitor interface is enabled in co-exist mode, only local traffic are +captured. It's caused by missing monitor vdev in co-exist mode. So, +monitor mode clean up is done with separate Monitor APIs. For this, +introduce flags monitor_started and monitor_vdev_created. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01725-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Co-developed-by: Vasanthakumar Thiagarajan +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721162053.46290-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 - + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- + drivers/net/wireless/ath/ath11k/dp_tx.c | 8 +- + drivers/net/wireless/ath/ath11k/mac.c | 150 ++++++++++++++++-------- + 4 files changed, 110 insertions(+), 51 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -199,7 +199,6 @@ enum ath11k_dev_flags { + }; + + enum ath11k_monitor_flags { +- ATH11K_FLAG_MONITOR_ENABLED, + ATH11K_FLAG_MONITOR_CONF_ENABLED, + ATH11K_FLAG_MONITOR_STARTED, + ATH11K_FLAG_MONITOR_VDEV_CREATED, +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -5032,7 +5032,7 @@ int ath11k_dp_rx_process_mon_rings(struc + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); + int ret = 0; + +- if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) + ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); + else + ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -1076,12 +1076,16 @@ int ath11k_dp_tx_htt_monitor_mode_ring_c + + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; +- if (!reset) ++ if (!reset) { + tlv_filter.rx_filter = + HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; +- else ++ } else { + tlv_filter = ath11k_mac_mon_status_filter_default; + ++ if (ath11k_debugfs_is_extd_rx_stats_enabled(ar)) ++ tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar); ++ } ++ + ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, + dp->mac_id + i, + HAL_RXDMA_MONITOR_STATUS, +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -716,22 +716,6 @@ void ath11k_mac_peer_cleanup_all(struct + ar->num_stations = 0; + } + +-static int ath11k_monitor_vdev_up(struct ath11k *ar, int vdev_id) +-{ +- int ret = 0; +- +- ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); +- if (ret) { +- ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", +- vdev_id, ret); +- return ret; +- } +- +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n", +- vdev_id); +- return 0; +-} +- + static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar) + { + lockdep_assert_held(&ar->conf_mutex); +@@ -2331,7 +2315,7 @@ static int ath11k_mac_config_obss_pd(str + + /* Set and enable SRG/non-SRG OBSS PD Threshold */ + param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD; +- if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) { ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) { + ret = ath11k_wmi_pdev_set_param(ar, param_id, 0, pdev_id); + if (ret) + ath11k_warn(ar->ab, +@@ -5110,8 +5094,8 @@ static int ath11k_mac_op_add_interface(s + } + + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { +- ath11k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", +- TARGET_NUM_VDEVS); ++ ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n", ++ ar->num_created_vdevs, TARGET_NUM_VDEVS); + ret = -EBUSY; + goto err; + } +@@ -5151,6 +5135,7 @@ static int ath11k_mac_op_add_interface(s + break; + case NL80211_IFTYPE_MONITOR: + arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ++ ar->monitor_vdev_id = bit; + break; + default: + WARN_ON(1); +@@ -5252,6 +5237,9 @@ static int ath11k_mac_op_add_interface(s + goto err_peer_del; + } + break; ++ case WMI_VDEV_TYPE_MONITOR: ++ set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ break; + default: + break; + } +@@ -5272,6 +5260,16 @@ static int ath11k_mac_op_add_interface(s + + ath11k_dp_vdev_tx_attach(ar, arvif); + ++ if (vif->type != NL80211_IFTYPE_MONITOR && ++ test_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_vdev_create(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to create monitor vdev during add interface: %d", ++ ret); ++ goto err_peer_del; ++ } ++ } ++ + mutex_unlock(&ar->conf_mutex); + + return 0; +@@ -5369,6 +5367,18 @@ static void ath11k_mac_op_remove_interfa + ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", + vif->addr, arvif->vdev_id); + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ ar->monitor_vdev_id = -1; ++ } else if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags) && ++ !test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_vdev_delete(ar); ++ if (ret) ++ /* continue even if there's an error */ ++ ath11k_warn(ar->ab, "failed to delete vdev monitor during remove interface: %d", ++ ret); ++ } ++ + err_vdev_del: + spin_lock_bh(&ar->data_lock); + list_del(&arvif->list); +@@ -5388,7 +5398,6 @@ err_vdev_del: + + /* Recalc txpower for remaining vdev */ + ath11k_mac_txpower_recalc(ar); +- clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); + + /* TODO: recal traffic pause state based on the available vdevs */ + +@@ -5411,8 +5420,6 @@ static void ath11k_mac_op_configure_filt + u64 multicast) + { + struct ath11k *ar = hw->priv; +- bool reset_flag = false; +- int ret = 0; + + mutex_lock(&ar->conf_mutex); + +@@ -5420,23 +5427,6 @@ static void ath11k_mac_op_configure_filt + *total_flags &= SUPPORTED_FILTERS; + ar->filter_flags = *total_flags; + +- /* For monitor mode */ +- reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC); +- +- ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag); +- if (!ret) { +- if (!reset_flag) +- set_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); +- else +- clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); +- } else { +- ath11k_warn(ar->ab, +- "fail to set monitor filter: %d\n", ret); +- } +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "changed_flags:0x%x, total_flags:0x%x, reset_flag:%d\n", +- changed_flags, *total_flags, reset_flag); +- + mutex_unlock(&ar->conf_mutex); + } + +@@ -5627,7 +5617,9 @@ ath11k_mac_vdev_start_restart(struct ath + return ret; + } + +- ar->num_started_vdevs++; ++ if (!restart) ++ ar->num_started_vdevs++; ++ + ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM started, vdev_id %d\n", + arvif->vif->addr, arvif->vdev_id); + +@@ -5755,12 +5747,16 @@ ath11k_mac_update_vif_chan(struct ath11k + struct ath11k_vif *arvif; + int ret; + int i; ++ bool monitor_vif = false; + + lockdep_assert_held(&ar->conf_mutex); + + for (i = 0; i < n_vifs; i++) { + arvif = (void *)vifs[i].vif->drv_priv; + ++ if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) ++ monitor_vif = true; ++ + ath11k_dbg(ab, ATH11K_DBG_MAC, + "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", + arvif->vdev_id, +@@ -5781,6 +5777,8 @@ ath11k_mac_update_vif_chan(struct ath11k + arvif->vdev_id, ret); + continue; + } ++ ++ ar->num_started_vdevs--; + } + + /* All relevant vdevs are downed and associated channel resources +@@ -5818,6 +5816,24 @@ ath11k_mac_update_vif_chan(struct ath11k + continue; + } + } ++ ++ /* Restart the internal monitor vdev on new channel */ ++ if (!monitor_vif && ++ test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor during vif channel update: %d", ++ ret); ++ return; ++ } ++ ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor during vif channel update: %d", ++ ret); ++ return; ++ } ++ } + } + + static void +@@ -5897,7 +5913,7 @@ static int ath11k_start_vdev_delay(struc + } + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { +- ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); ++ ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr); + if (ret) { + ath11k_warn(ab, "failed put monitor up: %d\n", ret); + return ret; +@@ -5957,6 +5973,18 @@ ath11k_mac_op_assign_vif_chanctx(struct + } + } + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor during vif channel context assignment: %d", ++ ret); ++ goto out; ++ } ++ ++ arvif->is_started = true; ++ goto out; ++ } ++ + ret = ath11k_mac_vdev_start(arvif, &ctx->def); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", +@@ -5964,14 +5992,19 @@ ath11k_mac_op_assign_vif_chanctx(struct + ctx->def.chan->center_freq, ret); + goto out; + } +- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { +- ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); +- if (ret) +- goto out; +- } + + arvif->is_started = true; + ++ if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ++ test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor during vif channel context assignment: %d", ++ ret); ++ goto out; ++ } ++ } ++ + /* TODO: Setup ps and cts/rts protection */ + + ret = 0; +@@ -6005,6 +6038,20 @@ ath11k_mac_op_unassign_vif_chanctx(struc + ath11k_peer_find_by_addr(ab, ar->mac_addr)) + ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr); + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor during vif channel context unassignment: %d", ++ ret); ++ mutex_unlock(&ar->conf_mutex); ++ return; ++ } ++ ++ arvif->is_started = false; ++ mutex_unlock(&ar->conf_mutex); ++ return; ++ } ++ + ret = ath11k_mac_vdev_stop(arvif); + if (ret) + ath11k_warn(ab, "failed to stop vdev %i: %d\n", +@@ -6016,6 +6063,16 @@ ath11k_mac_op_unassign_vif_chanctx(struc + arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + ath11k_wmi_vdev_down(ar, arvif->vdev_id); + ++ if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ++ ar->num_started_vdevs == 1 && ++ test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) ++ /* continue even if there's an error */ ++ ath11k_warn(ar->ab, "failed to stop monitor during vif channel context unassignment: %d", ++ ret); ++ } ++ + mutex_unlock(&ar->conf_mutex); + } + +@@ -7138,7 +7195,6 @@ int ath11k_mac_allocate(struct ath11k_ba + INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + +- clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); + clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); + + ar->monitor_vdev_id = -1; diff --git a/package/kernel/mac80211/patches/ath11k/0008-wifi-ath11k-add-support-to-configure-channel-dwell-t.patch b/package/kernel/mac80211/patches/ath11k/0008-wifi-ath11k-add-support-to-configure-channel-dwell-t.patch deleted file mode 100644 index d0b19fe59..000000000 --- a/package/kernel/mac80211/patches/ath11k/0008-wifi-ath11k-add-support-to-configure-channel-dwell-t.patch +++ /dev/null @@ -1,102 +0,0 @@ -From c362daa213cdeb0a9e7c2ed84849544c24505720 Mon Sep 17 00:00:00 2001 -From: Manikanta Pubbisetty -Date: Fri, 7 Oct 2022 10:41:30 +0530 -Subject: [PATCH 8/9] wifi: ath11k: add support to configure channel dwell time - -Add support to configure channel dwell time during scan. -Dwell time help to stay on the channel for a specified duration -during scan and aid userspace in finding WiFi networks. Very -useful in passive scans where longer dwell times are needed -to find the WiFi networks. - -Configure channel dwell time from duration of the scan request -received from mac80211 when the duration is non-zero. When the -scan request does not have duration value, use the default ones, -the current implementation. - -Advertise corresponding feature flag NL80211_EXT_FEATURE_SET_SCAN_DWELL -to enable the feature. - -Change is applicable for all ath11k hardware. - -Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00887-QCAMSLSWPLZ-1 - -Signed-off-by: Manikanta Pubbisetty -Reviewed-by: Jeff Johnson -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221007051130.6067-1-quic_mpubbise@quicinc.com ---- - drivers/net/wireless/ath/ath11k/mac.c | 33 +++++++++++++++++++++++---- - 1 file changed, 29 insertions(+), 4 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/mac.c -+++ b/drivers/net/wireless/ath/ath11k/mac.c -@@ -241,7 +241,10 @@ const struct htt_rx_ring_tlv_filter ath1 - #define ath11k_a_rates (ath11k_legacy_rates + 4) - #define ath11k_a_rates_size (ARRAY_SIZE(ath11k_legacy_rates) - 4) - --#define ATH11K_MAC_SCAN_TIMEOUT_MSECS 200 /* in msecs */ -+#define ATH11K_MAC_SCAN_CMD_EVT_OVERHEAD 200 /* in msecs */ -+ -+/* Overhead due to the processing of channel switch events from FW */ -+#define ATH11K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD 10 /* in msecs */ - - static const u32 ath11k_smps_map[] = { - [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, -@@ -3612,6 +3615,7 @@ static int ath11k_mac_op_hw_scan(struct - struct scan_req_params arg; - int ret = 0; - int i; -+ u32 scan_timeout; - - mutex_lock(&ar->conf_mutex); - -@@ -3681,6 +3685,26 @@ static int ath11k_mac_op_hw_scan(struct - ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); - } - -+ /* if duration is set, default dwell times will be overwritten */ -+ if (req->duration) { -+ arg.dwell_time_active = req->duration; -+ arg.dwell_time_active_2g = req->duration; -+ arg.dwell_time_active_6g = req->duration; -+ arg.dwell_time_passive = req->duration; -+ arg.dwell_time_passive_6g = req->duration; -+ arg.burst_duration = req->duration; -+ -+ scan_timeout = min_t(u32, arg.max_rest_time * -+ (arg.num_chan - 1) + (req->duration + -+ ATH11K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * -+ arg.num_chan, arg.max_scan_time); -+ } else { -+ scan_timeout = arg.max_scan_time; -+ } -+ -+ /* Add a margin to account for event/command processing */ -+ scan_timeout += ATH11K_MAC_SCAN_CMD_EVT_OVERHEAD; -+ - ret = ath11k_start_scan(ar, &arg); - if (ret) { - ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret); -@@ -3689,10 +3713,8 @@ static int ath11k_mac_op_hw_scan(struct - spin_unlock_bh(&ar->data_lock); - } - -- /* Add a 200ms margin to account for event/command processing */ - ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, -- msecs_to_jiffies(arg.max_scan_time + -- ATH11K_MAC_SCAN_TIMEOUT_MSECS)); -+ msecs_to_jiffies(scan_timeout)); - - exit: - kfree(arg.chan_list); -@@ -9060,6 +9082,9 @@ static int __ath11k_mac_register(struct - NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); - } - -+ wiphy_ext_feature_set(ar->hw->wiphy, -+ NL80211_EXT_FEATURE_SET_SCAN_DWELL); -+ - ath11k_reg_init(ar); - - if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) { diff --git a/package/kernel/mac80211/patches/ath11k/0009-ath11k-add-support-for-setting-fixed-HE-rate-gi-ltf.patch b/package/kernel/mac80211/patches/ath11k/0009-ath11k-add-support-for-setting-fixed-HE-rate-gi-ltf.patch new file mode 100644 index 000000000..78c06b92b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0009-ath11k-add-support-for-setting-fixed-HE-rate-gi-ltf.patch @@ -0,0 +1,1020 @@ +From 61fe43e7216df6e9a912d831aafc7142fa20f280 Mon Sep 17 00:00:00 2001 +From: Miles Hu +Date: Fri, 24 Sep 2021 16:52:45 +0300 +Subject: [PATCH] ath11k: add support for setting fixed HE rate/gi/ltf + +Support setting fixed HE rate/gi/ltf values that we are now able to send +to the kernel using nl80211. The added code is reusing parts of the +existing code path already used for HT/VHT. The new helpers are +symmetric to how we do it for HT/VHT. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00235-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Miles Hu +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Co-developed-by: Pradeep Chitrapu +Signed-off-by: Pradeep Chitrapu +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721173615.75637-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 595 ++++++++++++++++++++++++-- + drivers/net/wireless/ath/ath11k/wmi.c | 4 +- + drivers/net/wireless/ath/ath11k/wmi.h | 22 + + 3 files changed, 580 insertions(+), 41 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -355,6 +355,18 @@ ath11k_mac_max_vht_nss(const u16 vht_mcs + return 1; + } + ++static u32 ++ath11k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) ++{ ++ int nss; ++ ++ for (nss = NL80211_HE_NSS_MAX - 1; nss >= 0; nss--) ++ if (he_mcs_mask[nss]) ++ return nss + 1; ++ ++ return 1; ++} ++ + static u8 ath11k_parse_mpdudensity(u8 mpdudensity) + { + /* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": +@@ -1452,6 +1464,14 @@ static void ath11k_peer_assoc_h_ht(struc + arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG; + } + ++ /* As firmware handles this two flags (IEEE80211_HT_CAP_SGI_20 ++ * and IEEE80211_HT_CAP_SGI_40) for enabling SGI, we reset ++ * both flags if guard interval is Default GI ++ */ ++ if (arvif->bitrate_mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI) ++ arg->peer_ht_caps &= ~(IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40); ++ + if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { + if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40)) +@@ -1575,10 +1595,11 @@ static void ath11k_peer_assoc_h_vht(stru + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct cfg80211_chan_def def; + enum nl80211_band band; +- const u16 *vht_mcs_mask; ++ u16 *vht_mcs_mask; + u8 ampdu_factor; + u8 max_nss, vht_mcs; +- int i; ++ int i, vht_nss, nss_idx; ++ bool user_rate_valid = true; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1621,6 +1642,24 @@ static void ath11k_peer_assoc_h_vht(stru + if (sta->bandwidth == IEEE80211_STA_RX_BW_160) + arg->bw_160 = true; + ++ vht_nss = ath11k_mac_max_vht_nss(vht_mcs_mask); ++ ++ if (vht_nss > sta->rx_nss) { ++ user_rate_valid = false; ++ for (nss_idx = sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { ++ if (vht_mcs_mask[nss_idx]) { ++ user_rate_valid = true; ++ break; ++ } ++ } ++ } ++ ++ if (!user_rate_valid) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac setting vht range mcs value to peer supported nss %d for peer %pM\n", ++ sta->rx_nss, sta->addr); ++ vht_mcs_mask[sta->rx_nss - 1] = vht_mcs_mask[vht_nss - 1]; ++ } ++ + /* Calculate peer NSS capability from VHT capabilities if STA + * supports VHT. + */ +@@ -1659,18 +1698,100 @@ static void ath11k_peer_assoc_h_vht(stru + /* TODO: rxnss_override */ + } + ++static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) ++{ ++ switch ((mcs_map >> (2 * nss)) & 0x3) { ++ case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(8) - 1; ++ case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(10) - 1; ++ case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(12) - 1; ++ } ++ return 0; ++} ++ ++static u16 ath11k_peer_assoc_h_he_limit(u16 tx_mcs_set, ++ const u16 he_mcs_limit[NL80211_HE_NSS_MAX]) ++{ ++ int idx_limit; ++ int nss; ++ u16 mcs_map; ++ u16 mcs; ++ ++ for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { ++ mcs_map = ath11k_mac_get_max_he_mcs_map(tx_mcs_set, nss) & ++ he_mcs_limit[nss]; ++ ++ if (mcs_map) ++ idx_limit = fls(mcs_map) - 1; ++ else ++ idx_limit = -1; ++ ++ switch (idx_limit) { ++ case 0 ... 7: ++ mcs = IEEE80211_HE_MCS_SUPPORT_0_7; ++ break; ++ case 8: ++ case 9: ++ mcs = IEEE80211_HE_MCS_SUPPORT_0_9; ++ break; ++ case 10: ++ case 11: ++ mcs = IEEE80211_HE_MCS_SUPPORT_0_11; ++ break; ++ default: ++ WARN_ON(1); ++ fallthrough; ++ case -1: ++ mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; ++ break; ++ } ++ ++ tx_mcs_set &= ~(0x3 << (nss * 2)); ++ tx_mcs_set |= mcs << (nss * 2); ++ } ++ ++ return tx_mcs_set; ++} ++ ++static bool ++ath11k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) ++{ ++ int nss; ++ ++ for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) ++ if (he_mcs_mask[nss]) ++ return false; ++ ++ return true; ++} ++ + static void ath11k_peer_assoc_h_he(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct peer_assoc_params *arg) + { ++ struct ath11k_vif *arvif = (void *)vif->drv_priv; ++ struct cfg80211_chan_def def; + const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + u8 ampdu_factor; +- u16 v; ++ enum nl80211_band band; ++ u16 *he_mcs_mask; ++ u8 max_nss, he_mcs; ++ u16 he_tx_mcs = 0, v = 0; ++ int i, he_nss, nss_idx; ++ bool user_rate_valid = true; ++ ++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) ++ return; + + if (!he_cap->has_he) + return; + ++ band = def.chan->band; ++ he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; ++ ++ if (ath11k_peer_assoc_h_he_masked(he_mcs_mask)) ++ return; ++ + arg->he_flag = true; + + memcpy_and_pad(&arg->peer_he_cap_macinfo, +@@ -1747,25 +1868,48 @@ static void ath11k_peer_assoc_h_he(struc + if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ) + arg->twt_requester = true; + ++ he_nss = ath11k_mac_max_he_nss(he_mcs_mask); ++ ++ if (he_nss > sta->rx_nss) { ++ user_rate_valid = false; ++ for (nss_idx = sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { ++ if (he_mcs_mask[nss_idx]) { ++ user_rate_valid = true; ++ break; ++ } ++ } ++ } ++ ++ if (!user_rate_valid) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac setting he range mcs value to peer supported nss %d for peer %pM\n", ++ sta->rx_nss, sta->addr); ++ he_mcs_mask[sta->rx_nss - 1] = he_mcs_mask[he_nss - 1]; ++ } ++ + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { + v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80); ++ v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); + arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; + + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); + arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; + + arg->peer_he_mcs_count++; ++ he_tx_mcs = v; + } + v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; + + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); ++ v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); + arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; + + arg->peer_he_mcs_count++; ++ if (!he_tx_mcs) ++ he_tx_mcs = v; + fallthrough; + + default: +@@ -1773,11 +1917,34 @@ static void ath11k_peer_assoc_h_he(struc + arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; + + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); ++ v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); + arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; + + arg->peer_he_mcs_count++; ++ if (!he_tx_mcs) ++ he_tx_mcs = v; + break; + } ++ ++ /* Calculate peer NSS capability from HE capabilities if STA ++ * supports HE. ++ */ ++ for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) { ++ he_mcs = he_tx_mcs >> (2 * i) & 3; ++ ++ /* In case of fixed rates, MCS Range in he_tx_mcs might have ++ * unsupported range, with he_mcs_mask set, so check either of them ++ * to find nss. ++ */ ++ if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED || ++ he_mcs_mask[i]) ++ max_nss = i + 1; ++ } ++ arg->peer_nss = min(sta->rx_nss, max_nss); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac he peer %pM nss %d mcs cnt %d\n", ++ sta->addr, arg->peer_nss, arg->peer_he_mcs_count); + } + + static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, +@@ -1980,6 +2147,7 @@ static void ath11k_peer_assoc_h_phymode( + enum nl80211_band band; + const u8 *ht_mcs_mask; + const u16 *vht_mcs_mask; ++ const u16 *he_mcs_mask; + enum wmi_phy_mode phymode = MODE_UNKNOWN; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) +@@ -1988,10 +2156,12 @@ static void ath11k_peer_assoc_h_phymode( + band = def.chan->band; + ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; + vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; ++ he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + switch (band) { + case NL80211_BAND_2GHZ: +- if (sta->he_cap.has_he) { ++ if (sta->he_cap.has_he && ++ !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) { + if (sta->bandwidth == IEEE80211_STA_RX_BW_80) + phymode = MODE_11AX_HE80_2G; + else if (sta->bandwidth == IEEE80211_STA_RX_BW_40) +@@ -2019,7 +2189,8 @@ static void ath11k_peer_assoc_h_phymode( + case NL80211_BAND_5GHZ: + case NL80211_BAND_6GHZ: + /* Check HE first */ +- if (sta->he_cap.has_he) { ++ if (sta->he_cap.has_he && ++ !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) { + phymode = ath11k_mac_get_phymode_he(ar, sta); + } else if (sta->vht_cap.vht_supported && + !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) { +@@ -3247,6 +3418,20 @@ ath11k_mac_bitrate_mask_num_vht_rates(st + } + + static int ++ath11k_mac_bitrate_mask_num_he_rates(struct ath11k *ar, ++ enum nl80211_band band, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ int num_rates = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) ++ num_rates += hweight16(mask->control[band].he_mcs[i]); ++ ++ return num_rates; ++} ++ ++static int + ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif, + struct ieee80211_sta *sta, + const struct cfg80211_bitrate_mask *mask, +@@ -3274,6 +3459,10 @@ ath11k_mac_set_peer_vht_fixed_rate(struc + return -EINVAL; + } + ++ /* Avoid updating invalid nss as fixed rate*/ ++ if (nss > sta->rx_nss) ++ return -EINVAL; ++ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "Setting Fixed VHT Rate for peer %pM. Device will not switch to any other selected rates", + sta->addr); +@@ -3292,6 +3481,57 @@ ath11k_mac_set_peer_vht_fixed_rate(struc + return ret; + } + ++static int ++ath11k_mac_set_peer_he_fixed_rate(struct ath11k_vif *arvif, ++ struct ieee80211_sta *sta, ++ const struct cfg80211_bitrate_mask *mask, ++ enum nl80211_band band) ++{ ++ struct ath11k *ar = arvif->ar; ++ u8 he_rate, nss; ++ u32 rate_code; ++ int ret, i; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ nss = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { ++ if (hweight16(mask->control[band].he_mcs[i]) == 1) { ++ nss = i + 1; ++ he_rate = ffs(mask->control[band].he_mcs[i]) - 1; ++ } ++ } ++ ++ if (!nss) { ++ ath11k_warn(ar->ab, "No single he fixed rate found to set for %pM", ++ sta->addr); ++ return -EINVAL; ++ } ++ ++ /* Avoid updating invalid nss as fixed rate */ ++ if (nss > sta->rx_nss) ++ return -EINVAL; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac setting fixed he rate for peer %pM, device will not switch to any other selected rates", ++ sta->addr); ++ ++ rate_code = ATH11K_HW_RATE_CODE(he_rate, nss - 1, ++ WMI_RATE_PREAMBLE_HE); ++ ++ ret = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_PARAM_FIXED_RATE, ++ rate_code); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to update sta %pM fixed rate %d: %d\n", ++ sta->addr, rate_code, ret); ++ ++ return ret; ++} ++ + static int ath11k_station_assoc(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -3303,7 +3543,7 @@ static int ath11k_station_assoc(struct a + struct cfg80211_chan_def def; + enum nl80211_band band; + struct cfg80211_bitrate_mask *mask; +- u8 num_vht_rates; ++ u8 num_vht_rates, num_he_rates; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -3329,9 +3569,10 @@ static int ath11k_station_assoc(struct a + } + + num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask); ++ num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask); + +- /* If single VHT rate is configured (by set_bitrate_mask()), +- * peer_assoc will disable VHT. This is now enabled by a peer specific ++ /* If single VHT/HE rate is configured (by set_bitrate_mask()), ++ * peer_assoc will disable VHT/HE. This is now enabled by a peer specific + * fixed param. + * Note that all other rates and NSS will be disabled for this peer. + */ +@@ -3340,6 +3581,11 @@ static int ath11k_station_assoc(struct a + band); + if (ret) + return ret; ++ } else if (sta->he_cap.has_he && num_he_rates == 1) { ++ ret = ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, ++ band); ++ if (ret) ++ return ret; + } + + /* Re-assoc is run only to update supported rates for given station. It +@@ -3410,8 +3656,9 @@ static void ath11k_sta_rc_update_wk(stru + enum nl80211_band band; + const u8 *ht_mcs_mask; + const u16 *vht_mcs_mask; ++ const u16 *he_mcs_mask; + u32 changed, bw, nss, smps; +- int err, num_vht_rates; ++ int err, num_vht_rates, num_he_rates; + const struct cfg80211_bitrate_mask *mask; + struct peer_assoc_params peer_arg; + +@@ -3426,6 +3673,7 @@ static void ath11k_sta_rc_update_wk(stru + band = def.chan->band; + ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; + vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; ++ he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + spin_lock_bh(&ar->data_lock); + +@@ -3441,8 +3689,9 @@ static void ath11k_sta_rc_update_wk(stru + mutex_lock(&ar->conf_mutex); + + nss = max_t(u32, 1, nss); +- nss = min(nss, max(ath11k_mac_max_ht_nss(ht_mcs_mask), +- ath11k_mac_max_vht_nss(vht_mcs_mask))); ++ nss = min(nss, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), ++ ath11k_mac_max_vht_nss(vht_mcs_mask)), ++ ath11k_mac_max_he_nss(he_mcs_mask))); + + if (changed & IEEE80211_RC_BW_CHANGED) { + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, +@@ -3478,6 +3727,8 @@ static void ath11k_sta_rc_update_wk(stru + mask = &arvif->bitrate_mask; + num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, + mask); ++ num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, ++ mask); + + /* Peer_assoc_prepare will reject vht rates in + * bitrate_mask if its not available in range format and +@@ -3493,11 +3744,25 @@ static void ath11k_sta_rc_update_wk(stru + if (sta->vht_cap.vht_supported && num_vht_rates == 1) { + ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, + band); ++ } else if (sta->he_cap.has_he && num_he_rates == 1) { ++ ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, ++ band); + } else { +- /* If the peer is non-VHT or no fixed VHT rate ++ /* If the peer is non-VHT/HE or no fixed VHT/HE rate + * is provided in the new bitrate mask we set the +- * other rates using peer_assoc command. ++ * other rates using peer_assoc command. Also clear ++ * the peer fixed rate settings as it has higher proprity ++ * than peer assoc + */ ++ err = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_PARAM_FIXED_RATE, ++ WMI_FIXED_RATE_NONE); ++ if (err) ++ ath11k_warn(ar->ab, ++ "failed to disable peer fixed rate for sta %pM: %d\n", ++ sta->addr, err); ++ + ath11k_peer_assoc_prepare(ar, arvif->vif, sta, + &peer_arg, true); + +@@ -5111,10 +5376,13 @@ static int ath11k_mac_op_add_interface(s + + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { + arvif->bitrate_mask.control[i].legacy = 0xffffffff; ++ arvif->bitrate_mask.control[i].gi = NL80211_TXRATE_FORCE_SGI; + memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].ht_mcs)); + memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].vht_mcs)); ++ memset(arvif->bitrate_mask.control[i].he_mcs, 0xff, ++ sizeof(arvif->bitrate_mask.control[i].he_mcs)); + } + + bit = __ffs64(ab->free_vdev_map); +@@ -6190,9 +6458,26 @@ ath11k_mac_has_single_legacy_rate(struct + if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask)) + return false; + ++ if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask)) ++ return false; ++ + return num_rates == 1; + } + ++static __le16 ++ath11k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap) ++{ ++ if (he_cap->he_cap_elem.phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) ++ return he_cap->he_mcs_nss_supp.tx_mcs_80p80; ++ ++ if (he_cap->he_cap_elem.phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) ++ return he_cap->he_mcs_nss_supp.tx_mcs_160; ++ ++ return he_cap->he_mcs_nss_supp.tx_mcs_80; ++} ++ + static bool + ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar, + enum nl80211_band band, +@@ -6201,8 +6486,10 @@ ath11k_mac_bitrate_mask_get_single_nss(s + { + struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; + u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); ++ u16 he_mcs_map = 0; + u8 ht_nss_mask = 0; + u8 vht_nss_mask = 0; ++ u8 he_nss_mask = 0; + int i; + + /* No need to consider legacy here. Basic rates are always present +@@ -6229,7 +6516,20 @@ ath11k_mac_bitrate_mask_get_single_nss(s + return false; + } + +- if (ht_nss_mask != vht_nss_mask) ++ he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(&sband->iftype_data->he_cap)); ++ ++ for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { ++ if (mask->control[band].he_mcs[i] == 0) ++ continue; ++ ++ if (mask->control[band].he_mcs[i] == ++ ath11k_mac_get_max_he_mcs_map(he_mcs_map, i)) ++ he_nss_mask |= BIT(i); ++ else ++ return false; ++ } ++ ++ if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask) + return false; + + if (ht_nss_mask == 0) +@@ -6276,42 +6576,125 @@ ath11k_mac_get_single_legacy_rate(struct + return 0; + } + +-static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif, +- u32 rate, u8 nss, u8 sgi, u8 ldpc) ++static int ++ath11k_mac_set_fixed_rate_gi_ltf(struct ath11k_vif *arvif, u8 he_gi, u8 he_ltf) + { + struct ath11k *ar = arvif->ar; +- u32 vdev_param; + int ret; + +- lockdep_assert_held(&ar->conf_mutex); ++ /* 0.8 = 0, 1.6 = 2 and 3.2 = 3. */ ++ if (he_gi && he_gi != 0xFF) ++ he_gi += 1; + +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", +- arvif->vdev_id, rate, nss, sgi); ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ WMI_VDEV_PARAM_SGI, he_gi); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set he gi %d: %d\n", ++ he_gi, ret); ++ return ret; ++ } ++ /* start from 1 */ ++ if (he_ltf != 0xFF) ++ he_ltf += 1; + +- vdev_param = WMI_VDEV_PARAM_FIXED_RATE; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- vdev_param, rate); ++ WMI_VDEV_PARAM_HE_LTF, he_ltf); + if (ret) { +- ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", +- rate, ret); ++ ath11k_warn(ar->ab, "failed to set he ltf %d: %d\n", ++ he_ltf, ret); + return ret; + } + +- vdev_param = WMI_VDEV_PARAM_NSS; ++ return 0; ++} ++ ++static int ++ath11k_mac_set_auto_rate_gi_ltf(struct ath11k_vif *arvif, u16 he_gi, u8 he_ltf) ++{ ++ struct ath11k *ar = arvif->ar; ++ int ret; ++ u32 he_ar_gi_ltf; ++ ++ if (he_gi != 0xFF) { ++ switch (he_gi) { ++ case NL80211_RATE_INFO_HE_GI_0_8: ++ he_gi = WMI_AUTORATE_800NS_GI; ++ break; ++ case NL80211_RATE_INFO_HE_GI_1_6: ++ he_gi = WMI_AUTORATE_1600NS_GI; ++ break; ++ case NL80211_RATE_INFO_HE_GI_3_2: ++ he_gi = WMI_AUTORATE_3200NS_GI; ++ break; ++ default: ++ ath11k_warn(ar->ab, "invalid he gi: %d\n", he_gi); ++ return -EINVAL; ++ } ++ } ++ ++ if (he_ltf != 0xFF) { ++ switch (he_ltf) { ++ case NL80211_RATE_INFO_HE_1XLTF: ++ he_ltf = WMI_HE_AUTORATE_LTF_1X; ++ break; ++ case NL80211_RATE_INFO_HE_2XLTF: ++ he_ltf = WMI_HE_AUTORATE_LTF_2X; ++ break; ++ case NL80211_RATE_INFO_HE_4XLTF: ++ he_ltf = WMI_HE_AUTORATE_LTF_4X; ++ break; ++ default: ++ ath11k_warn(ar->ab, "invalid he ltf: %d\n", he_ltf); ++ return -EINVAL; ++ } ++ } ++ ++ he_ar_gi_ltf = he_gi | he_ltf; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- vdev_param, nss); ++ WMI_VDEV_PARAM_AUTORATE_MISC_CFG, ++ he_ar_gi_ltf); + if (ret) { +- ath11k_warn(ar->ab, "failed to set nss param %d: %d\n", +- nss, ret); ++ ath11k_warn(ar->ab, ++ "failed to set he autorate gi %u ltf %u: %d\n", ++ he_gi, he_ltf, ret); + return ret; + } + +- vdev_param = WMI_VDEV_PARAM_SGI; ++ return 0; ++} ++ ++static int ath11k_mac_set_rate_params(struct ath11k_vif *arvif, ++ u32 rate, u8 nss, u8 sgi, u8 ldpc, ++ u8 he_gi, u8 he_ltf, bool he_fixed_rate) ++{ ++ struct ath11k *ar = arvif->ar; ++ u32 vdev_param; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", ++ arvif->vdev_id, rate, nss, sgi, ldpc, he_gi, ++ he_ltf, he_fixed_rate); ++ ++ if (!arvif->vif->bss_conf.he_support) { ++ vdev_param = WMI_VDEV_PARAM_FIXED_RATE; ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ vdev_param, rate); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", ++ rate, ret); ++ return ret; ++ } ++ } ++ ++ vdev_param = WMI_VDEV_PARAM_NSS; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- vdev_param, sgi); ++ vdev_param, nss); + if (ret) { +- ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n", +- sgi, ret); ++ ath11k_warn(ar->ab, "failed to set nss param %d: %d\n", ++ nss, ret); + return ret; + } + +@@ -6324,6 +6707,35 @@ static int ath11k_mac_set_fixed_rate_par + return ret; + } + ++ if (arvif->vif->bss_conf.he_support) { ++ if (he_fixed_rate) { ++ ret = ath11k_mac_set_fixed_rate_gi_ltf(arvif, he_gi, ++ he_ltf); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set fixed rate gi ltf: %d\n", ++ ret); ++ return ret; ++ } ++ } else { ++ ret = ath11k_mac_set_auto_rate_gi_ltf(arvif, he_gi, ++ he_ltf); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set auto rate gi ltf: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ } else { ++ vdev_param = WMI_VDEV_PARAM_SGI; ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ vdev_param, sgi); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n", ++ sgi, ret); ++ return ret; ++ } ++ } ++ + return 0; + } + +@@ -6352,6 +6764,31 @@ ath11k_mac_vht_mcs_range_present(struct + return true; + } + ++static bool ++ath11k_mac_he_mcs_range_present(struct ath11k *ar, ++ enum nl80211_band band, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ int i; ++ u16 he_mcs; ++ ++ for (i = 0; i < NL80211_HE_NSS_MAX; i++) { ++ he_mcs = mask->control[band].he_mcs[i]; ++ ++ switch (he_mcs) { ++ case 0: ++ case BIT(8) - 1: ++ case BIT(10) - 1: ++ case BIT(12) - 1: ++ break; ++ default: ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static void ath11k_mac_set_bitrate_mask_iter(void *data, + struct ieee80211_sta *sta) + { +@@ -6383,6 +6820,54 @@ static void ath11k_mac_disable_peer_fixe + sta->addr, ret); + } + ++static bool ++ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_band band, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ bool he_fixed_rate = false, vht_fixed_rate = false; ++ struct ath11k_peer *peer, *tmp; ++ const u16 *vht_mcs_mask, *he_mcs_mask; ++ u8 vht_nss, he_nss; ++ bool ret = true; ++ ++ vht_mcs_mask = mask->control[band].vht_mcs; ++ he_mcs_mask = mask->control[band].he_mcs; ++ ++ if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask) == 1) ++ vht_fixed_rate = true; ++ ++ if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask) == 1) ++ he_fixed_rate = true; ++ ++ if (!vht_fixed_rate && !he_fixed_rate) ++ return true; ++ ++ vht_nss = ath11k_mac_max_vht_nss(vht_mcs_mask); ++ he_nss = ath11k_mac_max_he_nss(he_mcs_mask); ++ ++ rcu_read_lock(); ++ spin_lock_bh(&ar->ab->base_lock); ++ list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) { ++ if (peer->sta) { ++ if (vht_fixed_rate && (!peer->sta->vht_cap.vht_supported || ++ peer->sta->rx_nss < vht_nss)) { ++ ret = false; ++ goto out; ++ } ++ if (he_fixed_rate && (!peer->sta->he_cap.has_he || ++ peer->sta->rx_nss < he_nss)) { ++ ret = false; ++ goto out; ++ } ++ } ++ } ++ ++out: ++ spin_unlock_bh(&ar->ab->base_lock); ++ rcu_read_unlock(); ++ return ret; ++} ++ + static int + ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -6394,6 +6879,9 @@ ath11k_mac_op_set_bitrate_mask(struct ie + enum nl80211_band band; + const u8 *ht_mcs_mask; + const u16 *vht_mcs_mask; ++ const u16 *he_mcs_mask; ++ u8 he_ltf = 0; ++ u8 he_gi = 0; + u32 rate; + u8 nss; + u8 sgi; +@@ -6401,6 +6889,7 @@ ath11k_mac_op_set_bitrate_mask(struct ie + int single_nss; + int ret; + int num_rates; ++ bool he_fixed_rate = false; + + if (ath11k_mac_vif_chan(vif, &def)) + return -EPERM; +@@ -6408,12 +6897,16 @@ ath11k_mac_op_set_bitrate_mask(struct ie + band = def.chan->band; + ht_mcs_mask = mask->control[band].ht_mcs; + vht_mcs_mask = mask->control[band].vht_mcs; ++ he_mcs_mask = mask->control[band].he_mcs; + ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); + + sgi = mask->control[band].gi; + if (sgi == NL80211_TXRATE_FORCE_LGI) + return -EINVAL; + ++ he_gi = mask->control[band].he_gi; ++ he_ltf = mask->control[band].he_ltf; ++ + /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it + * requires passing atleast one of used basic rates along with them. + * Fixed rate setting across different preambles(legacy, HT, VHT) is +@@ -6437,11 +6930,22 @@ ath11k_mac_op_set_bitrate_mask(struct ie + &single_nss)) { + rate = WMI_FIXED_RATE_NONE; + nss = single_nss; ++ mutex_lock(&ar->conf_mutex); ++ arvif->bitrate_mask = *mask; ++ ieee80211_iterate_stations_atomic(ar->hw, ++ ath11k_mac_set_bitrate_mask_iter, ++ arvif); ++ mutex_unlock(&ar->conf_mutex); + } else { + rate = WMI_FIXED_RATE_NONE; ++ ++ if (!ath11k_mac_validate_vht_he_fixed_rate_settings(ar, band, mask)) ++ ath11k_warn(ar->ab, ++ "could not update fixed rate settings to all peers due to mcs/nss incompaitiblity\n"); + nss = min_t(u32, ar->num_tx_chains, +- max(ath11k_mac_max_ht_nss(ht_mcs_mask), +- ath11k_mac_max_vht_nss(vht_mcs_mask))); ++ max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), ++ ath11k_mac_max_vht_nss(vht_mcs_mask)), ++ ath11k_mac_max_he_nss(he_mcs_mask))); + + /* If multiple rates across different preambles are given + * we can reconfigure this info with all peers using PEER_ASSOC +@@ -6472,16 +6976,28 @@ ath11k_mac_op_set_bitrate_mask(struct ie + * RATEMASK CMD + */ + ath11k_warn(ar->ab, +- "Setting more than one MCS Value in bitrate mask not supported\n"); ++ "setting %d mcs values in bitrate mask not supported\n", ++ num_rates); + return -EINVAL; + } + ++ num_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, ++ mask); ++ if (num_rates == 1) ++ he_fixed_rate = true; ++ ++ if (!ath11k_mac_he_mcs_range_present(ar, band, mask) && ++ num_rates > 1) { ++ ath11k_warn(ar->ab, ++ "Setting more than one HE MCS Value in bitrate mask not supported\n"); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&ar->conf_mutex); + ieee80211_iterate_stations_atomic(ar->hw, + ath11k_mac_disable_peer_fixed_rate, + arvif); + +- mutex_lock(&ar->conf_mutex); +- + arvif->bitrate_mask = *mask; + ieee80211_iterate_stations_atomic(ar->hw, + ath11k_mac_set_bitrate_mask_iter, +@@ -6492,9 +7008,10 @@ ath11k_mac_op_set_bitrate_mask(struct ie + + mutex_lock(&ar->conf_mutex); + +- ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); ++ ret = ath11k_mac_set_rate_params(arvif, rate, nss, sgi, ldpc, he_gi, ++ he_ltf, he_fixed_rate); + if (ret) { +- ath11k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", ++ ath11k_warn(ar->ab, "failed to set rate params on vdev %i: %d\n", + arvif->vdev_id, ret); + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1905,8 +1905,8 @@ int ath11k_wmi_send_peer_assoc_cmd(struc + FIELD_PREP(WMI_TLV_LEN, + sizeof(*he_mcs) - TLV_HDR_SIZE); + +- he_mcs->rx_mcs_set = param->peer_he_rx_mcs_set[i]; +- he_mcs->tx_mcs_set = param->peer_he_tx_mcs_set[i]; ++ he_mcs->rx_mcs_set = param->peer_he_tx_mcs_set[i]; ++ he_mcs->tx_mcs_set = param->peer_he_rx_mcs_set[i]; + ptr += sizeof(*he_mcs); + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -119,6 +119,22 @@ enum { + WMI_HOST_WLAN_2G_5G_CAP = 0x3, + }; + ++/* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. ++ * Used only for HE auto rate mode. ++ */ ++enum { ++ /* HE LTF related configuration */ ++ WMI_HE_AUTORATE_LTF_1X = BIT(0), ++ WMI_HE_AUTORATE_LTF_2X = BIT(1), ++ WMI_HE_AUTORATE_LTF_4X = BIT(2), ++ ++ /* HE GI related configuration */ ++ WMI_AUTORATE_400NS_GI = BIT(8), ++ WMI_AUTORATE_800NS_GI = BIT(9), ++ WMI_AUTORATE_1600NS_GI = BIT(10), ++ WMI_AUTORATE_3200NS_GI = BIT(11), ++}; ++ + /* + * wmi command groups. + */ +@@ -1044,7 +1060,9 @@ enum wmi_tlv_vdev_param { + WMI_VDEV_PARAM_HE_RANGE_EXT, + WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, + WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, ++ WMI_VDEV_PARAM_HE_LTF = 0x74, + WMI_VDEV_PARAM_BA_MODE = 0x7e, ++ WMI_VDEV_PARAM_AUTORATE_MISC_CFG = 0x80, + WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, + WMI_VDEV_PARAM_6GHZ_PARAMS = 0x99, + WMI_VDEV_PARAM_PROTOTYPE = 0x8000, +@@ -3920,7 +3938,11 @@ struct wmi_vht_rate_set { + + struct wmi_he_rate_set { + u32 tlv_header; ++ ++ /* MCS at which the peer can receive */ + u32 rx_mcs_set; ++ ++ /* MCS at which the peer can transmit */ + u32 tx_mcs_set; + } __packed; + diff --git a/package/kernel/mac80211/patches/ath11k/0009-wifi-ath11k-Send-PME-message-during-wakeup-from-D3co.patch b/package/kernel/mac80211/patches/ath11k/0009-wifi-ath11k-Send-PME-message-during-wakeup-from-D3co.patch deleted file mode 100644 index 1e04c974f..000000000 --- a/package/kernel/mac80211/patches/ath11k/0009-wifi-ath11k-Send-PME-message-during-wakeup-from-D3co.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 3f9b09ccf7d5f23066b02881a737bee42def9d1a Mon Sep 17 00:00:00 2001 -From: Baochen Qiang -Date: Mon, 10 Oct 2022 11:32:37 +0800 -Subject: [PATCH 9/9] wifi: ath11k: Send PME message during wakeup from D3cold - -We are seeing system stuck on some specific platforms due to -WLAN chip fails to wakeup from D3cold state. - -With this flag, firmware will send PME message during wakeup -and this issue is gone. - -Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 - -Signed-off-by: Baochen Qiang -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221010033237.415478-1-quic_bqiang@quicinc.com ---- - drivers/net/wireless/ath/ath11k/qmi.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/net/wireless/ath/ath11k/qmi.c -+++ b/drivers/net/wireless/ath/ath11k/qmi.c -@@ -19,6 +19,7 @@ - #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 - #define HOST_CSTATE_BIT 0x04 - #define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08 -+#define PLATFORM_CAP_PCIE_PME_D3COLD 0x10 - - #define FW_BUILD_ID_MASK "QC_IMAGE_VERSION_STRING=" - -@@ -1752,6 +1753,8 @@ static int ath11k_qmi_host_cap_send(stru - if (ab->hw_params.global_reset) - req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET; - -+ req.nm_modem |= PLATFORM_CAP_PCIE_PME_D3COLD; -+ - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi host cap request\n"); - - ret = qmi_txn_init(&ab->qmi.handle, &txn, diff --git a/package/kernel/mac80211/patches/ath11k/0010-ath11k-add-support-for-80P80-and-160-MHz-bandwidth.patch b/package/kernel/mac80211/patches/ath11k/0010-ath11k-add-support-for-80P80-and-160-MHz-bandwidth.patch new file mode 100644 index 000000000..1b3dddb30 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0010-ath11k-add-support-for-80P80-and-160-MHz-bandwidth.patch @@ -0,0 +1,322 @@ +From f552d6fd2f27ce9430c74482c46272838e2de688 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH] ath11k: add support for 80P80 and 160 MHz bandwidth + +For 160 MHz, nss_ratio_enabled flag is added to indicate firmware +supports sending NSS ratio information from firmware as a part of +service ready ext event. Extract this NSS ratio info from service +ready ext event and save this information in ath11k_pdev_cap to +calculate NSS ratio. + +Current firmware configurations support two types of NSS ratio +which is WMI_NSS_RATIO_1_NSS for QCN9074 and WMI_NSS_RATIO_1BY2_NSS +for IPQ8074. Based on this two configuration, max supported +NSS getting calculated. + +Move ath11k_peer_assoc_h_phymode() before ath11k_peer_assoc_h_vht() +to get arg->peer_phymode updated. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-00097-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Ganesh Sesetti +Signed-off-by: Ganesh Sesetti +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: P Praneesh +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721173615.75637-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 2 + + drivers/net/wireless/ath/ath11k/mac.c | 95 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/mac.h | 3 + + drivers/net/wireless/ath/ath11k/wmi.c | 20 +++++- + drivers/net/wireless/ath/ath11k/wmi.h | 30 ++++++++ + 5 files changed, 136 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -603,6 +603,8 @@ struct ath11k_pdev_cap { + u32 tx_chain_mask_shift; + u32 rx_chain_mask_shift; + struct ath11k_band_cap band[NUM_NL80211_BANDS]; ++ bool nss_ratio_enabled; ++ u8 nss_ratio_info; + }; + + struct ath11k_pdev { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1586,6 +1586,34 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs + return tx_mcs_set; + } + ++static u8 ath11k_get_nss_160mhz(struct ath11k *ar, ++ u8 max_nss) ++{ ++ u8 nss_ratio_info = ar->pdev->cap.nss_ratio_info; ++ u8 max_sup_nss = 0; ++ ++ switch (nss_ratio_info) { ++ case WMI_NSS_RATIO_1BY2_NSS: ++ max_sup_nss = max_nss >> 1; ++ break; ++ case WMI_NSS_RATIO_3BY4_NSS: ++ ath11k_warn(ar->ab, "WMI_NSS_RATIO_3BY4_NSS not supported\n"); ++ break; ++ case WMI_NSS_RATIO_1_NSS: ++ max_sup_nss = max_nss; ++ break; ++ case WMI_NSS_RATIO_2_NSS: ++ ath11k_warn(ar->ab, "WMI_NSS_RATIO_2_NSS not supported\n"); ++ break; ++ default: ++ ath11k_warn(ar->ab, "invalid nss ratio received from firmware: %d\n", ++ nss_ratio_info); ++ break; ++ } ++ ++ return max_sup_nss; ++} ++ + static void ath11k_peer_assoc_h_vht(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -1600,6 +1628,7 @@ static void ath11k_peer_assoc_h_vht(stru + u8 max_nss, vht_mcs; + int i, vht_nss, nss_idx; + bool user_rate_valid = true; ++ u32 rx_nss, tx_nss, nss_160; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1692,10 +1721,29 @@ static void ath11k_peer_assoc_h_vht(stru + /* TODO: Check */ + arg->tx_max_mcs_nss = 0xFF; + +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", +- sta->addr, arg->peer_max_mpdu, arg->peer_flags); ++ if (arg->peer_phymode == MODE_11AC_VHT160 || ++ arg->peer_phymode == MODE_11AC_VHT80_80) { ++ tx_nss = ath11k_get_nss_160mhz(ar, max_nss); ++ rx_nss = min(arg->peer_nss, tx_nss); ++ arg->peer_bw_rxnss_override = ATH11K_BW_NSS_MAP_ENABLE; ++ ++ if (!rx_nss) { ++ ath11k_warn(ar->ab, "invalid max_nss\n"); ++ return; ++ } ++ ++ if (arg->peer_phymode == MODE_11AC_VHT160) ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_160MHZ, rx_nss - 1); ++ else ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_80_80MHZ, rx_nss - 1); + +- /* TODO: rxnss_override */ ++ arg->peer_bw_rxnss_override |= nss_160; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n", ++ sta->addr, arg->peer_max_mpdu, arg->peer_flags, ++ arg->peer_bw_rxnss_override); + } + + static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) +@@ -1779,6 +1827,7 @@ static void ath11k_peer_assoc_h_he(struc + u16 he_tx_mcs = 0, v = 0; + int i, he_nss, nss_idx; + bool user_rate_valid = true; ++ u32 rx_nss, tx_nss, nss_160; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1942,9 +1991,30 @@ static void ath11k_peer_assoc_h_he(struc + } + arg->peer_nss = min(sta->rx_nss, max_nss); + ++ if (arg->peer_phymode == MODE_11AX_HE160 || ++ arg->peer_phymode == MODE_11AX_HE80_80) { ++ tx_nss = ath11k_get_nss_160mhz(ar, max_nss); ++ rx_nss = min(arg->peer_nss, tx_nss); ++ arg->peer_bw_rxnss_override = ATH11K_BW_NSS_MAP_ENABLE; ++ ++ if (!rx_nss) { ++ ath11k_warn(ar->ab, "invalid max_nss\n"); ++ return; ++ } ++ ++ if (arg->peer_phymode == MODE_11AX_HE160) ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_160MHZ, rx_nss - 1); ++ else ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_80_80MHZ, rx_nss - 1); ++ ++ arg->peer_bw_rxnss_override |= nss_160; ++ } ++ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "mac he peer %pM nss %d mcs cnt %d\n", +- sta->addr, arg->peer_nss, arg->peer_he_mcs_count); ++ "mac he peer %pM nss %d mcs cnt %d nss_override 0x%x\n", ++ sta->addr, arg->peer_nss, ++ arg->peer_he_mcs_count, ++ arg->peer_bw_rxnss_override); + } + + static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, +@@ -2232,11 +2302,11 @@ static void ath11k_peer_assoc_prepare(st + ath11k_peer_assoc_h_basic(ar, vif, sta, arg); + ath11k_peer_assoc_h_crypto(ar, vif, sta, arg); + ath11k_peer_assoc_h_rates(ar, vif, sta, arg); ++ ath11k_peer_assoc_h_phymode(ar, vif, sta, arg); + ath11k_peer_assoc_h_ht(ar, vif, sta, arg); + ath11k_peer_assoc_h_vht(ar, vif, sta, arg); + ath11k_peer_assoc_h_he(ar, vif, sta, arg); + ath11k_peer_assoc_h_qos(ar, vif, sta, arg); +- ath11k_peer_assoc_h_phymode(ar, vif, sta, arg); + ath11k_peer_assoc_h_smps(sta, arg); + + /* TODO: amsdu_disable req? */ +@@ -4433,11 +4503,6 @@ ath11k_create_vht_cap(struct ath11k *ar, + + ath11k_set_vht_txbf_cap(ar, &vht_cap.cap); + +- /* TODO: Enable back VHT160 mode once association issues are fixed */ +- /* Disabling VHT160 and VHT80+80 modes */ +- vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; +- vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; +- + rxmcs_map = 0; + txmcs_map = 0; + for (i = 0; i < 8; i++) { +@@ -7355,7 +7420,9 @@ static int ath11k_mac_setup_iface_combin + combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | +- BIT(NL80211_CHAN_WIDTH_80); ++ BIT(NL80211_CHAN_WIDTH_80) | ++ BIT(NL80211_CHAN_WIDTH_80P80) | ++ BIT(NL80211_CHAN_WIDTH_160); + + ar->hw->wiphy->iface_combinations = combinations; + ar->hw->wiphy->n_iface_combinations = 1; +@@ -7494,6 +7561,10 @@ static int __ath11k_mac_register(struct + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ++ if (cap->nss_ratio_enabled) ++ ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW); ++ + if (ht_cap & WMI_HT_CAP_ENABLED) { + ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -115,6 +115,9 @@ struct ath11k_generic_iter { + #define WMI_MAX_SPATIAL_STREAM 3 + + #define ATH11K_CHAN_WIDTH_NUM 8 ++#define ATH11K_BW_NSS_MAP_ENABLE BIT(31) ++#define ATH11K_PEER_RX_NSS_160MHZ GENMASK(2, 0) ++#define ATH11K_PEER_RX_NSS_80_80MHZ GENMASK(5, 3) + + #define ATH11K_OBSS_PD_MAX_THRESHOLD -82 + #define ATH11K_OBSS_PD_NON_SRG_MAX_THRESHOLD -62 +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -360,6 +360,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + pdev_cap->he_mcs = mac_phy_caps->he_supp_mcs_5g; + pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_5g; + pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_5g; ++ pdev_cap->nss_ratio_enabled = ++ WMI_NSS_RATIO_ENABLE_DISABLE_GET(mac_phy_caps->nss_ratio); ++ pdev_cap->nss_ratio_info = ++ WMI_NSS_RATIO_INFO_GET(mac_phy_caps->nss_ratio); + } else { + return -EINVAL; + } +@@ -783,14 +787,26 @@ int ath11k_wmi_vdev_down(struct ath11k * + static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan, + struct wmi_vdev_start_req_arg *arg) + { ++ u32 center_freq1 = arg->channel.band_center_freq1; ++ + memset(chan, 0, sizeof(*chan)); + + chan->mhz = arg->channel.freq; + chan->band_center_freq1 = arg->channel.band_center_freq1; +- if (arg->channel.mode == MODE_11AC_VHT80_80) ++ ++ if (arg->channel.mode == MODE_11AX_HE160) { ++ if (arg->channel.freq > arg->channel.band_center_freq1) ++ chan->band_center_freq1 = center_freq1 + 40; ++ else ++ chan->band_center_freq1 = center_freq1 - 40; ++ ++ chan->band_center_freq2 = arg->channel.band_center_freq1; ++ ++ } else if (arg->channel.mode == MODE_11AC_VHT80_80) { + chan->band_center_freq2 = arg->channel.band_center_freq2; +- else ++ } else { + chan->band_center_freq2 = 0; ++ } + + chan->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, arg->channel.mode); + if (arg->channel.passive) +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2146,6 +2146,24 @@ enum wmi_direct_buffer_module { + WMI_DIRECT_BUF_MAX + }; + ++/* enum wmi_nss_ratio - NSS ratio received from FW during service ready ext ++ * event ++ * WMI_NSS_RATIO_1BY2_NSS -Max nss of 160MHz is equals to half of the max nss ++ * of 80MHz ++ * WMI_NSS_RATIO_3BY4_NSS - Max nss of 160MHz is equals to 3/4 of the max nss ++ * of 80MHz ++ * WMI_NSS_RATIO_1_NSS - Max nss of 160MHz is equals to the max nss of 80MHz ++ * WMI_NSS_RATIO_2_NSS - Max nss of 160MHz is equals to two times the max ++ * nss of 80MHz ++ */ ++ ++enum wmi_nss_ratio { ++ WMI_NSS_RATIO_1BY2_NSS = 0x0, ++ WMI_NSS_RATIO_3BY4_NSS = 0x1, ++ WMI_NSS_RATIO_1_NSS = 0x2, ++ WMI_NSS_RATIO_2_NSS = 0x3, ++}; ++ + struct wmi_host_pdev_band_to_mac { + u32 pdev_id; + u32 start_freq; +@@ -2390,6 +2408,12 @@ struct wmi_hw_mode_capabilities { + } __packed; + + #define WMI_MAX_HECAP_PHY_SIZE (3) ++#define WMI_NSS_RATIO_ENABLE_DISABLE_BITPOS BIT(0) ++#define WMI_NSS_RATIO_ENABLE_DISABLE_GET(_val) \ ++ FIELD_GET(WMI_NSS_RATIO_ENABLE_DISABLE_BITPOS, _val) ++#define WMI_NSS_RATIO_INFO_BITPOS GENMASK(4, 1) ++#define WMI_NSS_RATIO_INFO_GET(_val) \ ++ FIELD_GET(WMI_NSS_RATIO_INFO_BITPOS, _val) + + struct wmi_mac_phy_capabilities { + u32 hw_mode_id; +@@ -2423,6 +2447,12 @@ struct wmi_mac_phy_capabilities { + u32 he_cap_info_2g_ext; + u32 he_cap_info_5g_ext; + u32 he_cap_info_internal; ++ u32 wireless_modes; ++ u32 low_2ghz_chan_freq; ++ u32 high_2ghz_chan_freq; ++ u32 low_5ghz_chan_freq; ++ u32 high_5ghz_chan_freq; ++ u32 nss_ratio; + } __packed; + + struct wmi_hal_reg_capabilities_ext { diff --git a/package/kernel/mac80211/patches/ath11k/0010-wifi-ath11k-Fix-firmware-crash-on-vdev-delete-race-c.patch b/package/kernel/mac80211/patches/ath11k/0010-wifi-ath11k-Fix-firmware-crash-on-vdev-delete-race-c.patch deleted file mode 100644 index 7275af06e..000000000 --- a/package/kernel/mac80211/patches/ath11k/0010-wifi-ath11k-Fix-firmware-crash-on-vdev-delete-race-c.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 3811fa1f231f1a3e29759efef4992116604aab8b Mon Sep 17 00:00:00 2001 -From: Sowmiya Sree Elavalagan -Date: Tue, 11 Oct 2022 15:23:46 +0530 -Subject: [PATCH] wifi: ath11k: Fix firmware crash on vdev delete race - condition - -Current code does not wait for vdev delete completion on vdev create -failures and tries to send another vdev create followed by vdev set -param to firmware with same vdev id. This causes firmware crash. -Fix this crash by waiting for vdev delete completion on vdev -create failures. - -Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.6.0.1-00905-QCAHKSWPL_SILICONZ-1 - -Signed-off-by: Sowmiya Sree Elavalagan -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221011095346.3901-1-quic_ssreeela@quicinc.com ---- - drivers/net/wireless/ath/ath11k/mac.c | 60 +++++++++++++++++---------- - 1 file changed, 37 insertions(+), 23 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/mac.c -+++ b/drivers/net/wireless/ath/ath11k/mac.c -@@ -6233,6 +6233,40 @@ void ath11k_mac_11d_scan_stop_all(struct - } - } - -+static int ath11k_mac_vdev_delete(struct ath11k *ar, struct ath11k_vif *arvif) -+{ -+ unsigned long time_left; -+ struct ieee80211_vif *vif = arvif->vif; -+ int ret = 0; -+ -+ lockdep_assert_held(&ar->conf_mutex); -+ -+ reinit_completion(&ar->vdev_delete_done); -+ -+ ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id); -+ if (ret) { -+ ath11k_warn(ar->ab, "failed to delete WMI vdev %d: %d\n", -+ arvif->vdev_id, ret); -+ return ret; -+ } -+ -+ time_left = wait_for_completion_timeout(&ar->vdev_delete_done, -+ ATH11K_VDEV_DELETE_TIMEOUT_HZ); -+ if (time_left == 0) { -+ ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n"); -+ return -ETIMEDOUT; -+ } -+ -+ ar->ab->free_vdev_map |= 1LL << (arvif->vdev_id); -+ ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); -+ ar->num_created_vdevs--; -+ -+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", -+ vif->addr, arvif->vdev_id); -+ -+ return ret; -+} -+ - static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) - { -@@ -6468,10 +6502,7 @@ err_peer_del: - } - - err_vdev_del: -- ath11k_wmi_vdev_delete(ar, arvif->vdev_id); -- ar->num_created_vdevs--; -- ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); -- ab->free_vdev_map |= 1LL << arvif->vdev_id; -+ ath11k_mac_vdev_delete(ar, arvif); - spin_lock_bh(&ar->data_lock); - list_del(&arvif->list); - spin_unlock_bh(&ar->data_lock); -@@ -6499,7 +6530,6 @@ static void ath11k_mac_op_remove_interfa - struct ath11k *ar = hw->priv; - struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_base *ab = ar->ab; -- unsigned long time_left; - int ret; - int i; - -@@ -6520,29 +6550,13 @@ static void ath11k_mac_op_remove_interfa - arvif->vdev_id, ret); - } - -- reinit_completion(&ar->vdev_delete_done); -- -- ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id); -+ ret = ath11k_mac_vdev_delete(ar, arvif); - if (ret) { -- ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n", -+ ath11k_warn(ab, "failed to delete vdev %d: %d\n", - arvif->vdev_id, ret); - goto err_vdev_del; - } - -- time_left = wait_for_completion_timeout(&ar->vdev_delete_done, -- ATH11K_VDEV_DELETE_TIMEOUT_HZ); -- if (time_left == 0) { -- ath11k_warn(ab, "Timeout in receiving vdev delete response\n"); -- goto err_vdev_del; -- } -- -- ab->free_vdev_map |= 1LL << (arvif->vdev_id); -- ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); -- ar->num_created_vdevs--; -- -- ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", -- vif->addr, arvif->vdev_id); -- - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { - clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); - ar->monitor_vdev_id = -1; diff --git a/package/kernel/mac80211/patches/ath11k/0011-ath11k-Refactor-spectral-FFT-bin-size.patch b/package/kernel/mac80211/patches/ath11k/0011-ath11k-Refactor-spectral-FFT-bin-size.patch new file mode 100644 index 000000000..c7dc058d1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0011-ath11k-Refactor-spectral-FFT-bin-size.patch @@ -0,0 +1,165 @@ +From cc2ad7541486f1f755949c1ccd17e14a15bf1f4e Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH] ath11k: Refactor spectral FFT bin size + +In IPQ8074, actual FFT bin size is two bytes but hardware reports it +with extra pad size of two bytes for each FFT bin. So finally each FFT +bin advertise as four bytes size in the collected data. This FFT pad is +not advertised in IPQ6018 platform. To accommodate this different +behavior across the platforms, introduce the hw param fft_pad_sz and use +it in spectral process. Also group all the spectral params under the new +structure in hw param structure for scalable in future. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 33 +++++++++++++++++++--- + drivers/net/wireless/ath/ath11k/hw.h | 6 +++- + drivers/net/wireless/ath/ath11k/spectral.c | 13 ++++----- + 3 files changed, 40 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -59,7 +59,14 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = false, + .htt_peer_map_v2 = true, + .tcl_0_only = false, +- .spectral_fft_sz = 2, ++ ++ .spectral = { ++ .fft_sz = 2, ++ /* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes. ++ * so added pad size as 2 bytes to compensate the BIN size ++ */ ++ .fft_pad_sz = 2, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +@@ -100,7 +107,11 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = false, + .htt_peer_map_v2 = true, + .tcl_0_only = false, +- .spectral_fft_sz = 4, ++ ++ .spectral = { ++ .fft_sz = 4, ++ .fft_pad_sz = 0, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +@@ -141,7 +152,11 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + .tcl_0_only = true, +- .spectral_fft_sz = 0, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), +@@ -180,6 +195,12 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = false, + .htt_peer_map_v2 = true, + .tcl_0_only = false, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ }, ++ + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), +@@ -219,7 +240,11 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + .tcl_0_only = true, +- .spectral_fft_sz = 0, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -153,7 +153,11 @@ struct ath11k_hw_params { + bool vdev_start_delay; + bool htt_peer_map_v2; + bool tcl_0_only; +- u8 spectral_fft_sz; ++ ++ struct { ++ u8 fft_sz; ++ u8 fft_pad_sz; ++ } spectral; + + u16 interface_modes; + bool supports_monitor; +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -11,8 +11,6 @@ + #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + + #define ATH11K_SPECTRAL_DWORD_SIZE 4 +-/* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes */ +-#define ATH11K_SPECTRAL_BIN_SIZE 4 + #define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64 + #define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32 + #define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256 +@@ -585,12 +583,12 @@ int ath11k_spectral_process_fft(struct a + struct spectral_tlv *tlv; + int tlv_len, bin_len, num_bins; + u16 length, freq; +- u8 chan_width_mhz; ++ u8 chan_width_mhz, bin_sz; + int ret; + + lockdep_assert_held(&ar->spectral.lock); + +- if (!ab->hw_params.spectral_fft_sz) { ++ if (!ab->hw_params.spectral.fft_sz) { + ath11k_warn(ab, "invalid bin size type for hw rev %d\n", + ab->hw_rev); + return -EINVAL; +@@ -608,7 +606,8 @@ int ath11k_spectral_process_fft(struct a + return -EINVAL; + } + +- num_bins = bin_len / ATH11K_SPECTRAL_BIN_SIZE; ++ bin_sz = ab->hw_params.spectral.fft_sz + ab->hw_params.spectral.fft_pad_sz; ++ num_bins = bin_len / bin_sz; + /* Only In-band bins are useful to user for visualize */ + num_bins >>= 1; + +@@ -658,7 +657,7 @@ int ath11k_spectral_process_fft(struct a + fft_sample->freq2 = __cpu_to_be16(freq); + + ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins, +- ab->hw_params.spectral_fft_sz); ++ ab->hw_params.spectral.fft_sz); + + fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index, + search.peak_mag, +@@ -966,7 +965,7 @@ int ath11k_spectral_init(struct ath11k_b + ab->wmi_ab.svc_map)) + return 0; + +- if (!ab->hw_params.spectral_fft_sz) ++ if (!ab->hw_params.spectral.fft_sz) + return 0; + + for (i = 0; i < ab->num_radios; i++) { diff --git a/package/kernel/mac80211/patches/ath11k/0011-wifi-ath11k-fix-monitor-vdev-creation-with-firmware-.patch b/package/kernel/mac80211/patches/ath11k/0011-wifi-ath11k-fix-monitor-vdev-creation-with-firmware-.patch deleted file mode 100644 index 2f066d0a5..000000000 --- a/package/kernel/mac80211/patches/ath11k/0011-wifi-ath11k-fix-monitor-vdev-creation-with-firmware-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From f3ca72b0327101a074a871539e61775d43908ca4 Mon Sep 17 00:00:00 2001 -From: Nagarajan Maran -Date: Fri, 14 Oct 2022 21:20:54 +0530 -Subject: [PATCH] wifi: ath11k: fix monitor vdev creation with firmware - recovery - -During firmware recovery, the monitor interface is not -getting created in the driver and firmware since -the respective flags are not updated properly. - -So after firmware recovery is successful, when monitor -interface is brought down manually, firmware assertion -is observed, since we are trying to bring down the -interface which is not yet created in the firmware. - -Fix this by updating the monitor flags properly per -phy#, during firmware recovery. - -Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 - -Signed-off-by: Nagarajan Maran -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221014155054.11471-1-quic_nmaran@quicinc.com ---- - drivers/net/wireless/ath/ath11k/core.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/net/wireless/ath/ath11k/core.c -+++ b/drivers/net/wireless/ath/ath11k/core.c -@@ -1677,6 +1677,10 @@ void ath11k_core_pre_reconfigure_recover - ath11k_mac_tx_mgmt_pending_free, ar); - idr_destroy(&ar->txmgmt_idr); - wake_up(&ar->txmgmt_empty_waitq); -+ -+ ar->monitor_vdev_id = -1; -+ clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); -+ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); - } - - wake_up(&ab->wmi_ab.tx_credits_wq); diff --git a/package/kernel/mac80211/patches/ath11k/0012-ath11k-Introduce-spectral-hw-configurable-param.patch b/package/kernel/mac80211/patches/ath11k/0012-ath11k-Introduce-spectral-hw-configurable-param.patch new file mode 100644 index 000000000..3f2ea13dd --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0012-ath11k-Introduce-spectral-hw-configurable-param.patch @@ -0,0 +1,168 @@ +From 1cae9c0009d35cec94ad8e1b06ebcb2d704626bf Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH] ath11k: Introduce spectral hw configurable param + +Below parameters have been identified as configurable across the platforms. +So to scale the spectral across the platforms, move these parameter +into hw param. + + 1. Maximum FFT bins + 2. Summary report pad size + 3. FFT report header length + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 12 +++++++++ + drivers/net/wireless/ath/ath11k/hw.h | 3 +++ + drivers/net/wireless/ath/ath11k/spectral.c | 29 +++++++++++----------- + 3 files changed, 30 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -66,6 +66,9 @@ static const struct ath11k_hw_params ath + * so added pad size as 2 bytes to compensate the BIN size + */ + .fft_pad_sz = 2, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 16, ++ .max_fft_bins = 512, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +@@ -111,6 +114,9 @@ static const struct ath11k_hw_params ath + .spectral = { + .fft_sz = 4, + .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 16, ++ .max_fft_bins = 512, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +@@ -156,6 +162,9 @@ static const struct ath11k_hw_params ath + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 0, ++ .max_fft_bins = 0, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +@@ -244,6 +253,9 @@ static const struct ath11k_hw_params ath + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 0, ++ .max_fft_bins = 0, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -157,6 +157,9 @@ struct ath11k_hw_params { + struct { + u8 fft_sz; + u8 fft_pad_sz; ++ u8 summary_pad_sz; ++ u8 fft_hdr_len; ++ u16 max_fft_bins; + } spectral; + + u16 interface_modes; +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -11,20 +11,20 @@ + #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + + #define ATH11K_SPECTRAL_DWORD_SIZE 4 +-#define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64 +-#define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32 +-#define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256 ++#define ATH11K_SPECTRAL_MIN_BINS 64 ++#define ATH11K_SPECTRAL_MIN_IB_BINS (ATH11K_SPECTRAL_MIN_BINS >> 1) ++#define ATH11K_SPECTRAL_MAX_IB_BINS(x) ((x)->hw_params.spectral.max_fft_bins >> 1) + + #define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095 + + /* Max channel computed by sum of 2g and 5g band channels */ + #define ATH11K_SPECTRAL_TOTAL_CHANNEL 41 + #define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70 +-#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE (sizeof(struct fft_sample_ath11k) + \ +- ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS) ++#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x) (sizeof(struct fft_sample_ath11k) + \ ++ ATH11K_SPECTRAL_MAX_IB_BINS(x)) + #define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \ + ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL) +-#define ATH11K_SPECTRAL_SUB_BUFF_SIZE ATH11K_SPECTRAL_PER_SAMPLE_SIZE ++#define ATH11K_SPECTRAL_SUB_BUFF_SIZE(x) ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x) + #define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE + + #define ATH11K_SPECTRAL_20MHZ 20 +@@ -446,8 +446,8 @@ static ssize_t ath11k_write_file_spectra + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + +- if (val < ATH11K_SPECTRAL_ATH11K_MIN_BINS || +- val > SPECTRAL_ATH11K_MAX_NUM_BINS) ++ if (val < ATH11K_SPECTRAL_MIN_BINS || ++ val > ar->ab->hw_params.spectral.max_fft_bins) + return -EINVAL; + + if (!is_power_of_2(val)) +@@ -598,7 +598,7 @@ int ath11k_spectral_process_fft(struct a + tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header)); + /* convert Dword into bytes */ + tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; +- bin_len = tlv_len - (sizeof(*fft_report) - sizeof(*tlv)); ++ bin_len = tlv_len - ab->hw_params.spectral.fft_hdr_len; + + if (data_len < (bin_len + sizeof(*fft_report))) { + ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n", +@@ -611,8 +611,8 @@ int ath11k_spectral_process_fft(struct a + /* Only In-band bins are useful to user for visualize */ + num_bins >>= 1; + +- if (num_bins < ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS || +- num_bins > ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS || ++ if (num_bins < ATH11K_SPECTRAL_MIN_IB_BINS || ++ num_bins > ATH11K_SPECTRAL_MAX_IB_BINS(ab) || + !is_power_of_2(num_bins)) { + ath11k_warn(ab, "Invalid num of bins %d\n", num_bins); + return -EINVAL; +@@ -693,7 +693,7 @@ static int ath11k_spectral_process_data( + goto unlock; + } + +- sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS; ++ sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_MAX_IB_BINS(ab); + fft_sample = kmalloc(sample_sz, GFP_ATOMIC); + if (!fft_sample) { + ret = -ENOBUFS; +@@ -741,7 +741,8 @@ static int ath11k_spectral_process_data( + * is 4 DWORD size (16 bytes). + * Need to remove this workaround once HW bug fixed + */ +- tlv_len = sizeof(*summary) - sizeof(*tlv); ++ tlv_len = sizeof(*summary) - sizeof(*tlv) + ++ ab->hw_params.spectral.summary_pad_sz; + + if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) { + ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n", +@@ -904,7 +905,7 @@ static inline int ath11k_spectral_debug_ + + ar->spectral.rfs_scan = relay_open("spectral_scan", + ar->debug.debugfs_pdev, +- ATH11K_SPECTRAL_SUB_BUFF_SIZE, ++ ATH11K_SPECTRAL_SUB_BUFF_SIZE(ar->ab), + ATH11K_SPECTRAL_NUM_SUB_BUF, + &rfs_scan_cb, NULL); + if (!ar->spectral.rfs_scan) { diff --git a/package/kernel/mac80211/patches/ath11k/0012-wifi-ath11k-Fix-qmi_msg_handler-data-structure-initi.patch b/package/kernel/mac80211/patches/ath11k/0012-wifi-ath11k-Fix-qmi_msg_handler-data-structure-initi.patch deleted file mode 100644 index 1f7418ff8..000000000 --- a/package/kernel/mac80211/patches/ath11k/0012-wifi-ath11k-Fix-qmi_msg_handler-data-structure-initi.patch +++ /dev/null @@ -1,33 +0,0 @@ -From ed3725e15a154ebebf44e0c34806c57525483f92 Mon Sep 17 00:00:00 2001 -From: Rahul Bhattacharjee -Date: Fri, 21 Oct 2022 14:31:26 +0530 -Subject: [PATCH] wifi: ath11k: Fix qmi_msg_handler data structure - initialization - -qmi_msg_handler is required to be null terminated by QMI module. -There might be a case where a handler for a msg id is not present in the -handlers array which can lead to infinite loop while searching the handler -and therefore out of bound access in qmi_invoke_handler(). -Hence update the initialization in qmi_msg_handler data structure. - -Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 - -Signed-off-by: Rahul Bhattacharjee -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221021090126.28626-1-quic_rbhattac@quicinc.com ---- - drivers/net/wireless/ath/ath11k/qmi.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/net/wireless/ath/ath11k/qmi.c -+++ b/drivers/net/wireless/ath/ath11k/qmi.c -@@ -3090,6 +3090,9 @@ static const struct qmi_msg_handler ath1 - sizeof(struct qmi_wlfw_fw_init_done_ind_msg_v01), - .fn = ath11k_qmi_msg_fw_init_done_cb, - }, -+ -+ /* end of list */ -+ {}, - }; - - static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl, diff --git a/package/kernel/mac80211/patches/ath11k/0013-ath11k-Fix-the-spectral-minimum-FFT-bin-count.patch b/package/kernel/mac80211/patches/ath11k/0013-ath11k-Fix-the-spectral-minimum-FFT-bin-count.patch new file mode 100644 index 000000000..50dbdd55c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0013-ath11k-Fix-the-spectral-minimum-FFT-bin-count.patch @@ -0,0 +1,33 @@ +From 6dfd20c8a6cd1fcf2c68d86c9d678f42535f6ade Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH] ath11k: Fix the spectral minimum FFT bin count + +User was not able to configure the spectral with the FFT bin count 32. +In all supported platforms, the expected minimum FFT bin count is 32 but +it was wrongly defined as 64. This restrict the user to not configure +down to the actually supported minimum FFT bin count. So update the +minimum FFT bin count as 32. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/spectral.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -11,7 +11,7 @@ + #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + + #define ATH11K_SPECTRAL_DWORD_SIZE 4 +-#define ATH11K_SPECTRAL_MIN_BINS 64 ++#define ATH11K_SPECTRAL_MIN_BINS 32 + #define ATH11K_SPECTRAL_MIN_IB_BINS (ATH11K_SPECTRAL_MIN_BINS >> 1) + #define ATH11K_SPECTRAL_MAX_IB_BINS(x) ((x)->hw_params.spectral.max_fft_bins >> 1) + diff --git a/package/kernel/mac80211/patches/ath11k/0013-wifi-ath11k-synchronize-ath11k_mac_he_gi_to_nl80211_.patch b/package/kernel/mac80211/patches/ath11k/0013-wifi-ath11k-synchronize-ath11k_mac_he_gi_to_nl80211_.patch deleted file mode 100644 index 1e89b4d4f..000000000 --- a/package/kernel/mac80211/patches/ath11k/0013-wifi-ath11k-synchronize-ath11k_mac_he_gi_to_nl80211_.patch +++ /dev/null @@ -1,42 +0,0 @@ -From dd1c2322694522f674c874f5fa02ac5ae39135dd Mon Sep 17 00:00:00 2001 -From: "Jiri Slaby (SUSE)" -Date: Mon, 31 Oct 2022 12:43:41 +0100 -Subject: [PATCH] wifi: ath11k: synchronize - ath11k_mac_he_gi_to_nl80211_he_gi()'s return type - -ath11k_mac_he_gi_to_nl80211_he_gi() generates a valid warning with gcc-13: - drivers/net/wireless/ath/ath11k/mac.c:321:20: error: conflicting types for 'ath11k_mac_he_gi_to_nl80211_he_gi' due to enum/integer mismatch; have 'enum nl80211_he_gi(u8)' - drivers/net/wireless/ath/ath11k/mac.h:166:5: note: previous declaration of 'ath11k_mac_he_gi_to_nl80211_he_gi' with type 'u32(u8)' - -I.e. the type of the return value ath11k_mac_he_gi_to_nl80211_he_gi() in -the declaration is u32, while the definition spells enum nl80211_he_gi. -Synchronize them to the latter. - -Cc: Martin Liska -Cc: Kalle Valo -Cc: "David S. Miller" -Cc: Eric Dumazet -Cc: Jakub Kicinski -Cc: Paolo Abeni -Cc: ath11k@lists.infradead.org -Cc: linux-wireless@vger.kernel.org -Cc: netdev@vger.kernel.org -Signed-off-by: Jiri Slaby (SUSE) -Reviewed-by: Jeff Johnson -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221031114341.10377-1-jirislaby@kernel.org ---- - drivers/net/wireless/ath/ath11k/mac.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/wireless/ath/ath11k/mac.h -+++ b/drivers/net/wireless/ath/ath11k/mac.h -@@ -163,7 +163,7 @@ void ath11k_mac_drain_tx(struct ath11k * - void ath11k_mac_peer_cleanup_all(struct ath11k *ar); - int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx); - u8 ath11k_mac_bw_to_mac80211_bw(u8 bw); --u32 ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi); -+enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi); - enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy); - enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones); - enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw); diff --git a/package/kernel/mac80211/patches/ath11k/0014-ath11k-Add-spectral-scan-support-for-QCN9074.patch b/package/kernel/mac80211/patches/ath11k/0014-ath11k-Add-spectral-scan-support-for-QCN9074.patch new file mode 100644 index 000000000..f2c2c7c56 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0014-ath11k-Add-spectral-scan-support-for-QCN9074.patch @@ -0,0 +1,36 @@ +From b72e86c07e9881d249fbb7511060692f3fb6b687 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH] ath11k: Add spectral scan support for QCN9074 + +Populate the below hw parameters as per the QCN9074 support + 1. FFT bin size as two bytes + 2. Maximum FFT bin count as 1024 + 3. Summary report pad size as 16 + 4. FFT report header length as 24 + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -206,8 +206,11 @@ static const struct ath11k_hw_params ath + .tcl_0_only = false, + + .spectral = { +- .fft_sz = 0, ++ .fft_sz = 2, + .fft_pad_sz = 0, ++ .summary_pad_sz = 16, ++ .fft_hdr_len = 24, ++ .max_fft_bins = 1024, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/package/kernel/mac80211/patches/ath11k/0015-ath11k-Wstringop-overread-warning.patch b/package/kernel/mac80211/patches/ath11k/0015-ath11k-Wstringop-overread-warning.patch new file mode 100644 index 000000000..1188b00fc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0015-ath11k-Wstringop-overread-warning.patch @@ -0,0 +1,44 @@ +From eb19efed836a51ee30a602abe2dd21a97c47bbcc Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Fri, 24 Sep 2021 16:52:52 +0300 +Subject: [PATCH] ath11k: Wstringop-overread warning + +gcc-11 with the kernel address sanitizer prints a warning for this +driver: + +In function 'ath11k_peer_assoc_h_vht', + inlined from 'ath11k_peer_assoc_prepare' at drivers/net/wireless/ath/ath11k/mac.c:1632:2: +drivers/net/wireless/ath/ath11k/mac.c:1164:13: error: 'ath11k_peer_assoc_h_vht_masked' reading 16 bytes from a region of size 4 [-Werror=stringop-overread] + 1164 | if (ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +drivers/net/wireless/ath/ath11k/mac.c: In function 'ath11k_peer_assoc_prepare': +drivers/net/wireless/ath/ath11k/mac.c:1164:13: note: referencing argument 1 of type 'const u16 *' {aka 'const short unsigned int *'} +drivers/net/wireless/ath/ath11k/mac.c:969:1: note: in a call to function 'ath11k_peer_assoc_h_vht_masked' + 969 | ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +According to analysis from gcc developers, this is a glitch in the +way gcc tracks the size of struct members. This should really get +fixed in gcc, but it's also easy to work around this instance +by changing the function prototype to no include the length of +the array. + +Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99673 +Signed-off-by: Arnd Bergmann +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210322160253.4032422-5-arnd@kernel.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1406,7 +1406,7 @@ ath11k_peer_assoc_h_ht_masked(const u8 h + } + + static bool +-ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) ++ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[]) + { + int nss; + diff --git a/package/kernel/mac80211/patches/ath11k/0016-ath11k-use-hw_params-to-access-board_size-and-cal_of.patch b/package/kernel/mac80211/patches/ath11k/0016-ath11k-use-hw_params-to-access-board_size-and-cal_of.patch new file mode 100644 index 000000000..1ff4ae8dd --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0016-ath11k-use-hw_params-to-access-board_size-and-cal_of.patch @@ -0,0 +1,113 @@ +From c72aa32d6d1c04fa83d4c0e6849e4e60d9d39ae4 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH] ath11k: use hw_params to access board_size and cal_offset + +Reuse board_size from hw_params, add cal_offset to hw params. +This patch is clean up only, there is no change in functionality. + +cal_size was unused, so remove that. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 10 +++++----- + drivers/net/wireless/ath/ath11k/hw.h | 2 +- + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++-- + drivers/net/wireless/ath/ath11k/qmi.h | 2 -- + 4 files changed, 8 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -37,7 +37,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "IPQ8074/hw2.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, +@@ -88,7 +88,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "IPQ6018/hw1.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 2, + .bdf_addr = 0x4ABC0000, +@@ -136,7 +136,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "QCA6390/hw2.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, +@@ -183,7 +183,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "QCN9074/hw1.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 1, + .single_pdev_only = false, +@@ -230,7 +230,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "WCN6855/hw2.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -128,7 +128,7 @@ struct ath11k_hw_params { + struct { + const char *dir; + size_t board_size; +- size_t cal_size; ++ size_t cal_offset; + } fw; + + const struct ath11k_hw_ops *hw_ops; +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1953,7 +1953,7 @@ ath11k_qmi_prepare_bdf_download(struct a + fw_size = min_t(u32, ab->hw_params.fw.board_size, + fw_entry->size); + +- memcpy_toio(bdf_addr + ATH11K_QMI_CALDATA_OFFSET, ++ memcpy_toio(bdf_addr + ab->hw_params.fw.cal_offset, + fw_entry->data, fw_size); + + release_firmware(fw_entry); +@@ -1979,7 +1979,7 @@ static int ath11k_qmi_load_bdf_fixed_add + return -ENOMEM; + memset(&resp, 0, sizeof(resp)); + +- bdf_addr = ioremap(ab->hw_params.bdf_addr, ATH11K_QMI_BDF_MAX_SIZE); ++ bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); + if (!bdf_addr) { + ath11k_warn(ab, "failed ioremap for board file\n"); + ret = -EIO; +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -13,8 +13,6 @@ + #define ATH11K_QMI_WLANFW_TIMEOUT_MS 5000 + #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64 + #define ATH11K_QMI_CALDB_ADDRESS 0x4BA00000 +-#define ATH11K_QMI_BDF_MAX_SIZE (256 * 1024) +-#define ATH11K_QMI_CALDATA_OFFSET (128 * 1024) + #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 + #define ATH11K_QMI_WLFW_SERVICE_ID_V01 0x45 + #define ATH11K_QMI_WLFW_SERVICE_VERS_V01 0x01 diff --git a/package/kernel/mac80211/patches/ath11k/0016-wifi-ath11k-Make-QMI-message-rules-const.patch b/package/kernel/mac80211/patches/ath11k/0016-wifi-ath11k-Make-QMI-message-rules-const.patch deleted file mode 100644 index 1f48df73f..000000000 --- a/package/kernel/mac80211/patches/ath11k/0016-wifi-ath11k-Make-QMI-message-rules-const.patch +++ /dev/null @@ -1,341 +0,0 @@ -From 93c1592889fca46d09d833455628bab05516cdbf Mon Sep 17 00:00:00 2001 -From: Jeff Johnson -Date: Wed, 14 Sep 2022 17:23:03 -0700 -Subject: [PATCH] wifi: ath11k: Make QMI message rules const - -Commit ff6d365898d4 ("soc: qcom: qmi: use const for struct -qmi_elem_info") allows QMI message encoding/decoding rules to be -const, so do that for ath11k. - -Compile tested only. - -Signed-off-by: Jeff Johnson -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20220915002303.12206-1-quic_jjohnson@quicinc.com ---- - drivers/net/wireless/ath/ath11k/qmi.c | 72 +++++++++++++-------------- - 1 file changed, 36 insertions(+), 36 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/qmi.c -+++ b/drivers/net/wireless/ath/ath11k/qmi.c -@@ -29,7 +29,7 @@ module_param_named(cold_boot_cal, ath11k - MODULE_PARM_DESC(cold_boot_cal, - "Decrease the channel switch time but increase the driver load time (Default: true)"); - --static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, -@@ -280,7 +280,7 @@ static struct qmi_elem_info qmi_wlanfw_h - }, - }; - --static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -297,7 +297,7 @@ static struct qmi_elem_info qmi_wlanfw_h - }, - }; - --static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, -@@ -522,7 +522,7 @@ static struct qmi_elem_info qmi_wlanfw_i - }, - }; - --static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -558,7 +558,7 @@ static struct qmi_elem_info qmi_wlanfw_i - }, - }; - --static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, -@@ -590,7 +590,7 @@ static struct qmi_elem_info qmi_wlanfw_m - }, - }; - --static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -632,7 +632,7 @@ static struct qmi_elem_info qmi_wlanfw_m - }, - }; - --static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, -@@ -659,7 +659,7 @@ static struct qmi_elem_info qmi_wlanfw_r - }, - }; - --static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, -@@ -699,7 +699,7 @@ static struct qmi_elem_info qmi_wlanfw_m - }, - }; - --static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, -@@ -726,7 +726,7 @@ static struct qmi_elem_info qmi_wlanfw_r - }, - }; - --static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -744,7 +744,7 @@ static struct qmi_elem_info qmi_wlanfw_r - }, - }; - --static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .array_type = NO_ARRAY, -@@ -752,7 +752,7 @@ static struct qmi_elem_info qmi_wlanfw_c - }, - }; - --static struct qmi_elem_info qmi_wlanfw_device_info_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_device_info_req_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .array_type = NO_ARRAY, -@@ -760,7 +760,7 @@ static struct qmi_elem_info qmi_wlanfw_d - }, - }; - --static struct qmi_elem_info qmi_wlfw_device_info_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlfw_device_info_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -814,7 +814,7 @@ static struct qmi_elem_info qmi_wlfw_dev - }, - }; - --static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -840,7 +840,7 @@ static struct qmi_elem_info qmi_wlanfw_r - }, - }; - --static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -857,7 +857,7 @@ static struct qmi_elem_info qmi_wlanfw_r - }, - }; - --static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -873,7 +873,7 @@ static struct qmi_elem_info qmi_wlanfw_s - }, - }; - --static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -899,7 +899,7 @@ static struct qmi_elem_info qmi_wlanfw_f - }, - }; - --static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -1100,7 +1100,7 @@ static struct qmi_elem_info qmi_wlanfw_c - }, - }; - --static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, -@@ -1235,7 +1235,7 @@ static struct qmi_elem_info qmi_wlanfw_b - }, - }; - --static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -1253,7 +1253,7 @@ static struct qmi_elem_info qmi_wlanfw_b - }, - }; - --static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_8_BYTE, - .elem_len = 1, -@@ -1277,7 +1277,7 @@ static struct qmi_elem_info qmi_wlanfw_m - }, - }; - --static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -1294,7 +1294,7 @@ static struct qmi_elem_info qmi_wlanfw_m - }, - }; - --static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -1347,7 +1347,7 @@ static struct qmi_elem_info qmi_wlanfw_c - }, - }; - --static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -1382,7 +1382,7 @@ static struct qmi_elem_info qmi_wlanfw_c - }, - }; - --static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, -@@ -1406,7 +1406,7 @@ static struct qmi_elem_info qmi_wlanfw_s - }, - }; - --static struct qmi_elem_info qmi_wlanfw_shadow_reg_v2_cfg_s_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_shadow_reg_v2_cfg_s_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -1423,7 +1423,7 @@ static struct qmi_elem_info qmi_wlanfw_s - }, - }; - --static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, -@@ -1458,7 +1458,7 @@ static struct qmi_elem_info qmi_wlanfw_w - }, - }; - --static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -1476,7 +1476,7 @@ static struct qmi_elem_info qmi_wlanfw_w - }, - }; - --static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, -@@ -1615,7 +1615,7 @@ static struct qmi_elem_info qmi_wlanfw_w - }, - }; - --static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -1632,28 +1632,28 @@ static struct qmi_elem_info qmi_wlanfw_w - }, - }; - --static struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .array_type = NO_ARRAY, - }, - }; - --static struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .array_type = NO_ARRAY, - }, - }; - --static struct qmi_elem_info qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .array_type = NO_ARRAY, - }, - }; - --static struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = { - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, -@@ -1679,7 +1679,7 @@ static struct qmi_elem_info qmi_wlanfw_w - }, - }; - --static struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, -@@ -1697,7 +1697,7 @@ static struct qmi_elem_info qmi_wlanfw_w - }, - }; - --static struct qmi_elem_info qmi_wlfw_fw_init_done_ind_msg_v01_ei[] = { -+static const struct qmi_elem_info qmi_wlfw_fw_init_done_ind_msg_v01_ei[] = { - { - .data_type = QMI_EOTI, - .array_type = NO_ARRAY, diff --git a/package/kernel/mac80211/patches/ath11k/0017-ath11k-clean-up-BDF-download-functions.patch b/package/kernel/mac80211/patches/ath11k/0017-ath11k-clean-up-BDF-download-functions.patch new file mode 100644 index 000000000..f26c6ce33 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0017-ath11k-clean-up-BDF-download-functions.patch @@ -0,0 +1,357 @@ +From 336e7b53c82fc74d261024773a0fab43623a94fb Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH] ath11k: clean up BDF download functions + +In current code, AHB/PCI uses two separate functions to download +BDF file. Refactor code and make a common function to send QMI BDF +download request for both AHB and PCI devices. This patch has no +functional change. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 248 +++++++++++--------------- + 1 file changed, 101 insertions(+), 147 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1917,98 +1917,72 @@ out: + return ret; + } + +-static int +-ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, +- struct qmi_wlanfw_bdf_download_req_msg_v01 *req, +- void __iomem *bdf_addr) +-{ +- const struct firmware *fw_entry; +- struct ath11k_board_data bd; +- u32 fw_size; +- int ret; +- +- switch (type) { +- case ATH11K_QMI_FILE_TYPE_BDF_GOLDEN: +- memset(&bd, 0, sizeof(bd)); +- +- ret = ath11k_core_fetch_bdf(ab, &bd); +- if (ret) { +- ath11k_warn(ab, "failed to load board file: %d\n", ret); +- return ret; +- } +- +- fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); +- memcpy_toio(bdf_addr, bd.data, fw_size); +- ath11k_core_free_bdf(ab, &bd); +- break; +- case ATH11K_QMI_FILE_TYPE_CALDATA: +- fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); +- if (IS_ERR(fw_entry)) { +- ret = PTR_ERR(fw_entry); +- ath11k_warn(ab, "failed to load %s: %d\n", +- ATH11K_DEFAULT_CAL_FILE, ret); +- return ret; +- } +- +- fw_size = min_t(u32, ab->hw_params.fw.board_size, +- fw_entry->size); +- +- memcpy_toio(bdf_addr + ab->hw_params.fw.cal_offset, +- fw_entry->data, fw_size); +- +- release_firmware(fw_entry); +- break; +- default: +- return -EINVAL; +- } +- +- req->total_size = fw_size; +- return 0; +-} +- +-static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab) ++static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab, ++ const u8 *data, u32 len, u8 type) + { + struct qmi_wlanfw_bdf_download_req_msg_v01 *req; + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; + struct qmi_txn txn = {}; ++ const u8 *temp = data; + void __iomem *bdf_addr = NULL; +- int type, ret; ++ int ret; ++ u32 remaining = len; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; ++ + memset(&resp, 0, sizeof(resp)); + +- bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); +- if (!bdf_addr) { +- ath11k_warn(ab, "failed ioremap for board file\n"); +- ret = -EIO; +- goto out; ++ if (ab->bus_params.fixed_bdf_addr) { ++ bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); ++ if (!bdf_addr) { ++ ath11k_warn(ab, "qmi ioremap error for bdf_addr\n"); ++ ret = -EIO; ++ goto err_free_req; ++ } + } + +- for (type = 0; type < ATH11K_QMI_MAX_FILE_TYPE; type++) { ++ while (remaining) { + req->valid = 1; + req->file_id_valid = 1; + req->file_id = ab->qmi.target.board_id; + req->total_size_valid = 1; ++ req->total_size = remaining; + req->seg_id_valid = 1; +- req->seg_id = type; +- req->data_valid = 0; +- req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; +- req->bdf_type = 0; +- req->bdf_type_valid = 0; ++ req->data_valid = 1; ++ req->bdf_type = type; ++ req->bdf_type_valid = 1; + req->end_valid = 1; +- req->end = 1; ++ req->end = 0; + +- ret = ath11k_qmi_prepare_bdf_download(ab, type, req, bdf_addr); +- if (ret < 0) +- goto out_qmi_bdf; ++ if (remaining > QMI_WLANFW_MAX_DATA_SIZE_V01) { ++ req->data_len = QMI_WLANFW_MAX_DATA_SIZE_V01; ++ } else { ++ req->data_len = remaining; ++ req->end = 1; ++ } ++ ++ if (ab->bus_params.fixed_bdf_addr) { ++ req->data_valid = 0; ++ req->end = 1; ++ req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; ++ } else { ++ memcpy(req->data, temp, req->data_len); ++ } ++ ++ if (ab->bus_params.fixed_bdf_addr) { ++ if (type == ATH11K_QMI_FILE_TYPE_CALDATA) ++ bdf_addr += ab->hw_params.fw.cal_offset; ++ ++ memcpy_toio(bdf_addr, temp, len); ++ } + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_bdf_download_resp_msg_v01_ei, + &resp); + if (ret < 0) +- goto out_qmi_bdf; ++ goto err_iounmap; + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download req fixed addr type %d\n", + type); +@@ -2019,54 +1993,59 @@ static int ath11k_qmi_load_bdf_fixed_add + qmi_wlanfw_bdf_download_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); +- goto out_qmi_bdf; ++ goto err_iounmap; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); +- if (ret < 0) +- goto out_qmi_bdf; ++ if (ret < 0) { ++ ath11k_warn(ab, "failed to wait board file download request: %d\n", ++ ret); ++ goto err_iounmap; ++ } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath11k_warn(ab, "board file download request failed: %d %d\n", + resp.resp.result, resp.resp.error); + ret = -EINVAL; +- goto out_qmi_bdf; ++ goto err_iounmap; ++ } ++ ++ if (ab->bus_params.fixed_bdf_addr) { ++ remaining = 0; ++ } else { ++ remaining -= req->data_len; ++ temp += req->data_len; ++ req->seg_id++; ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download request remaining %i\n", ++ remaining); + } + } + +-out_qmi_bdf: +- iounmap(bdf_addr); +-out: ++err_iounmap: ++ if (ab->bus_params.fixed_bdf_addr) ++ iounmap(bdf_addr); ++ ++err_free_req: + kfree(req); ++ + return ret; + } + + static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) + { +- struct qmi_wlanfw_bdf_download_req_msg_v01 *req; +- struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; ++ char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; ++ const struct firmware *fw_entry; + struct ath11k_board_data bd; +- unsigned int remaining; +- struct qmi_txn txn = {}; +- int ret; +- const u8 *temp; +- int bdf_type; +- +- req = kzalloc(sizeof(*req), GFP_KERNEL); +- if (!req) +- return -ENOMEM; +- memset(&resp, 0, sizeof(resp)); ++ u32 fw_size, file_type; ++ int ret = 0, bdf_type; + + memset(&bd, 0, sizeof(bd)); + ret = ath11k_core_fetch_bdf(ab, &bd); + if (ret) { +- ath11k_warn(ab, "failed to fetch board file: %d\n", ret); ++ ath11k_warn(ab, "qmi failed to fetch board file: %d\n", ret); + goto out; + } + +- temp = bd.data; +- remaining = bd.len; +- + if (bd.len >= SELFMAG && memcmp(bd.data, ELFMAG, SELFMAG) == 0) + bdf_type = ATH11K_QMI_BDF_TYPE_ELF; + else +@@ -2074,67 +2053,45 @@ static int ath11k_qmi_load_bdf_qmi(struc + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf_type %d\n", bdf_type); + +- while (remaining) { +- req->valid = 1; +- req->file_id_valid = 1; +- req->file_id = ab->qmi.target.board_id; +- req->total_size_valid = 1; +- req->total_size = bd.len; +- req->seg_id_valid = 1; +- req->data_valid = 1; +- req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; +- req->bdf_type = bdf_type; +- req->bdf_type_valid = 1; +- req->end_valid = 1; +- req->end = 0; +- +- if (remaining > QMI_WLANFW_MAX_DATA_SIZE_V01) { +- req->data_len = QMI_WLANFW_MAX_DATA_SIZE_V01; +- } else { +- req->data_len = remaining; +- req->end = 1; +- } +- +- memcpy(req->data, temp, req->data_len); +- +- ret = qmi_txn_init(&ab->qmi.handle, &txn, +- qmi_wlanfw_bdf_download_resp_msg_v01_ei, +- &resp); +- if (ret < 0) +- goto out_qmi_bdf; ++ fw_size = bd.len; ++ fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); + +- ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download request remaining %i\n", +- remaining); ++ ret = ath11k_qmi_load_file_target_mem(ab, bd.data, fw_size, bdf_type); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to load bdf file\n"); ++ goto out; ++ } + +- ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, +- QMI_WLANFW_BDF_DOWNLOAD_REQ_V01, +- QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN, +- qmi_wlanfw_bdf_download_req_msg_v01_ei, req); +- if (ret < 0) { +- qmi_txn_cancel(&txn); +- goto out_qmi_bdf; +- } ++ /* QCA6390 does not support cal data file, skip it */ ++ if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF) ++ goto out; + +- ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); +- if (ret < 0) +- goto out_qmi_bdf; ++ file_type = ATH11K_QMI_FILE_TYPE_CALDATA; ++ fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); ++ if (IS_ERR(fw_entry)) { ++ ret = PTR_ERR(fw_entry); ++ ath11k_warn(ab, ++ "qmi failed to load CAL data file:%s\n", ++ filename); ++ goto out; ++ } + +- if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { +- ath11k_warn(ab, "bdf download request failed: %d %d\n", +- resp.resp.result, resp.resp.error); +- ret = resp.resp.result; +- goto out_qmi_bdf; +- } +- remaining -= req->data_len; +- temp += req->data_len; +- req->seg_id++; ++ fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); ++ ret = ath11k_qmi_load_file_target_mem(ab, fw_entry->data, fw_size, file_type); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to load caldata\n"); ++ goto out_qmi_cal; + } + +-out_qmi_bdf: +- ath11k_core_free_bdf(ab, &bd); ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata downloaded: type: %u\n", ++ file_type); + ++out_qmi_cal: ++ release_firmware(fw_entry); + out: +- kfree(req); ++ ath11k_core_free_bdf(ab, &bd); ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi BDF download sequence completed\n"); ++ + return ret; + } + +@@ -2519,10 +2476,7 @@ static int ath11k_qmi_event_load_bdf(str + return ret; + } + +- if (ab->bus_params.fixed_bdf_addr) +- ret = ath11k_qmi_load_bdf_fixed_addr(ab); +- else +- ret = ath11k_qmi_load_bdf_qmi(ab); ++ ret = ath11k_qmi_load_bdf_qmi(ab); + if (ret < 0) { + ath11k_warn(ab, "failed to load board data file: %d\n", ret); + return ret; diff --git a/package/kernel/mac80211/patches/ath11k/0017-wifi-ath11k-Trigger-sta-disconnect-on-hardware-resta.patch b/package/kernel/mac80211/patches/ath11k/0017-wifi-ath11k-Trigger-sta-disconnect-on-hardware-resta.patch deleted file mode 100644 index f95e5027b..000000000 --- a/package/kernel/mac80211/patches/ath11k/0017-wifi-ath11k-Trigger-sta-disconnect-on-hardware-resta.patch +++ /dev/null @@ -1,119 +0,0 @@ -From a018750a2cceaf4427c4ee3d9ce3e83a171d5bd6 Mon Sep 17 00:00:00 2001 -From: Youghandhar Chintala -Date: Fri, 4 Nov 2022 14:24:03 +0530 -Subject: [PATCH] wifi: ath11k: Trigger sta disconnect on hardware restart - -Currently after the hardware restart triggered from the driver, the -station interface connection remains intact, since a disconnect trigger -is not sent to userspace. This can lead to a problem in targets where -the wifi mac sequence is added by the firmware. - -After the target restart, its wifi mac sequence number gets reset to -zero. Hence AP to which our device is connected will receive frames with -a wifi mac sequence number jump to the past, thereby resulting in the -AP dropping all these frames, until the frame arrives with a wifi mac -sequence number which AP was expecting. - -To avoid such frame drops, its better to trigger a station disconnect -upon target hardware restart which can be done with API -ieee80211_reconfig_disconnect exposed to mac80211. - -The other targets are not affected by this change, since the hardware -params flag is not set. - -Reported-by: kernel test robot - -Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00887-QCAMSLSWPLZ-1 - -Signed-off-by: Youghandhar Chintala -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221104085403.11025-1-quic_youghand@quicinc.com ---- - drivers/net/wireless/ath/ath11k/core.c | 6 ++++++ - drivers/net/wireless/ath/ath11k/hw.h | 1 + - drivers/net/wireless/ath/ath11k/mac.c | 7 +++++++ - 3 files changed, 14 insertions(+) - ---- a/drivers/net/wireless/ath/ath11k/core.c -+++ b/drivers/net/wireless/ath/ath11k/core.c -@@ -195,6 +195,7 @@ static const struct ath11k_hw_params ath - .tcl_ring_retry = true, - .tx_ring_size = DP_TCL_DATA_RING_SIZE, - .smp2p_wow_exit = false, -+ .support_fw_mac_sequence = false, - }, - { - .name = "qca6390 hw2.0", -@@ -277,6 +278,7 @@ static const struct ath11k_hw_params ath - .tcl_ring_retry = true, - .tx_ring_size = DP_TCL_DATA_RING_SIZE, - .smp2p_wow_exit = false, -+ .support_fw_mac_sequence = true, - }, - { - .name = "qcn9074 hw1.0", -@@ -356,6 +358,7 @@ static const struct ath11k_hw_params ath - .tcl_ring_retry = true, - .tx_ring_size = DP_TCL_DATA_RING_SIZE, - .smp2p_wow_exit = false, -+ .support_fw_mac_sequence = false, - }, - { - .name = "wcn6855 hw2.0", -@@ -438,6 +441,7 @@ static const struct ath11k_hw_params ath - .tcl_ring_retry = true, - .tx_ring_size = DP_TCL_DATA_RING_SIZE, - .smp2p_wow_exit = false, -+ .support_fw_mac_sequence = true, - }, - { - .name = "wcn6855 hw2.1", -@@ -519,6 +523,7 @@ static const struct ath11k_hw_params ath - .tcl_ring_retry = true, - .tx_ring_size = DP_TCL_DATA_RING_SIZE, - .smp2p_wow_exit = false, -+ .support_fw_mac_sequence = true, - }, - { - .name = "wcn6750 hw1.0", -@@ -597,6 +602,7 @@ static const struct ath11k_hw_params ath - .tcl_ring_retry = false, - .tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750, - .smp2p_wow_exit = true, -+ .support_fw_mac_sequence = true, - }, - }; - ---- a/drivers/net/wireless/ath/ath11k/hw.h -+++ b/drivers/net/wireless/ath/ath11k/hw.h -@@ -219,6 +219,7 @@ struct ath11k_hw_params { - bool tcl_ring_retry; - u32 tx_ring_size; - bool smp2p_wow_exit; -+ bool support_fw_mac_sequence; - }; - - struct ath11k_hw_ops { ---- a/drivers/net/wireless/ath/ath11k/mac.c -+++ b/drivers/net/wireless/ath/ath11k/mac.c -@@ -8010,6 +8010,7 @@ ath11k_mac_op_reconfig_complete(struct i - struct ath11k *ar = hw->priv; - struct ath11k_base *ab = ar->ab; - int recovery_count; -+ struct ath11k_vif *arvif; - - if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) - return; -@@ -8045,6 +8046,12 @@ ath11k_mac_op_reconfig_complete(struct i - ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset success\n"); - } - } -+ if (ar->ab->hw_params.support_fw_mac_sequence) { -+ list_for_each_entry(arvif, &ar->arvifs, list) { -+ if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) -+ ieee80211_hw_restart_disconnect(arvif->vif); -+ } -+ } - } - - mutex_unlock(&ar->conf_mutex); diff --git a/package/kernel/mac80211/patches/ath11k/0018-ath11k-add-caldata-file-for-multiple-radios.patch b/package/kernel/mac80211/patches/ath11k/0018-ath11k-add-caldata-file-for-multiple-radios.patch new file mode 100644 index 000000000..9975cca01 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0018-ath11k-add-caldata-file-for-multiple-radios.patch @@ -0,0 +1,68 @@ +From e82dfe7b5608592c270cc69100cb4322069f949d Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH] ath11k: add caldata file for multiple radios + +If multiple PCI cards are attached, each needs its own caldata file. + +Added new Caldata file name, +PCI Bus: + cal-pci-0001:01:00.0.bin + cal-pci-0000:01:00.0.bin +AHB Bus: + cal-ahb-c000000.wifi1.bin + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2033,6 +2033,7 @@ err_free_req: + + static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) + { ++ struct device *dev = ab->dev; + char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; + const struct firmware *fw_entry; + struct ath11k_board_data bd; +@@ -2067,6 +2068,14 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + + file_type = ATH11K_QMI_FILE_TYPE_CALDATA; ++ ++ /* cal--.bin */ ++ snprintf(filename, sizeof(filename), "cal-%s-%s.bin", ++ ath11k_bus_str(ab->hif.bus), dev_name(dev)); ++ fw_entry = ath11k_core_firmware_request(ab, filename); ++ if (!IS_ERR(fw_entry)) ++ goto success; ++ + fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); + if (IS_ERR(fw_entry)) { + ret = PTR_ERR(fw_entry); +@@ -2076,6 +2085,7 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + } + ++success: + fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); + ret = ath11k_qmi_load_file_target_mem(ab, fw_entry->data, fw_size, file_type); + if (ret < 0) { +@@ -2083,8 +2093,7 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out_qmi_cal; + } + +- ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata downloaded: type: %u\n", +- file_type); ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata type: %u\n", file_type); + + out_qmi_cal: + release_firmware(fw_entry); diff --git a/package/kernel/mac80211/patches/ath11k/0018-wifi-ath11k-Fix-race-condition-with-struct-htt_ppdu_.patch b/package/kernel/mac80211/patches/ath11k/0018-wifi-ath11k-Fix-race-condition-with-struct-htt_ppdu_.patch deleted file mode 100644 index cef61ee34..000000000 --- a/package/kernel/mac80211/patches/ath11k/0018-wifi-ath11k-Fix-race-condition-with-struct-htt_ppdu_.patch +++ /dev/null @@ -1,103 +0,0 @@ -From e44de90453bb2b46a523df78c39eb896bab35dcd Mon Sep 17 00:00:00 2001 -From: Govindaraj Saminathan -Date: Tue, 29 Nov 2022 13:04:02 +0200 -Subject: [PATCH] wifi: ath11k: Fix race condition with struct - htt_ppdu_stats_info - -A crash happens when running the traffic with multiple clients: - -Crash Signature : Unable to handle kernel paging request at -virtual address ffffffd700970918 During the crash, PC points to -"ieee80211_tx_rate_update+0x30/0x68 [mac80211]" -LR points to "ath11k_dp_htt_htc_t2h_msg_handler+0x5a8/0x8a0 [ath11k]". - -Struct ppdu_stats_info is allocated and accessed from event callback via copy -engine tasklet, this has a problem when freeing it from ath11k_mac_op_stop(). - -Use data_lock during entire ath11k_dp_htt_get_ppdu_desc() call to protect -struct htt_ppdu_stats_info access and to avoid race condition when accessing it -from ath11k_mac_op_stop(). - -Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 - -Signed-off-by: Govindaraj Saminathan -Co-developed-by: Karthikeyan Kathirvel -Signed-off-by: Karthikeyan Kathirvel -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/20221124071104.22506-1-quic_kathirve@quicinc.com ---- - drivers/net/wireless/ath/ath11k/dp_rx.c | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/dp_rx.c -+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c -@@ -1535,13 +1535,12 @@ struct htt_ppdu_stats_info *ath11k_dp_ht - { - struct htt_ppdu_stats_info *ppdu_info; - -- spin_lock_bh(&ar->data_lock); -+ lockdep_assert_held(&ar->data_lock); -+ - if (!list_empty(&ar->ppdu_stats_info)) { - list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) { -- if (ppdu_info->ppdu_id == ppdu_id) { -- spin_unlock_bh(&ar->data_lock); -+ if (ppdu_info->ppdu_id == ppdu_id) - return ppdu_info; -- } - } - - if (ar->ppdu_stat_list_depth > HTT_PPDU_DESC_MAX_DEPTH) { -@@ -1553,16 +1552,13 @@ struct htt_ppdu_stats_info *ath11k_dp_ht - kfree(ppdu_info); - } - } -- spin_unlock_bh(&ar->data_lock); - - ppdu_info = kzalloc(sizeof(*ppdu_info), GFP_ATOMIC); - if (!ppdu_info) - return NULL; - -- spin_lock_bh(&ar->data_lock); - list_add_tail(&ppdu_info->list, &ar->ppdu_stats_info); - ar->ppdu_stat_list_depth++; -- spin_unlock_bh(&ar->data_lock); - - return ppdu_info; - } -@@ -1586,16 +1582,17 @@ static int ath11k_htt_pull_ppdu_stats(st - ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id); - if (!ar) { - ret = -EINVAL; -- goto exit; -+ goto out; - } - - if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) - trace_ath11k_htt_ppdu_stats(ar, skb->data, len); - -+ spin_lock_bh(&ar->data_lock); - ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id); - if (!ppdu_info) { - ret = -EINVAL; -- goto exit; -+ goto out_unlock_data; - } - - ppdu_info->ppdu_id = ppdu_id; -@@ -1604,10 +1601,13 @@ static int ath11k_htt_pull_ppdu_stats(st - (void *)ppdu_info); - if (ret) { - ath11k_warn(ab, "Failed to parse tlv %d\n", ret); -- goto exit; -+ goto out_unlock_data; - } - --exit: -+out_unlock_data: -+ spin_unlock_bh(&ar->data_lock); -+ -+out: - rcu_read_unlock(); - - return ret; diff --git a/package/kernel/mac80211/patches/ath11k/0019-ath11k-add-caldata-download-support-from-EEPROM.patch b/package/kernel/mac80211/patches/ath11k/0019-ath11k-add-caldata-download-support-from-EEPROM.patch new file mode 100644 index 000000000..22993dac3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0019-ath11k-add-caldata-download-support-from-EEPROM.patch @@ -0,0 +1,282 @@ +From 4ba3b05ebd0c3e98c7dd8c7ee03aed9d80299b79 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH] ath11k: add caldata download support from EEPROM + +Firmware updates EEPROM support capability in QMI FW caps, send QMI BDF +download request message with file type EEPROM, to get caldata download +from EEPROM. Firmware takes more time to update cal data from EEPROM, so +increase QMI timeout. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 139 +++++++++++++++++++++----- + drivers/net/wireless/ath/ath11k/qmi.h | 16 ++- + 2 files changed, 127 insertions(+), 28 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -951,6 +951,78 @@ static struct qmi_elem_info qmi_wlanfw_c + num_macs), + }, + { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x16, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ voltage_mv_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x16, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ voltage_mv), ++ }, ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x17, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ time_freq_hz_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x17, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ time_freq_hz), ++ }, ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x18, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ otp_version_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x18, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ otp_version), ++ }, ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x19, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ eeprom_read_timeout_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x19, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ eeprom_read_timeout), ++ }, ++ { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, +@@ -1846,8 +1918,8 @@ static int ath11k_qmi_request_target_cap + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + +- ret = qmi_txn_init(&ab->qmi.handle, &txn, +- qmi_wlanfw_cap_resp_msg_v01_ei, &resp); ++ ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_cap_resp_msg_v01_ei, ++ &resp); + if (ret < 0) + goto out; + +@@ -1900,6 +1972,12 @@ static int ath11k_qmi_request_target_cap + strlcpy(ab->qmi.target.fw_build_id, resp.fw_build_id, + sizeof(ab->qmi.target.fw_build_id)); + ++ if (resp.eeprom_read_timeout_valid) { ++ ab->qmi.target.eeprom_caldata = ++ resp.eeprom_read_timeout; ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cal data supported from eeprom\n"); ++ } ++ + ath11k_info(ab, "chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x\n", + ab->qmi.target.chip_id, ab->qmi.target.chip_family, + ab->qmi.target.board_id, ab->qmi.target.soc_id); +@@ -1963,7 +2041,8 @@ static int ath11k_qmi_load_file_target_m + req->end = 1; + } + +- if (ab->bus_params.fixed_bdf_addr) { ++ if (ab->bus_params.fixed_bdf_addr || ++ type == ATH11K_QMI_FILE_TYPE_EEPROM) { + req->data_valid = 0; + req->end = 1; + req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; +@@ -2010,7 +2089,8 @@ static int ath11k_qmi_load_file_target_m + goto err_iounmap; + } + +- if (ab->bus_params.fixed_bdf_addr) { ++ if (ab->bus_params.fixed_bdf_addr || ++ type == ATH11K_QMI_FILE_TYPE_EEPROM) { + remaining = 0; + } else { + remaining -= req->data_len; +@@ -2039,6 +2119,7 @@ static int ath11k_qmi_load_bdf_qmi(struc + struct ath11k_board_data bd; + u32 fw_size, file_type; + int ret = 0, bdf_type; ++ const u8 *tmp; + + memset(&bd, 0, sizeof(bd)); + ret = ath11k_core_fetch_bdf(ab, &bd); +@@ -2063,31 +2144,38 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + } + +- /* QCA6390 does not support cal data file, skip it */ ++ /* QCA6390 does not support cal data, skip it */ + if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF) + goto out; + +- file_type = ATH11K_QMI_FILE_TYPE_CALDATA; ++ if (ab->qmi.target.eeprom_caldata) { ++ file_type = ATH11K_QMI_FILE_TYPE_EEPROM; ++ tmp = filename; ++ fw_size = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; ++ } else { ++ file_type = ATH11K_QMI_FILE_TYPE_CALDATA; + +- /* cal--.bin */ +- snprintf(filename, sizeof(filename), "cal-%s-%s.bin", +- ath11k_bus_str(ab->hif.bus), dev_name(dev)); +- fw_entry = ath11k_core_firmware_request(ab, filename); +- if (!IS_ERR(fw_entry)) +- goto success; +- +- fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); +- if (IS_ERR(fw_entry)) { +- ret = PTR_ERR(fw_entry); +- ath11k_warn(ab, +- "qmi failed to load CAL data file:%s\n", +- filename); +- goto out; ++ /* cal--.bin */ ++ snprintf(filename, sizeof(filename), "cal-%s-%s.bin", ++ ath11k_bus_str(ab->hif.bus), dev_name(dev)); ++ fw_entry = ath11k_core_firmware_request(ab, filename); ++ if (!IS_ERR(fw_entry)) ++ goto success; ++ ++ fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); ++ if (IS_ERR(fw_entry)) { ++ ret = PTR_ERR(fw_entry); ++ ath11k_warn(ab, ++ "qmi failed to load CAL data file:%s\n", ++ filename); ++ goto out; ++ } ++success: ++ fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); ++ tmp = fw_entry->data; + } + +-success: +- fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); +- ret = ath11k_qmi_load_file_target_mem(ab, fw_entry->data, fw_size, file_type); ++ ret = ath11k_qmi_load_file_target_mem(ab, tmp, fw_size, file_type); + if (ret < 0) { + ath11k_warn(ab, "qmi failed to load caldata\n"); + goto out_qmi_cal; +@@ -2096,7 +2184,8 @@ success: + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata type: %u\n", file_type); + + out_qmi_cal: +- release_firmware(fw_entry); ++ if (!ab->qmi.target.eeprom_caldata) ++ release_firmware(fw_entry); + out: + ath11k_core_free_bdf(ab, &bd); + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi BDF download sequence completed\n"); +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -10,7 +10,7 @@ + #include + + #define ATH11K_HOST_VERSION_STRING "WIN" +-#define ATH11K_QMI_WLANFW_TIMEOUT_MS 5000 ++#define ATH11K_QMI_WLANFW_TIMEOUT_MS 10000 + #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64 + #define ATH11K_QMI_CALDB_ADDRESS 0x4BA00000 + #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 +@@ -42,6 +42,7 @@ struct ath11k_base; + enum ath11k_qmi_file_type { + ATH11K_QMI_FILE_TYPE_BDF_GOLDEN, + ATH11K_QMI_FILE_TYPE_CALDATA, ++ ATH11K_QMI_FILE_TYPE_EEPROM, + ATH11K_QMI_MAX_FILE_TYPE, + }; + +@@ -102,6 +103,7 @@ struct target_info { + u32 board_id; + u32 soc_id; + u32 fw_version; ++ u32 eeprom_caldata; + char fw_build_timestamp[ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 + 1]; + char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; + char bdf_ext[ATH11K_QMI_BDF_EXT_STR_LENGTH]; +@@ -133,7 +135,7 @@ struct ath11k_qmi { + wait_queue_head_t cold_boot_waitq; + }; + +-#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 ++#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 261 + #define QMI_WLANFW_HOST_CAP_REQ_V01 0x0034 + #define QMI_WLANFW_HOST_CAP_RESP_MSG_V01_MAX_LEN 7 + #define QMI_WLFW_HOST_CAP_RESP_V01 0x0034 +@@ -283,7 +285,7 @@ struct qmi_wlanfw_fw_cold_cal_done_ind_m + }; + + #define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0 +-#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 207 ++#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 235 + #define QMI_WLANFW_CAP_REQ_V01 0x0024 + #define QMI_WLANFW_CAP_RESP_V01 0x0024 + +@@ -364,6 +366,14 @@ struct qmi_wlanfw_cap_resp_msg_v01 { + char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; + u8 num_macs_valid; + u8 num_macs; ++ u8 voltage_mv_valid; ++ u32 voltage_mv; ++ u8 time_freq_hz_valid; ++ u32 time_freq_hz; ++ u8 otp_version_valid; ++ u32 otp_version; ++ u8 eeprom_read_timeout_valid; ++ u32 eeprom_read_timeout; + }; + + struct qmi_wlanfw_cap_req_msg_v01 { diff --git a/package/kernel/mac80211/patches/ath11k/0020-ath11k-Replace-one-element-array-with-flexible-array.patch b/package/kernel/mac80211/patches/ath11k/0020-ath11k-Replace-one-element-array-with-flexible-array.patch new file mode 100644 index 000000000..ec23c198e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0020-ath11k-Replace-one-element-array-with-flexible-array.patch @@ -0,0 +1,144 @@ +From b2549465cdeac3847487ce88b15ca47c37b60b88 Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Tue, 28 Sep 2021 12:05:44 +0300 +Subject: [PATCH] ath11k: Replace one-element array with flexible-array member + +There is a regular need in the kernel to provide a way to declare having a +dynamically sized set of trailing elements in a structure. Kernel code +should always use "flexible array members"[1] for these cases. The older +style of one-element or zero-length arrays should no longer be used[2]. + +Refactor the code a bit according to the use of a flexible-array member in +struct scan_chan_list_params instead of a one-element array, and use the +struct_size() helper. + +Also, save 25 (too many) bytes that were being allocated: + +$ pahole -C channel_param drivers/net/wireless/ath/ath11k/reg.o +struct channel_param { + u8 chan_id; /* 0 1 */ + u8 pwr; /* 1 1 */ + u32 mhz; /* 2 4 */ + + /* Bitfield combined with next fields */ + + u32 half_rate:1; /* 4:16 4 */ + u32 quarter_rate:1; /* 4:17 4 */ + u32 dfs_set:1; /* 4:18 4 */ + u32 dfs_set_cfreq2:1; /* 4:19 4 */ + u32 is_chan_passive:1; /* 4:20 4 */ + u32 allow_ht:1; /* 4:21 4 */ + u32 allow_vht:1; /* 4:22 4 */ + u32 allow_he:1; /* 4:23 4 */ + u32 set_agile:1; /* 4:24 4 */ + u32 psc_channel:1; /* 4:25 4 */ + + /* XXX 6 bits hole, try to pack */ + + u32 phy_mode; /* 8 4 */ + u32 cfreq1; /* 12 4 */ + u32 cfreq2; /* 16 4 */ + char maxpower; /* 20 1 */ + char minpower; /* 21 1 */ + char maxregpower; /* 22 1 */ + u8 antennamax; /* 23 1 */ + u8 reg_class_id; /* 24 1 */ + + /* size: 25, cachelines: 1, members: 21 */ + /* sum members: 23 */ + /* sum bitfield members: 10 bits, bit holes: 1, sum bit holes: 6 bits */ + /* last cacheline: 25 bytes */ +} __attribute__((__packed__)); + +as previously, sizeof(struct scan_chan_list_params) was 32 bytes: + +$ pahole -C scan_chan_list_params drivers/net/wireless/ath/ath11k/reg.o +struct scan_chan_list_params { + u32 pdev_id; /* 0 4 */ + u16 nallchans; /* 4 2 */ + struct channel_param ch_param[1]; /* 6 25 */ + + /* size: 32, cachelines: 1, members: 3 */ + /* padding: 1 */ + /* last cacheline: 32 bytes */ +}; + +and now with the flexible array transformation it is just 8 bytes: + +$ pahole -C scan_chan_list_params drivers/net/wireless/ath/ath11k/reg.o +struct scan_chan_list_params { + u32 pdev_id; /* 0 4 */ + u16 nallchans; /* 4 2 */ + struct channel_param ch_param[]; /* 6 0 */ + + /* size: 8, cachelines: 1, members: 3 */ + /* padding: 2 */ + /* last cacheline: 8 bytes */ +}; + +This helps with the ongoing efforts to globally enable -Warray-bounds and +get us closer to being able to tighten the FORTIFY_SOURCE routines on +memcpy(). + +This issue was found with the help of Coccinelle and audited and fixed, +manually. + +[1] https://en.wikipedia.org/wiki/Flexible_array_member +[2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays + +Link: https://github.com/KSPP/linux/issues/79 +Link: https://github.com/KSPP/linux/issues/109 +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210823172159.GA25800@embeddedor +--- + drivers/net/wireless/ath/ath11k/reg.c | 7 ++----- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + drivers/net/wireless/ath/ath11k/wmi.h | 2 +- + 3 files changed, 4 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -97,7 +97,6 @@ int ath11k_reg_update_chan_list(struct a + struct channel_param *ch; + enum nl80211_band band; + int num_channels = 0; +- int params_len; + int i, ret; + + bands = hw->wiphy->bands; +@@ -117,10 +116,8 @@ int ath11k_reg_update_chan_list(struct a + if (WARN_ON(!num_channels)) + return -EINVAL; + +- params_len = sizeof(struct scan_chan_list_params) + +- num_channels * sizeof(struct channel_param); +- params = kzalloc(params_len, GFP_KERNEL); +- ++ params = kzalloc(struct_size(params, ch_param, num_channels), ++ GFP_KERNEL); + if (!params) + return -ENOMEM; + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2303,7 +2303,7 @@ int ath11k_wmi_send_scan_chan_list_cmd(s + u16 num_send_chans, num_sends = 0, max_chan_limit = 0; + u32 *reg1, *reg2; + +- tchan_info = &chan_list->ch_param[0]; ++ tchan_info = chan_list->ch_param; + while (chan_list->nallchans) { + len = sizeof(*cmd) + TLV_HDR_SIZE; + max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3659,7 +3659,7 @@ struct wmi_stop_scan_cmd { + struct scan_chan_list_params { + u32 pdev_id; + u16 nallchans; +- struct channel_param ch_param[1]; ++ struct channel_param ch_param[]; + }; + + struct wmi_scan_chan_list_cmd { diff --git a/package/kernel/mac80211/patches/ath11k/0023-ath11k-Add-support-for-RX-decapsulation-offload.patch b/package/kernel/mac80211/patches/ath11k/0023-ath11k-Add-support-for-RX-decapsulation-offload.patch new file mode 100644 index 000000000..06ffef929 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0023-ath11k-Add-support-for-RX-decapsulation-offload.patch @@ -0,0 +1,596 @@ +From 2167fa606c0f0e64b95a04f9bc42d9fd5360838a Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH] ath11k: Add support for RX decapsulation offload + +Add support for rx decapsulation offload by advertising +the support to mac80211 during registration. Also ensure +the frames have the RX_FLAG_8023 flag set in decap offload +frames before passing to mac80211. + +Since the packets delivered to the driver are in 802.3 format, these +can be sent to the network core with minimal processing in mac80211. +This helps in releasing some CPU cycles in the host processor and +thereby improving the performance. + +Two exceptions are made before passing decap frames, one is +for EAPOL packets since mac80211 8023 fast rx for the sta +is set only after authorization, other case is for multicast +packets to validate PN in mac80211. In both the cases the +decap frames are converted to 80211 frame and sent to mac80211. + +Ethernet decap can be enabled by using frame_mode modparam: + +insmod ath11k frame_mode=2 + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00844-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Manikanta Pubbisetty +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721204217.120572-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 4 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 194 +++++++++++++-------- + drivers/net/wireless/ath/ath11k/hal_desc.h | 2 + + drivers/net/wireless/ath/ath11k/hw.c | 43 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 2 + + drivers/net/wireless/ath/ath11k/mac.c | 25 ++- + 6 files changed, 198 insertions(+), 72 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -98,6 +98,8 @@ struct ath11k_skb_rxcb { + bool is_first_msdu; + bool is_last_msdu; + bool is_continuation; ++ bool is_mcbc; ++ bool is_eapol; + struct hal_rx_desc *rx_desc; + u8 err_rel_src; + u8 err_code; +@@ -105,6 +107,8 @@ struct ath11k_skb_rxcb { + u8 unmapped; + u8 is_frag; + u8 tid; ++ u16 peer_id; ++ u16 seq_no; + }; + + enum ath11k_hw_rev { +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -270,6 +270,18 @@ static bool ath11k_dp_rx_h_attn_is_mcbc( + __le32_to_cpu(attn->info1))); + } + ++static bool ath11k_dp_rxdesc_mac_addr2_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ return ab->hw_params.hw_ops->rx_desc_mac_addr2_valid(desc); ++} ++ ++static u8 *ath11k_dp_rxdesc_mpdu_start_addr2(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ return ab->hw_params.hw_ops->rx_desc_mpdu_start_addr2(desc); ++} ++ + static void ath11k_dp_service_mon_ring(struct timer_list *t) + { + struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); +@@ -2156,6 +2168,7 @@ static void ath11k_dp_rx_h_undecap(struc + { + u8 *first_hdr; + u8 decap; ++ struct ethhdr *ehdr; + + first_hdr = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc); + decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc); +@@ -2170,9 +2183,22 @@ static void ath11k_dp_rx_h_undecap(struc + decrypted); + break; + case DP_RX_DECAP_TYPE_ETHERNET2_DIX: +- /* TODO undecap support for middle/last msdu's of amsdu */ +- ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, +- enctype, status); ++ ehdr = (struct ethhdr *)msdu->data; ++ ++ /* mac80211 allows fast path only for authorized STA */ ++ if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { ++ ATH11K_SKB_RXCB(msdu)->is_eapol = true; ++ ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, ++ enctype, status); ++ break; ++ } ++ ++ /* PN for mcast packets will be validated in mac80211; ++ * remove eth header and add 802.11 header. ++ */ ++ if (ATH11K_SKB_RXCB(msdu)->is_mcbc && decrypted) ++ ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, ++ enctype, status); + break; + case DP_RX_DECAP_TYPE_8023: + /* TODO: Handle undecap for these formats */ +@@ -2180,35 +2206,62 @@ static void ath11k_dp_rx_h_undecap(struc + } + } + ++static struct ath11k_peer * ++ath11k_dp_rx_h_find_peer(struct ath11k_base *ab, struct sk_buff *msdu) ++{ ++ struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); ++ struct hal_rx_desc *rx_desc = rxcb->rx_desc; ++ struct ath11k_peer *peer = NULL; ++ ++ lockdep_assert_held(&ab->base_lock); ++ ++ if (rxcb->peer_id) ++ peer = ath11k_peer_find_by_id(ab, rxcb->peer_id); ++ ++ if (peer) ++ return peer; ++ ++ if (!rx_desc || !(ath11k_dp_rxdesc_mac_addr2_valid(ab, rx_desc))) ++ return NULL; ++ ++ peer = ath11k_peer_find_by_addr(ab, ++ ath11k_dp_rxdesc_mpdu_start_addr2(ab, rx_desc)); ++ return peer; ++} ++ + static void ath11k_dp_rx_h_mpdu(struct ath11k *ar, + struct sk_buff *msdu, + struct hal_rx_desc *rx_desc, + struct ieee80211_rx_status *rx_status) + { +- bool fill_crypto_hdr, mcast; ++ bool fill_crypto_hdr; + enum hal_encrypt_type enctype; + bool is_decrypted = false; ++ struct ath11k_skb_rxcb *rxcb; + struct ieee80211_hdr *hdr; + struct ath11k_peer *peer; + struct rx_attention *rx_attention; + u32 err_bitmap; + +- hdr = (struct ieee80211_hdr *)msdu->data; +- + /* PN for multicast packets will be checked in mac80211 */ ++ rxcb = ATH11K_SKB_RXCB(msdu); ++ fill_crypto_hdr = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); ++ rxcb->is_mcbc = fill_crypto_hdr; + +- mcast = is_multicast_ether_addr(hdr->addr1); +- fill_crypto_hdr = mcast; ++ if (rxcb->is_mcbc) { ++ rxcb->peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); ++ rxcb->seq_no = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); ++ } + + spin_lock_bh(&ar->ab->base_lock); +- peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr2); ++ peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); + if (peer) { +- if (mcast) ++ if (rxcb->is_mcbc) + enctype = peer->sec_type_grp; + else + enctype = peer->sec_type; + } else { +- enctype = HAL_ENCRYPT_TYPE_OPEN; ++ enctype = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc); + } + spin_unlock_bh(&ar->ab->base_lock); + +@@ -2247,8 +2300,11 @@ static void ath11k_dp_rx_h_mpdu(struct a + if (!is_decrypted || fill_crypto_hdr) + return; + +- hdr = (void *)msdu->data; +- hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); ++ if (ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc) != ++ DP_RX_DECAP_TYPE_ETHERNET2_DIX) { ++ hdr = (void *)msdu->data; ++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); ++ } + } + + static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc, +@@ -2365,51 +2421,49 @@ static void ath11k_dp_rx_h_ppdu(struct a + ath11k_dp_rx_h_rate(ar, rx_desc, rx_status); + } + +-static char *ath11k_print_get_tid(struct ieee80211_hdr *hdr, char *out, +- size_t size) +-{ +- u8 *qc; +- int tid; +- +- if (!ieee80211_is_data_qos(hdr->frame_control)) +- return ""; +- +- qc = ieee80211_get_qos_ctl(hdr); +- tid = *qc & IEEE80211_QOS_CTL_TID_MASK; +- snprintf(out, size, "tid %d", tid); +- +- return out; +-} +- + static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi, +- struct sk_buff *msdu) ++ struct sk_buff *msdu, ++ struct ieee80211_rx_status *status) + { + static const struct ieee80211_radiotap_he known = { + .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), + .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), + }; +- struct ieee80211_rx_status *status; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ struct ieee80211_rx_status *rx_status; + struct ieee80211_radiotap_he *he = NULL; +- char tid[32]; +- +- status = IEEE80211_SKB_RXCB(msdu); +- if (status->encoding == RX_ENC_HE) { ++ struct ieee80211_sta *pubsta = NULL; ++ struct ath11k_peer *peer; ++ struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); ++ u8 decap = DP_RX_DECAP_TYPE_RAW; ++ bool is_mcbc = rxcb->is_mcbc; ++ bool is_eapol = rxcb->is_eapol; ++ ++ if (status->encoding == RX_ENC_HE && ++ !(status->flag & RX_FLAG_RADIOTAP_HE) && ++ !(status->flag & RX_FLAG_SKIP_MONITOR)) { + he = skb_push(msdu, sizeof(known)); + memcpy(he, &known, sizeof(known)); + status->flag |= RX_FLAG_RADIOTAP_HE; + } + ++ if (!(status->flag & RX_FLAG_ONLY_MONITOR)) ++ decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rxcb->rx_desc); ++ ++ spin_lock_bh(&ar->ab->base_lock); ++ peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); ++ if (peer && peer->sta) ++ pubsta = peer->sta; ++ spin_unlock_bh(&ar->ab->base_lock); ++ + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, +- "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", ++ "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + msdu, + msdu->len, +- ieee80211_get_SA(hdr), +- ath11k_print_get_tid(hdr, tid, sizeof(tid)), +- is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? +- "mcast" : "ucast", +- (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, ++ peer ? peer->addr : NULL, ++ rxcb->tid, ++ is_mcbc ? "mcast" : "ucast", ++ rxcb->seq_no, + (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", + (status->encoding == RX_ENC_HT) ? "ht" : "", + (status->encoding == RX_ENC_VHT) ? "vht" : "", +@@ -2429,22 +2483,32 @@ static void ath11k_dp_rx_deliver_msdu(st + ath11k_dbg_dump(ar->ab, ATH11K_DBG_DP_RX, NULL, "dp rx msdu: ", + msdu->data, msdu->len); + ++ rx_status = IEEE80211_SKB_RXCB(msdu); ++ *rx_status = *status; ++ + /* TODO: trace rx packet */ + +- ieee80211_rx_napi(ar->hw, NULL, msdu, napi); ++ /* PN for multicast packets are not validate in HW, ++ * so skip 802.3 rx path ++ * Also, fast_rx expectes the STA to be authorized, hence ++ * eapol packets are sent in slow path. ++ */ ++ if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && ++ !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) ++ rx_status->flag |= RX_FLAG_8023; ++ ++ ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + } + + static int ath11k_dp_rx_process_msdu(struct ath11k *ar, + struct sk_buff *msdu, +- struct sk_buff_head *msdu_list) ++ struct sk_buff_head *msdu_list, ++ struct ieee80211_rx_status *rx_status) + { + struct ath11k_base *ab = ar->ab; + struct hal_rx_desc *rx_desc, *lrx_desc; + struct rx_attention *rx_attention; +- struct ieee80211_rx_status rx_status = {0}; +- struct ieee80211_rx_status *status; + struct ath11k_skb_rxcb *rxcb; +- struct ieee80211_hdr *hdr; + struct sk_buff *last_buf; + u8 l3_pad_bytes; + u8 *hdr_status; +@@ -2500,19 +2564,11 @@ static int ath11k_dp_rx_process_msdu(str + } + } + +- hdr = (struct ieee80211_hdr *)msdu->data; +- +- /* Process only data frames */ +- if (!ieee80211_is_data(hdr->frame_control)) +- return -EINVAL; +- +- ath11k_dp_rx_h_ppdu(ar, rx_desc, &rx_status); +- ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, &rx_status); ++ ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status); ++ ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status); + +- rx_status.flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; ++ rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; + +- status = IEEE80211_SKB_RXCB(msdu); +- *status = rx_status; + return 0; + + free_out: +@@ -2527,6 +2583,7 @@ static void ath11k_dp_rx_process_receive + struct ath11k_skb_rxcb *rxcb; + struct sk_buff *msdu; + struct ath11k *ar; ++ struct ieee80211_rx_status rx_status = {0}; + u8 mac_id; + int ret; + +@@ -2549,7 +2606,7 @@ static void ath11k_dp_rx_process_receive + continue; + } + +- ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list); ++ ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "Unable to process msdu %d", ret); +@@ -2557,7 +2614,7 @@ static void ath11k_dp_rx_process_receive + continue; + } + +- ath11k_dp_rx_deliver_msdu(ar, napi, msdu); ++ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); + (*quota)--; + } + +@@ -2639,10 +2696,14 @@ try_again: + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); + rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); +- rxcb->mac_id = mac_id; ++ rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, ++ desc.rx_mpdu_info.meta_data); ++ rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, ++ desc.rx_mpdu_info.info0); + rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, + desc.info0); + ++ rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list, msdu); + + if (total_msdu_reaped >= quota && !rxcb->is_continuation) { +@@ -3944,7 +4005,6 @@ static void ath11k_dp_rx_wbm_err(struct + { + struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); + struct ieee80211_rx_status rxs = {0}; +- struct ieee80211_rx_status *status; + bool drop = true; + + switch (rxcb->err_rel_src) { +@@ -3964,10 +4024,7 @@ static void ath11k_dp_rx_wbm_err(struct + return; + } + +- status = IEEE80211_SKB_RXCB(msdu); +- *status = rxs; +- +- ath11k_dp_rx_deliver_msdu(ar, napi, msdu); ++ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rxs); + } + + int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, +@@ -4851,7 +4908,7 @@ static int ath11k_dp_rx_mon_deliver(stru + { + struct ath11k_pdev_dp *dp = &ar->dp; + struct sk_buff *mon_skb, *skb_next, *header; +- struct ieee80211_rx_status *rxs = &dp->rx_status, *status; ++ struct ieee80211_rx_status *rxs = &dp->rx_status; + + mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, + tail_msdu, rxs); +@@ -4877,10 +4934,7 @@ static int ath11k_dp_rx_mon_deliver(stru + } + rxs->flag |= RX_FLAG_ONLY_MONITOR; + +- status = IEEE80211_SKB_RXCB(mon_skb); +- *status = *rxs; +- +- ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb); ++ ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb, rxs); + mon_skb = skb_next; + } while (mon_skb); + rxs->flag = 0; +--- a/drivers/net/wireless/ath/ath11k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath11k/hal_desc.h +@@ -496,6 +496,8 @@ struct hal_tlv_hdr { + #define RX_MPDU_DESC_INFO0_DA_IDX_TIMEOUT BIT(29) + #define RX_MPDU_DESC_INFO0_RAW_MPDU BIT(30) + ++#define RX_MPDU_DESC_META_DATA_PEER_ID GENMASK(15, 0) ++ + struct rx_mpdu_desc { + u32 info0; /* %RX_MPDU_DESC_INFO */ + u32 meta_data; +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -374,6 +374,17 @@ static void ath11k_hw_ipq8074_rx_desc_se + desc->u.ipq8074.msdu_start.info1 = __cpu_to_le32(info); + } + ++static bool ath11k_hw_ipq8074_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) ++{ ++ return __le32_to_cpu(desc->u.ipq8074.mpdu_start.info1) & ++ RX_MPDU_START_INFO1_MAC_ADDR2_VALID; ++} ++ ++static u8 *ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) ++{ ++ return desc->u.ipq8074.mpdu_start.addr2; ++} ++ + static + struct rx_attention *ath11k_hw_ipq8074_rx_desc_get_attention(struct hal_rx_desc *desc) + { +@@ -545,6 +556,17 @@ static u8 *ath11k_hw_qcn9074_rx_desc_get + return &desc->u.qcn9074.msdu_payload[0]; + } + ++static bool ath11k_hw_ipq9074_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) ++{ ++ return __le32_to_cpu(desc->u.qcn9074.mpdu_start.info11) & ++ RX_MPDU_START_INFO11_MAC_ADDR2_VALID; ++} ++ ++static u8 *ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) ++{ ++ return desc->u.qcn9074.mpdu_start.addr2; ++} ++ + static bool ath11k_hw_wcn6855_rx_desc_get_first_msdu(struct hal_rx_desc *desc) + { + return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU_WCN6855, +@@ -705,6 +727,17 @@ static u8 *ath11k_hw_wcn6855_rx_desc_get + return &desc->u.wcn6855.msdu_payload[0]; + } + ++static bool ath11k_hw_wcn6855_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) ++{ ++ return __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1) & ++ RX_MPDU_START_INFO1_MAC_ADDR2_VALID; ++} ++ ++static u8 *ath11k_hw_wcn6855_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) ++{ ++ return desc->u.wcn6855.mpdu_start.addr2; ++} ++ + static void ath11k_hw_wcn6855_reo_setup(struct ath11k_base *ab) + { + u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; +@@ -801,6 +834,8 @@ const struct ath11k_hw_ops ipq8074_ops = + .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops ipq6018_ops = { +@@ -837,6 +872,8 @@ const struct ath11k_hw_ops ipq6018_ops = + .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops qca6390_ops = { +@@ -873,6 +910,8 @@ const struct ath11k_hw_ops qca6390_ops = + .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops qcn9074_ops = { +@@ -909,6 +948,8 @@ const struct ath11k_hw_ops qcn9074_ops = + .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops wcn6855_ops = { +@@ -945,6 +986,8 @@ const struct ath11k_hw_ops wcn6855_ops = + .rx_desc_get_msdu_payload = ath11k_hw_wcn6855_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_wcn6855_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_wcn6855_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_wcn6855_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_wcn6855_rx_desc_mpdu_start_addr2, + }; + + #define ATH11K_TX_RING_MASK_0 0x1 +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -209,6 +209,8 @@ struct ath11k_hw_ops { + u8 *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc); + void (*reo_setup)(struct ath11k_base *ab); + u16 (*mpdu_info_get_peerid)(u8 *tlv_data); ++ bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc); ++ u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc); + }; + + extern const struct ath11k_hw_ops ipq8074_ops; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5380,7 +5380,8 @@ static void ath11k_mac_op_update_vif_off + if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET || + (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP)) +- vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED | ++ IEEE80211_OFFLOAD_DECAP_ENABLED); + + if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) + param_value = ATH11K_HW_TXRX_ETHERNET; +@@ -5396,6 +5397,22 @@ static void ath11k_mac_op_update_vif_off + arvif->vdev_id, ret); + vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; + } ++ ++ param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE; ++ if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED) ++ param_value = ATH11K_HW_TXRX_ETHERNET; ++ else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) ++ param_value = ATH11K_HW_TXRX_RAW; ++ else ++ param_value = ATH11K_HW_TXRX_NATIVE_WIFI; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ param_id, param_value); ++ if (ret) { ++ ath11k_warn(ab, "failed to set vdev %d rx decap mode: %d\n", ++ arvif->vdev_id, ret); ++ vif->offload_flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; ++ } + } + + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, +@@ -7560,7 +7577,11 @@ static int __ath11k_mac_register(struct + ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); +- ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ++ if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET) { ++ ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ieee80211_hw_set(ar->hw, SUPPORTS_RX_DECAP_OFFLOAD); ++ } + + if (cap->nss_ratio_enabled) + ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW); diff --git a/package/kernel/mac80211/patches/ath11k/0024-ath11k-Fix-pktlog-lite-rx-events.patch b/package/kernel/mac80211/patches/ath11k/0024-ath11k-Fix-pktlog-lite-rx-events.patch new file mode 100644 index 000000000..01c1e8a26 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0024-ath11k-Fix-pktlog-lite-rx-events.patch @@ -0,0 +1,186 @@ +From ab18e3bc1c138f2b4358c6905a45afb7289d5086 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH] ath11k: Fix pktlog lite rx events + +Fix sending rx_buf_sz to ath11k_dp_tx_htt_rx_filter_setup() +to enable pktlog full or lite mode. Depending on mode update the +trace buffer with log type full/lite. + +Pktlog lite is a lighter version of pktlog. This can be used to capture +PPDU stats. These are useful for firmware performance debugging. + +pktlog lite dumps are enabled using, + echo "0x0 1" > ath11k/IPQ8074 hw2.0/mac0/pktlog_filter + +Tested On: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01233-QCAHKSWPL_SILICONZ-1 v2 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 25 +++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/dp.h | 1 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 16 ++++++++++++--- + drivers/net/wireless/ath/ath11k/trace.h | 11 ++++++---- + 4 files changed, 42 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -902,7 +902,7 @@ static ssize_t ath11k_write_pktlog_filte + struct htt_rx_ring_tlv_filter tlv_filter = {0}; + u32 rx_filter = 0, ring_id, filter, mode; + u8 buf[128] = {0}; +- int i, ret; ++ int i, ret, rx_buf_sz = 0; + ssize_t rc; + + mutex_lock(&ar->conf_mutex); +@@ -940,6 +940,17 @@ static ssize_t ath11k_write_pktlog_filte + } + } + ++ /* Clear rx filter set for monitor mode and rx status */ ++ for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { ++ ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ++ ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, ++ HAL_RXDMA_MONITOR_STATUS, ++ rx_buf_sz, &tlv_filter); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); ++ goto out; ++ } ++ } + #define HTT_RX_FILTER_TLV_LITE_MODE \ + (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \ + HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \ +@@ -955,6 +966,7 @@ static ssize_t ath11k_write_pktlog_filte + HTT_RX_FILTER_TLV_FLAGS_MPDU_END | + HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER | + HTT_RX_FILTER_TLV_FLAGS_ATTENTION; ++ rx_buf_sz = DP_RX_BUFFER_SIZE; + } else if (mode == ATH11K_PKTLOG_MODE_LITE) { + ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar, + HTT_PPDU_STATS_TAG_PKTLOG); +@@ -964,7 +976,12 @@ static ssize_t ath11k_write_pktlog_filte + } + + rx_filter = HTT_RX_FILTER_TLV_LITE_MODE; ++ rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; + } else { ++ rx_buf_sz = DP_RX_BUFFER_SIZE; ++ tlv_filter = ath11k_mac_mon_status_filter_default; ++ rx_filter = tlv_filter.rx_filter; ++ + ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar, + HTT_PPDU_STATS_TAG_DEFAULT); + if (ret) { +@@ -988,7 +1005,7 @@ static ssize_t ath11k_write_pktlog_filte + ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, + ar->dp.mac_id + i, + HAL_RXDMA_MONITOR_STATUS, +- DP_RX_BUFFER_SIZE, &tlv_filter); ++ rx_buf_sz, &tlv_filter); + + if (ret) { + ath11k_warn(ab, "failed to set rx filter for monitor status ring\n"); +@@ -996,8 +1013,8 @@ static ssize_t ath11k_write_pktlog_filte + } + } + +- ath11k_dbg(ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n", +- filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite")); ++ ath11k_info(ab, "pktlog mode %s\n", ++ ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite")); + + ar->debug.pktlog_filter = filter; + ar->debug.pktlog_mode = mode; +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -195,6 +195,7 @@ struct ath11k_pdev_dp { + #define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096 + + #define DP_RX_BUFFER_SIZE 2048 ++#define DP_RX_BUFFER_SIZE_LITE 1024 + #define DP_RX_BUFFER_ALIGN_SIZE 128 + + #define DP_RXDMA_BUF_COOKIE_BUF_ID GENMASK(17, 0) +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -3033,6 +3033,8 @@ int ath11k_dp_rx_process_mon_status(stru + struct ath11k_peer *peer; + struct ath11k_sta *arsta; + int num_buffs_reaped = 0; ++ u32 rx_buf_sz; ++ u16 log_type = 0; + + __skb_queue_head_init(&skb_list); + +@@ -3045,8 +3047,16 @@ int ath11k_dp_rx_process_mon_status(stru + memset(&ppdu_info, 0, sizeof(ppdu_info)); + ppdu_info.peer_id = HAL_INVALID_PEERID; + +- if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) +- trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); ++ if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_LITE_RX; ++ rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; ++ } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; ++ rx_buf_sz = DP_RX_BUFFER_SIZE; ++ } ++ ++ if (log_type) ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + + hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb); + +@@ -3074,7 +3084,7 @@ int ath11k_dp_rx_process_mon_status(stru + ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info); + + if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) +- trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -79,14 +79,15 @@ TRACE_EVENT(ath11k_htt_ppdu_stats, + ); + + TRACE_EVENT(ath11k_htt_rxdesc, +- TP_PROTO(struct ath11k *ar, const void *data, size_t len), ++ TP_PROTO(struct ath11k *ar, const void *data, size_t log_type, size_t len), + +- TP_ARGS(ar, data, len), ++ TP_ARGS(ar, data, log_type, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->ab->dev)) + __string(driver, dev_driver_string(ar->ab->dev)) + __field(u16, len) ++ __field(u16, log_type) + __dynamic_array(u8, rxdesc, len) + ), + +@@ -94,14 +95,16 @@ TRACE_EVENT(ath11k_htt_rxdesc, + __assign_str(device, dev_name(ar->ab->dev)); + __assign_str(driver, dev_driver_string(ar->ab->dev)); + __entry->len = len; ++ __entry->log_type = log_type; + memcpy(__get_dynamic_array(rxdesc), data, len); + ), + + TP_printk( +- "%s %s rxdesc len %d", ++ "%s %s rxdesc len %d type %d", + __get_str(driver), + __get_str(device), +- __entry->len ++ __entry->len, ++ __entry->log_type + ) + ); + diff --git a/package/kernel/mac80211/patches/ath11k/0025-ath11k-Update-pdev-tx-and-rx-firmware-stats.patch b/package/kernel/mac80211/patches/ath11k/0025-ath11k-Update-pdev-tx-and-rx-firmware-stats.patch new file mode 100644 index 000000000..cd654eca4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0025-ath11k-Update-pdev-tx-and-rx-firmware-stats.patch @@ -0,0 +1,250 @@ +From f394e4eae8e2c0579063e5473f1e321d22d3fe43 Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH] ath11k: Update pdev tx and rx firmware stats + +Update the fields of pdev tx and tx firmware stats structure. +Missing fields resulted in wrong fw stats to be displayed as below. + +root@OpenWrt:/# cat /sys/kernel/debug/ath11k/ + ipq8074\ hw2.0/mac0/fw_stats/pdev_stats | grep Illegal +Illegal rate phy errors 36839112 + +Note that this struct was missing its members from initial driver +support and this change doesn't introduce/modify the structure for +firmware changes. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 29 ++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 41 ++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/wmi.h | 42 ++++++++++++++++++++++++++ + 3 files changed, 111 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -819,12 +819,15 @@ struct ath11k_fw_stats_pdev { + s32 hw_reaped; + /* Num underruns */ + s32 underrun; ++ /* Num hw paused */ ++ u32 hw_paused; + /* Num PPDUs cleaned up in TX abort */ + s32 tx_abort; + /* Num MPDUs requeued by SW */ + s32 mpdus_requeued; + /* excessive retries */ + u32 tx_ko; ++ u32 tx_xretry; + /* data hw rate code */ + u32 data_rc; + /* Scheduler self triggers */ +@@ -845,6 +848,30 @@ struct ath11k_fw_stats_pdev { + u32 phy_underrun; + /* MPDU is more than txop limit */ + u32 txop_ovf; ++ /* Num sequences posted */ ++ u32 seq_posted; ++ /* Num sequences failed in queueing */ ++ u32 seq_failed_queueing; ++ /* Num sequences completed */ ++ u32 seq_completed; ++ /* Num sequences restarted */ ++ u32 seq_restarted; ++ /* Num of MU sequences posted */ ++ u32 mu_seq_posted; ++ /* Num MPDUs flushed by SW, HWPAUSED, SW TXABORT ++ * (Reset,channel change) ++ */ ++ s32 mpdus_sw_flush; ++ /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ ++ s32 mpdus_hw_filter; ++ /* Num MPDUs truncated by PDG (TXOP, TBTT, ++ * PPDU_duration based on rate, dyn_bw) ++ */ ++ s32 mpdus_truncated; ++ /* Num MPDUs that was tried but didn't receive ACK or BA */ ++ s32 mpdus_ack_failed; ++ /* Num MPDUs that was dropped du to expiry. */ ++ s32 mpdus_expired; + + /* PDEV RX stats */ + /* Cnts any change in ring routing mid-ppdu */ +@@ -870,6 +897,8 @@ struct ath11k_fw_stats_pdev { + s32 phy_err_drop; + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + s32 mpdu_errs; ++ /* Num overflow errors */ ++ s32 rx_ovfl_errs; + }; + + struct ath11k_fw_stats_vdev { +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -5252,9 +5252,11 @@ ath11k_wmi_pull_pdev_stats_tx(const stru + dst->hw_queued = src->hw_queued; + dst->hw_reaped = src->hw_reaped; + dst->underrun = src->underrun; ++ dst->hw_paused = src->hw_paused; + dst->tx_abort = src->tx_abort; + dst->mpdus_requeued = src->mpdus_requeued; + dst->tx_ko = src->tx_ko; ++ dst->tx_xretry = src->tx_xretry; + dst->data_rc = src->data_rc; + dst->self_triggers = src->self_triggers; + dst->sw_retry_failure = src->sw_retry_failure; +@@ -5265,6 +5267,16 @@ ath11k_wmi_pull_pdev_stats_tx(const stru + dst->stateless_tid_alloc_failure = src->stateless_tid_alloc_failure; + dst->phy_underrun = src->phy_underrun; + dst->txop_ovf = src->txop_ovf; ++ dst->seq_posted = src->seq_posted; ++ dst->seq_failed_queueing = src->seq_failed_queueing; ++ dst->seq_completed = src->seq_completed; ++ dst->seq_restarted = src->seq_restarted; ++ dst->mu_seq_posted = src->mu_seq_posted; ++ dst->mpdus_sw_flush = src->mpdus_sw_flush; ++ dst->mpdus_hw_filter = src->mpdus_hw_filter; ++ dst->mpdus_truncated = src->mpdus_truncated; ++ dst->mpdus_ack_failed = src->mpdus_ack_failed; ++ dst->mpdus_expired = src->mpdus_expired; + } + + static void ath11k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, +@@ -5284,6 +5296,7 @@ static void ath11k_wmi_pull_pdev_stats_r + dst->phy_errs = src->phy_errs; + dst->phy_err_drop = src->phy_err_drop; + dst->mpdu_errs = src->mpdu_errs; ++ dst->rx_ovfl_errs = src->rx_ovfl_errs; + } + + static void +@@ -5521,11 +5534,15 @@ ath11k_wmi_fw_pdev_tx_stats_fill(const s + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "Num underruns", pdev->underrun); + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Num HW Paused", pdev->hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "PPDUs cleaned", pdev->tx_abort); + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "MPDUs requeued", pdev->mpdus_requeued); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +- "Excessive retries", pdev->tx_ko); ++ "PPDU OK", pdev->tx_ko); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Excessive retries", pdev->tx_xretry); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "HW rate", pdev->data_rc); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +@@ -5549,6 +5566,26 @@ ath11k_wmi_fw_pdev_tx_stats_fill(const s + "PHY underrun", pdev->phy_underrun); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "MPDU is more than txop limit", pdev->txop_ovf); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num sequences posted", pdev->seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num seq failed queueing ", pdev->seq_failed_queueing); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num sequences completed ", pdev->seq_completed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num sequences restarted ", pdev->seq_restarted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MU sequences posted ", pdev->mu_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS SW flushed ", pdev->mpdus_sw_flush); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS HW filtered ", pdev->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS truncated ", pdev->mpdus_truncated); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS ACK failed ", pdev->mpdus_ack_failed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS expired ", pdev->mpdus_expired); + *length = len; + } + +@@ -5593,6 +5630,8 @@ ath11k_wmi_fw_pdev_rx_stats_fill(const s + "PHY errors drops", pdev->phy_err_drop); + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Overflow errors", pdev->rx_ovfl_errs); + *length = len; + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4223,6 +4223,9 @@ struct wmi_pdev_stats_tx { + /* Num underruns */ + s32 underrun; + ++ /* Num hw paused */ ++ u32 hw_paused; ++ + /* Num PPDUs cleaned up in TX abort */ + s32 tx_abort; + +@@ -4232,6 +4235,8 @@ struct wmi_pdev_stats_tx { + /* excessive retries */ + u32 tx_ko; + ++ u32 tx_xretry; ++ + /* data hw rate code */ + u32 data_rc; + +@@ -4261,6 +4266,40 @@ struct wmi_pdev_stats_tx { + + /* MPDU is more than txop limit */ + u32 txop_ovf; ++ ++ /* Num sequences posted */ ++ u32 seq_posted; ++ ++ /* Num sequences failed in queueing */ ++ u32 seq_failed_queueing; ++ ++ /* Num sequences completed */ ++ u32 seq_completed; ++ ++ /* Num sequences restarted */ ++ u32 seq_restarted; ++ ++ /* Num of MU sequences posted */ ++ u32 mu_seq_posted; ++ ++ /* Num MPDUs flushed by SW, HWPAUSED, SW TXABORT ++ * (Reset,channel change) ++ */ ++ s32 mpdus_sw_flush; ++ ++ /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ ++ s32 mpdus_hw_filter; ++ ++ /* Num MPDUs truncated by PDG (TXOP, TBTT, ++ * PPDU_duration based on rate, dyn_bw) ++ */ ++ s32 mpdus_truncated; ++ ++ /* Num MPDUs that was tried but didn't receive ACK or BA */ ++ s32 mpdus_ack_failed; ++ ++ /* Num MPDUs that was dropped du to expiry. */ ++ s32 mpdus_expired; + } __packed; + + struct wmi_pdev_stats_rx { +@@ -4295,6 +4334,9 @@ struct wmi_pdev_stats_rx { + + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + s32 mpdu_errs; ++ ++ /* Num overflow errors */ ++ s32 rx_ovfl_errs; + } __packed; + + struct wmi_pdev_stats { diff --git a/package/kernel/mac80211/patches/ath11k/0028-ath11k-Add-vdev-start-flag-to-disable-hardware-encry.patch b/package/kernel/mac80211/patches/ath11k/0028-ath11k-Add-vdev-start-flag-to-disable-hardware-encry.patch new file mode 100644 index 000000000..740f5de62 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0028-ath11k-Add-vdev-start-flag-to-disable-hardware-encry.patch @@ -0,0 +1,47 @@ +From 8717db7ee802b71fa3f2a79b265b1325bc61210c Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH] ath11k: Add vdev start flag to disable hardware encryption + +Firmware blocks all data traffic until the key is plumbed. But, with +software encryption mode, key is never plumbed to firmware. Due to this, +a traffic failure in software encryption mode has been observed. Hence, +firmware has introduced a flag to differentiate software encryption +mode. This flag can be passed during vdev_start command. + +Enable WMI_VDEV_START_HW_ENCRYPTION_DISABLED flag in vdev_start command +to notify firmware to disable hardware encryption for a vdev. This is set +if raw mode software encryption is enabled. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01421-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 ++ + drivers/net/wireless/ath/ath11k/wmi.h | 1 + + 2 files changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -884,6 +884,8 @@ int ath11k_wmi_vdev_start(struct ath11k + } + + cmd->flags |= WMI_VDEV_START_LDPC_RX_ENABLED; ++ if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) ++ cmd->flags |= WMI_VDEV_START_HW_ENCRYPTION_DISABLED; + + ptr = skb->data + sizeof(*cmd); + chan = ptr; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2577,6 +2577,7 @@ struct wmi_vdev_down_cmd { + #define WMI_VDEV_START_HIDDEN_SSID BIT(0) + #define WMI_VDEV_START_PMF_ENABLED BIT(1) + #define WMI_VDEV_START_LDPC_RX_ENABLED BIT(3) ++#define WMI_VDEV_START_HW_ENCRYPTION_DISABLED BIT(4) + + struct wmi_ssid { + u32 ssid_len; diff --git a/package/kernel/mac80211/patches/ath11k/0029-ath11k-Assign-free_vdev_map-value-before-ieee80211_r.patch b/package/kernel/mac80211/patches/ath11k/0029-ath11k-Assign-free_vdev_map-value-before-ieee80211_r.patch new file mode 100644 index 000000000..a2e2cbb8f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0029-ath11k-Assign-free_vdev_map-value-before-ieee80211_r.patch @@ -0,0 +1,62 @@ +From 3c79cb4d63c0d58462d439efa0db328008354deb Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH] ath11k: Assign free_vdev_map value before + ieee80211_register_hw + +Firmware crash is seen randomly, because of sending wrong vdev_id +in vdev_create command. This is due to free_vdev_map value being 0. +free_vdev_map is getting assigned after ieee80211_register_hw. In +some race conditions, add_interface api is getting called before +assigning value to free_vdev_map. Fix this by assigning free_vdev_map +before ieee80211_register_hw. + +Also, moved ar->cc_freq_hz and ar->txmgmt_idr initialization before +ieee80211_register_hw to avoid such race conditions. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00948-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-6-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7711,6 +7711,10 @@ int ath11k_mac_register(struct ath11k_ba + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + ++ /* Initialize channel counters frequency value in hertz */ ++ ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; ++ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; ++ + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; +@@ -7721,18 +7725,14 @@ int ath11k_mac_register(struct ath11k_ba + ar->mac_addr[4] += i; + } + ++ idr_init(&ar->txmgmt_idr); ++ spin_lock_init(&ar->txmgmt_idr_lock); ++ + ret = __ath11k_mac_register(ar); + if (ret) + goto err_cleanup; +- +- idr_init(&ar->txmgmt_idr); +- spin_lock_init(&ar->txmgmt_idr_lock); + } + +- /* Initialize channel counters frequency value in hertz */ +- ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; +- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; +- + return 0; + + err_cleanup: diff --git a/package/kernel/mac80211/patches/ath11k/0030-ath11k-Fix-crash-during-firmware-recovery-on-reo-cmd.patch b/package/kernel/mac80211/patches/ath11k/0030-ath11k-Fix-crash-during-firmware-recovery-on-reo-cmd.patch new file mode 100644 index 000000000..38f3064fc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0030-ath11k-Fix-crash-during-firmware-recovery-on-reo-cmd.patch @@ -0,0 +1,63 @@ +From 8ee8d38ca4727667e05a1dedf546162207bde9fa Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH] ath11k: Fix crash during firmware recovery on reo cmd ring + access + +In scenario when a peer is disassociating, there could be +multiple places where a reo cmd ring is accessed, such as +during aggregation teardown, tid queue cleanup, etc. + +When this happens during firmware recovery where accessing of FW/HW +resources/registers is not recommended, accessing reo cmd ring in +this case could lead to crash or undefined behaviour. + +Hence avoid this by checking for corresponding flag to avoid +accessing reo cmd ring during firmware recovery. + +Sample crash: + +[ 3936.456050] Unhandled fault: imprecise external abort (0x1c06) at 0x54bb842a +[ 3936.456411] WARN: Access Violation!!!, Run "cat /sys/kernel/debug/qcom_debug_logs/tz_log" for more details +[ 3936.467997] pgd = b4474000 +[ 3936.477440] [54bb842a] *pgd=6fa61831, *pte=7f95d59f, *ppte=7f95de7e + +[ 3937.177436] [<8030ab10>] (_raw_spin_unlock_bh) from [<7f5e9eb8>] (ath11k_hal_reo_cmd_send+0x440/0x458 [ath11k]) +[ 3937.185730] [<7f5e9eb8>] (ath11k_hal_reo_cmd_send [ath11k]) from [<7f601c4c>] (ath11k_dp_tx_send_reo_cmd+0x2c/0xcc [ath11k]) +[ 3937.195524] [<7f601c4c>] (ath11k_dp_tx_send_reo_cmd [ath11k]) from [<7f602f10>] (ath11k_peer_rx_tid_reo_update+0x84/0xbc [ath11k]) +[ 3937.206984] [<7f602f10>] (ath11k_peer_rx_tid_reo_update [ath11k]) from [<7f605a9c>] (ath11k_dp_rx_ampdu_stop+0xa8/0x130 [ath11k]) +[ 3937.218532] [<7f605a9c>] (ath11k_dp_rx_ampdu_stop [ath11k]) from [<7f5f6730>] (ath11k_mac_op_ampdu_action+0x6c/0x98 [ath11k]) +[ 3937.230250] [<7f5f6730>] (ath11k_mac_op_ampdu_action [ath11k]) from [] (___ieee80211_stop_rx_ba_session+0x98/0x144 [mac80211]) +[ 3937.241499] [] (___ieee80211_stop_rx_ba_session [mac80211]) from [] (ieee80211_sta_tear_down_BA_sessions+0x4c/0xf4 [) +[ 3937.253833] [] (ieee80211_sta_tear_down_BA_sessions [mac80211]) from [] (ieee80211_sta_eosp+0x5b8/0x960 [mac80211]) +[ 3937.266764] [] (ieee80211_sta_eosp [mac80211]) from [] (__sta_info_flush+0x9c/0x134 [mac80211]) +[ 3937.278826] [] (__sta_info_flush [mac80211]) from [] (ieee80211_stop_ap+0x14c/0x28c [mac80211]) +[ 3937.289240] [] (ieee80211_stop_ap [mac80211]) from [<7f509cf0>] (__cfg80211_stop_ap+0x4c/0xd8 [cfg80211]) +[ 3937.299629] [<7f509cf0>] (__cfg80211_stop_ap [cfg80211]) from [<7f4dddec>] (cfg80211_leave+0x24/0x30 [cfg80211]) +[ 3937.310041] [<7f4dddec>] (cfg80211_leave [cfg80211]) from [<7f4de03c>] (cfg80211_netdev_notifier_call+0x174/0x48c [cfg80211]) +[ 3937.320457] [<7f4de03c>] (cfg80211_netdev_notifier_call [cfg80211]) from [<80339928>] (notifier_call_chain+0x40/0x68) +[ 3937.331636] [<80339928>] (notifier_call_chain) from [<803399a8>] (raw_notifier_call_chain+0x14/0x1c) +[ 3937.342221] [<803399a8>] (raw_notifier_call_chain) from [<8073bb00>] (call_netdevice_notifiers+0xc/0x14) + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01240-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-7-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -622,6 +622,9 @@ int ath11k_dp_tx_send_reo_cmd(struct ath + struct hal_srng *cmd_ring; + int cmd_num; + ++ if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) ++ return -ESHUTDOWN; ++ + cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id]; + cmd_num = ath11k_hal_reo_cmd_send(ab, cmd_ring, type, cmd); + diff --git a/package/kernel/mac80211/patches/ath11k/0031-ath11k-Avoid-No-VIF-found-warning-message.patch b/package/kernel/mac80211/patches/ath11k/0031-ath11k-Avoid-No-VIF-found-warning-message.patch new file mode 100644 index 000000000..0798c0d43 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0031-ath11k-Avoid-No-VIF-found-warning-message.patch @@ -0,0 +1,44 @@ +From 79feedfea7793d91293ab72fac5fc66aae0c6a85 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Tue, 28 Sep 2021 12:05:41 +0300 +Subject: [PATCH] ath11k: Avoid "No VIF found" warning message + +Facing below warning prints when we do wifi down in multiple VAPs scenario. + +warning print: + +ath11k c000000.wifi: No VIF found for vdev 2 +... +ath11k c000000.wifi: No VIF found for vdev 0 + +In ath11k_mac_get_arvif_by_vdev_id(), we iterate all the radio to get the +arvif for the requested vdev_id through ath11k_mac_get_arvif(). +ath11k_mac_get_arvif() throws a warning message if the given vdev_id is +not found in the given radio. So to avoid the warning message, add +the allocated_vdev_map cross check against the given vdev_id before using +ath11k_mac_get_arvif() to ensure that vdev_id is allocated in the +given radio. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-8-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -501,7 +501,8 @@ struct ath11k_vif *ath11k_mac_get_arvif_ + + for (i = 0; i < ab->num_radios; i++) { + pdev = rcu_dereference(ab->pdevs_active[i]); +- if (pdev && pdev->ar) { ++ if (pdev && pdev->ar && ++ (pdev->ar->allocated_vdev_map & (1LL << vdev_id))) { + arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id); + if (arvif) + return arvif; diff --git a/package/kernel/mac80211/patches/ath11k/0032-ath11k-Add-wmi-peer-create-conf-event-in-wmi_tlv_eve.patch b/package/kernel/mac80211/patches/ath11k/0032-ath11k-Add-wmi-peer-create-conf-event-in-wmi_tlv_eve.patch new file mode 100644 index 000000000..89b68fd22 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0032-ath11k-Add-wmi-peer-create-conf-event-in-wmi_tlv_eve.patch @@ -0,0 +1,50 @@ +From 94a6df31dcf042f74db8209680d04546ce964ad5 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Tue, 28 Sep 2021 12:05:41 +0300 +Subject: [PATCH] ath11k: Add wmi peer create conf event in wmi_tlv_event_id + +When the driver sends a peer create cmd, the firmware responds with +WMI_PEER_CREATE_CONF_EVENTID to confirm the firmware received +WMI_PEER_CREATE_CMDID. Since the peer create conf event is not handled +in ath11k_wmi_tlv_op_rx, we are getting unknown event id warning prints +during peer creation. + +Add WMI_PEER_CREATE_CONF_EVENTID in wmi_tlv_event_id and handle +the same as unsupported event id under wmi logs. + +warning prints: +[ 4382.230817] ath11k_pci 0000:01:00.0: Unknown eventid: 0x601a + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: P Praneesh +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-9-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 1 + + drivers/net/wireless/ath/ath11k/wmi.h | 3 +++ + 2 files changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7137,6 +7137,7 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_TWT_ENABLE_EVENTID: + case WMI_TWT_DISABLE_EVENTID: + case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ++ case WMI_PEER_CREATE_CONF_EVENTID: + ath11k_dbg(ab, ATH11K_DBG_WMI, + "ignoring unsupported event 0x%x\n", id); + break; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -663,6 +663,9 @@ enum wmi_tlv_event_id { + WMI_PEER_RESERVED9_EVENTID, + WMI_PEER_RESERVED10_EVENTID, + WMI_PEER_OPER_MODE_CHANGE_EVENTID, ++ WMI_PEER_TX_PN_RESPONSE_EVENTID, ++ WMI_PEER_CFR_CAPTURE_EVENTID, ++ WMI_PEER_CREATE_CONF_EVENTID, + WMI_MGMT_RX_EVENTID = WMI_TLV_CMD(WMI_GRP_MGMT), + WMI_HOST_SWBA_EVENTID, + WMI_TBTTOFFSET_UPDATE_EVENTID, diff --git a/package/kernel/mac80211/patches/ath11k/0033-ath11k-add-channel-2-into-6-GHz-channel-list.patch b/package/kernel/mac80211/patches/ath11k/0033-ath11k-add-channel-2-into-6-GHz-channel-list.patch new file mode 100644 index 000000000..4e3d5d4fe --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0033-ath11k-add-channel-2-into-6-GHz-channel-list.patch @@ -0,0 +1,43 @@ +From 4a9550f536cc9c62210f77d875f000e560fc64b1 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH] ath11k: add channel 2 into 6 GHz channel list + +Add support for the 6 GHz channel 2 with center frequency 5935 MHz and +operating class 136 per IEEE Std 802.11ax-2021, Table E-4. + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210722102054.43419-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 4 ++-- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -393,9 +393,9 @@ struct ath11k_sta { + }; + + #define ATH11K_MIN_5G_FREQ 4150 +-#define ATH11K_MIN_6G_FREQ 5945 ++#define ATH11K_MIN_6G_FREQ 5925 + #define ATH11K_MAX_6G_FREQ 7115 +-#define ATH11K_NUM_CHANS 100 ++#define ATH11K_NUM_CHANS 101 + #define ATH11K_MAX_5G_CHAN 173 + + enum ath11k_state { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -151,6 +151,9 @@ static const struct ieee80211_channel at + CHAN6G(225, 7075, 0), + CHAN6G(229, 7095, 0), + CHAN6G(233, 7115, 0), ++ ++ /* new addition in IEEE Std 802.11ax-2021 */ ++ CHAN6G(2, 5935, 0), + }; + + static struct ieee80211_rate ath11k_legacy_rates[] = { diff --git a/package/kernel/mac80211/patches/ath11k/0035-ath11k-fix-survey-dump-collection-in-6-GHz.patch b/package/kernel/mac80211/patches/ath11k/0035-ath11k-fix-survey-dump-collection-in-6-GHz.patch new file mode 100644 index 000000000..8d612b3af --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0035-ath11k-fix-survey-dump-collection-in-6-GHz.patch @@ -0,0 +1,35 @@ +From b6b142f644d2d88e2ceabe0aa4479e0a09ba1ea9 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH] ath11k: fix survey dump collection in 6 GHz + +When ath11k receives survey request, choose the 6 GHz band when enabled. +Without this, survey request does not include any 6 GHz band results, +thereby causing auto channel selection to fail. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210722102054.43419-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7182,7 +7182,13 @@ static int ath11k_mac_op_get_survey(stru + + if (!sband) + sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; ++ if (sband && idx >= sband->n_channels) { ++ idx -= sband->n_channels; ++ sband = NULL; ++ } + ++ if (!sband) ++ sband = hw->wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband || idx >= sband->n_channels) { + ret = -ENOENT; + goto exit; diff --git a/package/kernel/mac80211/patches/ath11k/0036-ath11k-re-enable-ht_cap-vht_cap-for-5G-band-for-WCN6.patch b/package/kernel/mac80211/patches/ath11k/0036-ath11k-re-enable-ht_cap-vht_cap-for-5G-band-for-WCN6.patch new file mode 100644 index 000000000..a0c1288a8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0036-ath11k-re-enable-ht_cap-vht_cap-for-5G-band-for-WCN6.patch @@ -0,0 +1,34 @@ +From 54f40f552afd5a07e635a52221ec4b0ce765c374 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH] ath11k: re-enable ht_cap/vht_cap for 5G band for WCN6855 + +WCN6855 uses single_pdev_only, so it supports both the 5G and 6G bands +in the same ath11k/pdev and it needs to enable ht_cap/vht_cap for the 5G +band, otherwise it will downgrade to non-HT mode for the 5G band. Some +chips like QCN9074 only support the 6G band, not the 5G band, and use +the flag ar->supports_6ghz which is true to discard ht_cap/vht_cap. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210804181217.88751-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4551,7 +4551,9 @@ static void ath11k_mac_setup_ht_vht_cap( + rate_cap_rx_chainmask); + } + +- if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && !ar->supports_6ghz) { ++ if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && ++ (ar->ab->hw_params.single_pdev_only || ++ !ar->supports_6ghz)) { + band = &ar->mac.sbands[NL80211_BAND_5GHZ]; + ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info; + if (ht_cap_info) diff --git a/package/kernel/mac80211/patches/ath11k/0037-ath11k-enable-6G-channels-for-WCN6855.patch b/package/kernel/mac80211/patches/ath11k/0037-ath11k-enable-6G-channels-for-WCN6855.patch new file mode 100644 index 000000000..550f9d3c3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0037-ath11k-enable-6G-channels-for-WCN6855.patch @@ -0,0 +1,98 @@ +From 74bba5e5ba45d511a944082d76b64cc1849e4c2e Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH] ath11k: enable 6G channels for WCN6855 + +For some chips such as WCN6855, single_pdev_only is set in struct +ath11k_hw_params which means ath11k calls ieee80211_register_hw() only +once and create only one device interface, and that device interface +supports all 2G/5G/6G channels. + +ath11k_mac_setup_channels_rates() sets up the channels and it is called +for each device interface. It is called only once for single_pdev_only, +and then set up all channels for 2G/5G/6G. The logic of +ath11k_mac_setup_channels_rates() is not suitable for single_pdev_only, +it leads to all 6G channels being disabled for the device interface +which is single_pdev_only such as WCN6855. + +Add channel frequency checks for the 6G band and enable the 6G channels +properly based on what is supported by the chip. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210804181217.88751-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7322,7 +7322,7 @@ static int ath11k_mac_setup_channels_rat + u32 supported_bands) + { + struct ieee80211_supported_band *band; +- struct ath11k_hal_reg_capabilities_ext *reg_cap; ++ struct ath11k_hal_reg_capabilities_ext *reg_cap, *temp_reg_cap; + void *channels; + u32 phy_id; + +@@ -7332,6 +7332,7 @@ static int ath11k_mac_setup_channels_rat + ATH11K_NUM_CHANS); + + reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx]; ++ temp_reg_cap = reg_cap; + + if (supported_bands & WMI_HOST_WLAN_2G_CAP) { + channels = kmemdup(ath11k_2ghz_channels, +@@ -7350,11 +7351,11 @@ static int ath11k_mac_setup_channels_rat + + if (ar->ab->hw_params.single_pdev_only) { + phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); +- reg_cap = &ar->ab->hal_reg_cap[phy_id]; ++ temp_reg_cap = &ar->ab->hal_reg_cap[phy_id]; + } + ath11k_mac_update_ch_list(ar, band, +- reg_cap->low_2ghz_chan, +- reg_cap->high_2ghz_chan); ++ temp_reg_cap->low_2ghz_chan, ++ temp_reg_cap->high_2ghz_chan); + } + + if (supported_bands & WMI_HOST_WLAN_5G_CAP) { +@@ -7374,9 +7375,15 @@ static int ath11k_mac_setup_channels_rat + band->n_bitrates = ath11k_a_rates_size; + band->bitrates = ath11k_a_rates; + ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band; ++ ++ if (ar->ab->hw_params.single_pdev_only) { ++ phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); ++ temp_reg_cap = &ar->ab->hal_reg_cap[phy_id]; ++ } ++ + ath11k_mac_update_ch_list(ar, band, +- reg_cap->low_5ghz_chan, +- reg_cap->high_5ghz_chan); ++ temp_reg_cap->low_5ghz_chan, ++ temp_reg_cap->high_5ghz_chan); + } + + if (reg_cap->low_5ghz_chan < ATH11K_MIN_6G_FREQ) { +@@ -7399,12 +7406,12 @@ static int ath11k_mac_setup_channels_rat + + if (ar->ab->hw_params.single_pdev_only) { + phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); +- reg_cap = &ar->ab->hal_reg_cap[phy_id]; ++ temp_reg_cap = &ar->ab->hal_reg_cap[phy_id]; + } + + ath11k_mac_update_ch_list(ar, band, +- reg_cap->low_5ghz_chan, +- reg_cap->high_5ghz_chan); ++ temp_reg_cap->low_5ghz_chan, ++ temp_reg_cap->high_5ghz_chan); + } + } + diff --git a/package/kernel/mac80211/patches/ath11k/0038-ath11k-copy-cap-info-of-6G-band-under-WMI_HOST_WLAN_.patch b/package/kernel/mac80211/patches/ath11k/0038-ath11k-copy-cap-info-of-6G-band-under-WMI_HOST_WLAN_.patch new file mode 100644 index 000000000..71bc68062 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0038-ath11k-copy-cap-info-of-6G-band-under-WMI_HOST_WLAN_.patch @@ -0,0 +1,54 @@ +From 0f17ae43823b237c73ff138bc067229f7c57e3a2 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH] ath11k: copy cap info of 6G band under WMI_HOST_WLAN_5G_CAP + for WCN6855 + +WCN6855 has 2 phys, one is 2G, another is 5G/6G, so it should copy the +cap info of 6G band under the check of WMI_HOST_WLAN_5G_CAP as well as +for the 5G band. Some chips like QCN9074 only have 6G, not have 2G and +5G, and this 6G capability is also under WMI_HOST_WLAN_5G_CAP, so this +change will not disturb it. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210804181217.88751-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -407,18 +407,18 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); + memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, + sizeof(struct ath11k_ppe_threshold)); +- } + +- cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; +- cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; +- cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; +- cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; +- cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; +- cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; +- memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, +- sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); +- memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, +- sizeof(struct ath11k_ppe_threshold)); ++ cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; ++ cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; ++ cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; ++ cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; ++ cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; ++ cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; ++ memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, ++ sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); ++ memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, ++ sizeof(struct ath11k_ppe_threshold)); ++ } + + return 0; + } diff --git a/package/kernel/mac80211/patches/ath11k/0039-ath11k-Drop-MSDU-with-length-error-in-DP-rx-path.patch b/package/kernel/mac80211/patches/ath11k/0039-ath11k-Drop-MSDU-with-length-error-in-DP-rx-path.patch new file mode 100644 index 000000000..ac19edd81 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0039-ath11k-Drop-MSDU-with-length-error-in-DP-rx-path.patch @@ -0,0 +1,57 @@ +From cd18ed4cf8051ceb8590263f5914cb9bb58b0f25 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH] ath11k: Drop MSDU with length error in DP rx path + +There are MSDUs whose length are invalid. For example, +attackers may inject on purpose truncated A-MSDUs with +invalid MSDU length. + +Such MSDUs are marked with an err bit set in rx attention +tlvs, so we can check and drop them. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913180246.193388-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -142,6 +142,18 @@ static u32 ath11k_dp_rx_h_attn_mpdu_err( + return errmap; + } + ++static bool ath11k_dp_rx_h_attn_msdu_len_err(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ struct rx_attention *rx_attention; ++ u32 errmap; ++ ++ rx_attention = ath11k_dp_rx_get_attention(ab, desc); ++ errmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); ++ ++ return errmap & DP_RX_MPDU_ERR_MSDU_LEN; ++} ++ + static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, + struct hal_rx_desc *desc) + { +@@ -2525,6 +2537,12 @@ static int ath11k_dp_rx_process_msdu(str + } + + rx_desc = (struct hal_rx_desc *)msdu->data; ++ if (ath11k_dp_rx_h_attn_msdu_len_err(ab, rx_desc)) { ++ ath11k_warn(ar->ab, "msdu len not valid\n"); ++ ret = -EIO; ++ goto free_out; ++ } ++ + lrx_desc = (struct hal_rx_desc *)last_buf->data; + rx_attention = ath11k_dp_rx_get_attention(ab, lrx_desc); + if (!ath11k_dp_rx_h_attn_msdu_done(rx_attention)) { diff --git a/package/kernel/mac80211/patches/ath11k/0040-ath11k-Fix-inaccessible-debug-registers.patch b/package/kernel/mac80211/patches/ath11k/0040-ath11k-Fix-inaccessible-debug-registers.patch new file mode 100644 index 000000000..3563d0028 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0040-ath11k-Fix-inaccessible-debug-registers.patch @@ -0,0 +1,46 @@ +From 8a0b899f169d6b6102918327d026922140194fff Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Tue, 28 Sep 2021 14:00:44 +0300 +Subject: [PATCH] ath11k: Fix inaccessible debug registers + +Current code clears debug registers after SOC global reset performed +in ath11k_pci_sw_reset. However at that time those registers are +not accessible due to reset, thus they are actually not cleared at all. +For WCN6855, it may cause target fail to initialize. This issue can be +fixed by moving clear action ahead. + +In addition, on some specific platforms, need to add delay to wait +those registers to become accessible. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913180246.193388-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -430,6 +430,8 @@ static void ath11k_pci_force_wake(struct + + static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) + { ++ mdelay(100); ++ + if (power_on) { + ath11k_pci_enable_ltssm(ab); + ath11k_pci_clear_all_intrs(ab); +@@ -439,9 +441,9 @@ static void ath11k_pci_sw_reset(struct a + } + + ath11k_mhi_clear_vector(ab); ++ ath11k_pci_clear_dbg_registers(ab); + ath11k_pci_soc_global_reset(ab); + ath11k_mhi_set_mhictrl_reset(ab); +- ath11k_pci_clear_dbg_registers(ab); + } + + int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) diff --git a/package/kernel/mac80211/patches/ath11k/0042-ath11k-Rename-macro-ARRAY_TO_STRING-to-PRINT_ARRAY_T.patch b/package/kernel/mac80211/patches/ath11k/0042-ath11k-Rename-macro-ARRAY_TO_STRING-to-PRINT_ARRAY_T.patch new file mode 100644 index 000000000..3a6dd985f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0042-ath11k-Rename-macro-ARRAY_TO_STRING-to-PRINT_ARRAY_T.patch @@ -0,0 +1,852 @@ +From 9e2e2d7a4dd490ff6e95e37611070d3b3a9cf58b Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:44 +0300 +Subject: [PATCH] ath11k: Rename macro ARRAY_TO_STRING to PRINT_ARRAY_TO_BUF + +Renaming of macro is done to describe the macro functionality +better as the macro functionality is modified in next patch-sets. +No functional changes are done. + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-2-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 378 +++++++++--------- + 1 file changed, 189 insertions(+), 189 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -18,7 +18,7 @@ + + #define HTT_TLV_HDR_LEN 4 + +-#define ARRAY_TO_STRING(out, arr, len) \ ++#define PRINT_ARRAY_TO_BUF(out, arr, len) \ + do { \ + int index = 0; u8 i; \ + for (i = 0; i < len; i++) { \ +@@ -195,7 +195,7 @@ htt_print_tx_pdev_stats_urrn_tlv_v(const + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:"); + +- ARRAY_TO_STRING(urrn_stats, htt_stats_buf->urrn_stats, num_elems); ++ PRINT_ARRAY_TO_BUF(urrn_stats, htt_stats_buf->urrn_stats, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "urrn_stats = %s\n", urrn_stats); + + if (len >= buf_len) +@@ -220,7 +220,7 @@ htt_print_tx_pdev_stats_flush_tlv_v(cons + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:"); + +- ARRAY_TO_STRING(flush_errs, htt_stats_buf->flush_errs, num_elems); ++ PRINT_ARRAY_TO_BUF(flush_errs, htt_stats_buf->flush_errs, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_errs = %s\n", flush_errs); + + if (len >= buf_len) +@@ -245,7 +245,7 @@ htt_print_tx_pdev_stats_sifs_tlv_v(const + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:"); + +- ARRAY_TO_STRING(sifs_status, htt_stats_buf->sifs_status, num_elems); ++ PRINT_ARRAY_TO_BUF(sifs_status, htt_stats_buf->sifs_status, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_status = %s\n", + sifs_status); + +@@ -271,7 +271,7 @@ htt_print_tx_pdev_stats_phy_err_tlv_v(co + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:"); + +- ARRAY_TO_STRING(phy_errs, htt_stats_buf->phy_errs, num_elems); ++ PRINT_ARRAY_TO_BUF(phy_errs, htt_stats_buf->phy_errs, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); + + if (len >= buf_len) +@@ -297,7 +297,7 @@ htt_print_tx_pdev_stats_sifs_hist_tlv_v( + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:"); + +- ARRAY_TO_STRING(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); ++ PRINT_ARRAY_TO_BUF(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_hist_status = %s\n", + sifs_hist_status); + +@@ -363,9 +363,9 @@ htt_print_tx_pdev_stats_tried_mpdu_cnt_h + htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, ++ htt_stats_buf->tried_mpdu_cnt_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n", + tried_mpdu_cnt_hist); + } else { +@@ -667,9 +667,9 @@ static inline void htt_print_counter_tlv + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_COUNTER_TLV:"); + +- ARRAY_TO_STRING(counter_name, +- htt_stats_buf->counter_name, +- HTT_MAX_COUNTER_NAME); ++ PRINT_ARRAY_TO_BUF(counter_name, ++ htt_stats_buf->counter_name, ++ HTT_MAX_COUNTER_NAME); + len += HTT_DBG_OUT(buf + len, buf_len - len, "counter_name = %s ", counter_name); + len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n", + htt_stats_buf->count); +@@ -794,54 +794,54 @@ static inline void htt_print_tx_peer_rat + htt_stats_buf->ack_rssi); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_su_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_su_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_su_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mu_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mu_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mu_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, +- htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, ++ htt_stats_buf->tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, +- htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, ++ htt_stats_buf->tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); + + for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], +- htt_stats_buf->tx_gi[j], +- HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], ++ htt_stats_buf->tx_gi[j], ++ HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, +- htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, ++ htt_stats_buf->tx_dcm, ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); + + if (len >= buf_len) +@@ -895,47 +895,47 @@ static inline void htt_print_rx_peer_rat + htt_stats_buf->rssi_comb); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { +- ARRAY_TO_STRING(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PEER_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], ++ HTT_RX_PEER_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", + j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); + + if (len >= buf_len) +@@ -1115,10 +1115,10 @@ htt_print_tx_hwq_difs_latency_stats_tlv_ + len += HTT_DBG_OUT(buf + len, buf_len - len, "hist_intvl = %u", + htt_stats_buf->hist_intvl); + +- ARRAY_TO_STRING(difs_latency_hist, htt_stats_buf->difs_latency_hist, +- data_len); ++ PRINT_ARRAY_TO_BUF(difs_latency_hist, htt_stats_buf->difs_latency_hist, ++ data_len); + len += HTT_DBG_OUT(buf + len, buf_len - len, "difs_latency_hist = %s\n", +- difs_latency_hist); ++ difs_latency_hist); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1145,7 +1145,7 @@ htt_print_tx_hwq_cmd_result_stats_tlv_v( + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:"); + +- ARRAY_TO_STRING(cmd_result, htt_stats_buf->cmd_result, data_len); ++ PRINT_ARRAY_TO_BUF(cmd_result, htt_stats_buf->cmd_result, data_len); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_result = %s\n", cmd_result); + +@@ -1173,7 +1173,7 @@ htt_print_tx_hwq_cmd_stall_stats_tlv_v(c + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:"); + +- ARRAY_TO_STRING(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); ++ PRINT_ARRAY_TO_BUF(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_stall_status = %s\n", + cmd_stall_status); + +@@ -1202,7 +1202,7 @@ htt_print_tx_hwq_fes_result_stats_tlv_v( + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:"); + +- ARRAY_TO_STRING(fes_result, htt_stats_buf->fes_result, num_elems); ++ PRINT_ARRAY_TO_BUF(fes_result, htt_stats_buf->fes_result, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fes_result = %s\n", fes_result); + + if (len >= buf_len) +@@ -1233,9 +1233,9 @@ htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv + htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, ++ htt_stats_buf->tried_mpdu_cnt_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "tried_mpdu_cnt_hist = %s\n", + tried_mpdu_cnt_hist); +@@ -1269,9 +1269,9 @@ htt_print_tx_hwq_txop_used_cnt_hist_tlv_ + "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(txop_used_cnt_hist, +- htt_stats_buf->txop_used_cnt_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(txop_used_cnt_hist, ++ htt_stats_buf->txop_used_cnt_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n", + txop_used_cnt_hist); + } else { +@@ -1790,8 +1790,8 @@ htt_print_sched_txq_cmd_posted_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:"); + +- ARRAY_TO_STRING(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, +- num_elements); ++ PRINT_ARRAY_TO_BUF(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_posted = %s\n", + sched_cmd_posted); + +@@ -1817,8 +1817,8 @@ htt_print_sched_txq_cmd_reaped_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:"); + +- ARRAY_TO_STRING(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, +- num_elements); ++ PRINT_ARRAY_TO_BUF(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_reaped = %s\n", + sched_cmd_reaped); + +@@ -1847,8 +1847,8 @@ htt_print_sched_txq_sched_order_su_tlv_v + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:"); + +- ARRAY_TO_STRING(sched_order_su, htt_stats_buf->sched_order_su, +- sched_order_su_num_entries); ++ PRINT_ARRAY_TO_BUF(sched_order_su, htt_stats_buf->sched_order_su, ++ sched_order_su_num_entries); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_order_su = %s\n", + sched_order_su); + +@@ -1876,8 +1876,8 @@ htt_print_sched_txq_sched_ineligibility_ + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:"); + +- ARRAY_TO_STRING(sched_ineligibility, htt_stats_buf->sched_ineligibility, +- sched_ineligibility_num_entries); ++ PRINT_ARRAY_TO_BUF(sched_ineligibility, htt_stats_buf->sched_ineligibility, ++ sched_ineligibility_num_entries); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_ineligibility = %s\n", + sched_ineligibility); + +@@ -1992,8 +1992,8 @@ htt_print_tx_tqm_gen_mpdu_stats_tlv_v(co + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:"); + +- ARRAY_TO_STRING(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, +- num_elements); ++ PRINT_ARRAY_TO_BUF(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n", + gen_mpdu_end_reason); + +@@ -2020,8 +2020,8 @@ htt_print_tx_tqm_list_mpdu_stats_tlv_v(c + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:"); + +- ARRAY_TO_STRING(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, +- num_elems); ++ PRINT_ARRAY_TO_BUF(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n", + list_mpdu_end_reason); + if (len >= buf_len) +@@ -2047,8 +2047,8 @@ htt_print_tx_tqm_list_mpdu_cnt_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:"); + +- ARRAY_TO_STRING(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, +- num_elems); ++ PRINT_ARRAY_TO_BUF(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n", + list_mpdu_cnt_hist); + +@@ -2539,9 +2539,9 @@ htt_print_tx_de_fw2wbm_ring_full_hist_tl + "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(fw2wbm_ring_full_hist, +- htt_stats_buf->fw2wbm_ring_full_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(fw2wbm_ring_full_hist, ++ htt_stats_buf->fw2wbm_ring_full_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "fw2wbm_ring_full_hist = %s\n", + fw2wbm_ring_full_hist); +@@ -2634,13 +2634,13 @@ static inline void htt_print_ring_if_sta + len += HTT_DBG_OUT(buf + len, buf_len - len, "cons_blockwait_count = %u", + htt_stats_buf->cons_blockwait_count); + +- ARRAY_TO_STRING(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, +- HTT_STATS_LOW_WM_BINS); ++ PRINT_ARRAY_TO_BUF(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, ++ HTT_STATS_LOW_WM_BINS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "low_wm_hit_count = %s ", + low_wm_hit_count); + +- ARRAY_TO_STRING(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, +- HTT_STATS_HIGH_WM_BINS); ++ PRINT_ARRAY_TO_BUF(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, ++ HTT_STATS_HIGH_WM_BINS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "high_wm_hit_count = %s\n", + high_wm_hit_count); + +@@ -2687,9 +2687,9 @@ static inline void htt_print_sfm_client_ + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:"); + +- ARRAY_TO_STRING(dwords_used_by_user_n, +- htt_stats_buf->dwords_used_by_user_n, +- num_elems); ++ PRINT_ARRAY_TO_BUF(dwords_used_by_user_n, ++ htt_stats_buf->dwords_used_by_user_n, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n", + dwords_used_by_user_n); + +@@ -2889,73 +2889,73 @@ static inline void htt_print_tx_pdev_rat + htt_stats_buf->tx_legacy_ofdm_rate[7]); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u", +@@ -2965,16 +2965,16 @@ static inline void htt_print_tx_pdev_rat + + /* SU GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", + j, tx_gi[j]); + } + + /* AC MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "ac_mu_mimo_tx_gi[%u] = %s ", + j, tx_gi[j]); +@@ -2982,8 +2982,8 @@ static inline void htt_print_tx_pdev_rat + + /* AX MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "ax_mu_mimo_tx_gi[%u] = %s ", + j, tx_gi[j]); +@@ -2991,15 +2991,15 @@ static inline void htt_print_tx_pdev_rat + + /* DL OFDMA GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s ", + j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_dcm, ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); + + if (len >= buf_len) +@@ -3064,28 +3064,28 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->rssi_in_dbm); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_evm_nss_count = %u", + htt_stats_buf->nss_count); +@@ -3115,22 +3115,22 @@ static inline void htt_print_rx_pdev_rat + len += HTT_DBG_OUT(buf + len, buf_len - len, "pilot_evm_dB_mean = %s ", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- ARRAY_TO_STRING(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", + j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", + j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s", str_buf); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_su_ext = %u", +@@ -3145,14 +3145,14 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->txbf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_legacy_cck_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_cck_rate, ++ HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_cck_rate = %s ", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, ++ HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s ", + str_buf); + +@@ -3164,25 +3164,25 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->rx_11ax_ul_ofdma); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s ", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s ", + j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ul_ofdma_rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_nss, ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ul_ofdma_rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_bw, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s ", str_buf); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u", +@@ -3191,25 +3191,25 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->ul_ofdma_rx_ldpc); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s ", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s ", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s", + str_buf); + +@@ -3320,9 +3320,9 @@ htt_print_rx_soc_fw_refill_ring_empty_tl + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:"); + +- ARRAY_TO_STRING(refill_ring_empty_cnt, +- htt_stats_buf->refill_ring_empty_cnt, +- num_elems); ++ PRINT_ARRAY_TO_BUF(refill_ring_empty_cnt, ++ htt_stats_buf->refill_ring_empty_cnt, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n", + refill_ring_empty_cnt); + +@@ -3350,9 +3350,9 @@ htt_print_rx_soc_fw_refill_ring_num_rxdm + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:"); + +- ARRAY_TO_STRING(rxdma_err_cnt, +- htt_stats_buf->rxdma_err, +- num_elems); ++ PRINT_ARRAY_TO_BUF(rxdma_err_cnt, ++ htt_stats_buf->rxdma_err, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdma_err = %s\n", + rxdma_err_cnt); + +@@ -3379,9 +3379,9 @@ htt_print_rx_soc_fw_refill_ring_num_reo_ + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:"); + +- ARRAY_TO_STRING(reo_err_cnt, +- htt_stats_buf->reo_err, +- num_elems); ++ PRINT_ARRAY_TO_BUF(reo_err_cnt, ++ htt_stats_buf->reo_err, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "reo_err = %s\n", + reo_err_cnt); + +@@ -3447,9 +3447,9 @@ htt_print_rx_soc_fw_refill_ring_num_refi + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:"); + +- ARRAY_TO_STRING(refill_ring_num_refill, +- htt_stats_buf->refill_ring_num_refill, +- num_elems); ++ PRINT_ARRAY_TO_BUF(refill_ring_num_refill, ++ htt_stats_buf->refill_ring_num_refill, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_num_refill = %s\n", + refill_ring_num_refill); + +@@ -3491,15 +3491,15 @@ static inline void htt_print_rx_pdev_fw_ + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u", + htt_stats_buf->fw_ring_mpdu_ind); + +- ARRAY_TO_STRING(fw_ring_mgmt_subtype, +- htt_stats_buf->fw_ring_mgmt_subtype, +- HTT_STATS_SUBTYPE_MAX); ++ PRINT_ARRAY_TO_BUF(fw_ring_mgmt_subtype, ++ htt_stats_buf->fw_ring_mgmt_subtype, ++ HTT_STATS_SUBTYPE_MAX); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s ", + fw_ring_mgmt_subtype); + +- ARRAY_TO_STRING(fw_ring_ctrl_subtype, +- htt_stats_buf->fw_ring_ctrl_subtype, +- HTT_STATS_SUBTYPE_MAX); ++ PRINT_ARRAY_TO_BUF(fw_ring_ctrl_subtype, ++ htt_stats_buf->fw_ring_ctrl_subtype, ++ HTT_STATS_SUBTYPE_MAX); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s ", + fw_ring_ctrl_subtype); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u", +@@ -3597,9 +3597,9 @@ htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:"); + +- ARRAY_TO_STRING(fw_ring_mpdu_err, +- htt_stats_buf->fw_ring_mpdu_err, +- HTT_RX_STATS_RXDMA_MAX_ERR); ++ PRINT_ARRAY_TO_BUF(fw_ring_mpdu_err, ++ htt_stats_buf->fw_ring_mpdu_err, ++ HTT_RX_STATS_RXDMA_MAX_ERR); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n", + fw_ring_mpdu_err); + +@@ -3625,9 +3625,9 @@ htt_print_rx_pdev_fw_mpdu_drop_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:"); + +- ARRAY_TO_STRING(fw_mpdu_drop, +- htt_stats_buf->fw_mpdu_drop, +- num_elems); ++ PRINT_ARRAY_TO_BUF(fw_mpdu_drop, ++ htt_stats_buf->fw_mpdu_drop, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_mpdu_drop = %s\n", fw_mpdu_drop); + + if (len >= buf_len) +@@ -3654,9 +3654,9 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + len += HTT_DBG_OUT(buf + len, buf_len - len, "total_phy_err_nct = %u", + htt_stats_buf->total_phy_err_cnt); + +- ARRAY_TO_STRING(phy_errs, +- htt_stats_buf->phy_err, +- HTT_STATS_PHY_ERR_MAX); ++ PRINT_ARRAY_TO_BUF(phy_errs, ++ htt_stats_buf->phy_err, ++ HTT_STATS_PHY_ERR_MAX); + len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); + + if (len >= buf_len) diff --git a/package/kernel/mac80211/patches/ath11k/0043-ath11k-Replace-HTT_DBG_OUT-with-scnprintf.patch b/package/kernel/mac80211/patches/ath11k/0043-ath11k-Replace-HTT_DBG_OUT-with-scnprintf.patch new file mode 100644 index 000000000..cb2495a00 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0043-ath11k-Replace-HTT_DBG_OUT-with-scnprintf.patch @@ -0,0 +1,4451 @@ +From 6f442799bcfd62931ca100c7c5916bb5fc034302 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:44 +0300 +Subject: [PATCH] ath11k: Replace HTT_DBG_OUT with scnprintf + +Get rid of macro HTT_DBG_OUT and replace it with scnprintf(). +The macro does not do anything else. Added required new line +characters to scnprintf() for proper display. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01105-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-3-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 3370 ++++++++--------- + 1 file changed, 1683 insertions(+), 1687 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -10,9 +10,6 @@ + #include "debug.h" + #include "debugfs_htt_stats.h" + +-#define HTT_DBG_OUT(buf, len, fmt, ...) \ +- scnprintf(buf, len, fmt "\n", ##__VA_ARGS__) +- + #define HTT_MAX_STRING_LEN 256 + #define HTT_MAX_PRINT_CHAR_PER_ELEM 15 + +@@ -43,17 +40,17 @@ static inline void htt_print_stats_strin + + tag_len = tag_len >> 2; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n"); + + for (i = 0; i < tag_len; i++) { + index += scnprintf(&data[index], +- HTT_MAX_STRING_LEN - index, +- "%.*s", 4, (char *)&(htt_stats_buf->data[i])); ++ HTT_MAX_STRING_LEN - index, ++ "%.*s", 4, (char *)&(htt_stats_buf->data[i])); + if (index >= HTT_MAX_STRING_LEN) + break; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "data = %s\n", data); ++ len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -71,107 +68,107 @@ static inline void htt_print_tx_pdev_sta + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_queued = %u", +- htt_stats_buf->hw_queued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_reaped = %u", +- htt_stats_buf->hw_reaped); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun = %u", +- htt_stats_buf->underrun); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_paused = %u", +- htt_stats_buf->hw_paused); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_flush = %u", +- htt_stats_buf->hw_flush); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_filt = %u", +- htt_stats_buf->hw_filt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u", +- htt_stats_buf->tx_abort); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_requeued = %u", +- htt_stats_buf->mpdu_requeued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_xretry = %u", +- htt_stats_buf->tx_xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "data_rc = %u", +- htt_stats_buf->data_rc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_dropped_xretry = %u", +- htt_stats_buf->mpdu_dropped_xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "illegal_rate_phy_err = %u", +- htt_stats_buf->illgl_rate_phy_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cont_xretry = %u", +- htt_stats_buf->cont_xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_timeout = %u", +- htt_stats_buf->tx_timeout); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_resets = %u", +- htt_stats_buf->pdev_resets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_underrun = %u", +- htt_stats_buf->phy_underrun); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_ovf = %u", +- htt_stats_buf->txop_ovf); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_posted = %u", +- htt_stats_buf->seq_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_failed_queueing = %u", +- htt_stats_buf->seq_failed_queueing); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_completed = %u", +- htt_stats_buf->seq_completed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_restarted = %u", +- htt_stats_buf->seq_restarted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_seq_posted = %u", +- htt_stats_buf->mu_seq_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_switch_hw_paused = %u", +- htt_stats_buf->seq_switch_hw_paused); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "next_seq_posted_dsr = %u", +- htt_stats_buf->next_seq_posted_dsr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_posted_isr = %u", +- htt_stats_buf->seq_posted_isr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_ctrl_cached = %u", +- htt_stats_buf->seq_ctrl_cached); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_count_tqm = %u", +- htt_stats_buf->mpdu_count_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_count_tqm = %u", +- htt_stats_buf->msdu_count_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_removed_tqm = %u", +- htt_stats_buf->mpdu_removed_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_removed_tqm = %u", +- htt_stats_buf->msdu_removed_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_sw_flush = %u", +- htt_stats_buf->mpdus_sw_flush); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_hw_filter = %u", +- htt_stats_buf->mpdus_hw_filter); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_truncated = %u", +- htt_stats_buf->mpdus_truncated); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_ack_failed = %u", +- htt_stats_buf->mpdus_ack_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_expired = %u", +- htt_stats_buf->mpdus_expired); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u", +- htt_stats_buf->mpdus_seq_hw_retry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u", +- htt_stats_buf->ack_tlv_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u", +- htt_stats_buf->coex_abort_mpdu_cnt_valid); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u", +- htt_stats_buf->coex_abort_mpdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u", +- htt_stats_buf->num_total_ppdus_tried_ota); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u", +- htt_stats_buf->num_data_ppdus_tried_ota); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u", +- htt_stats_buf->local_ctrl_mgmt_enqued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u", +- htt_stats_buf->local_ctrl_mgmt_freed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_data_enqued = %u", +- htt_stats_buf->local_data_enqued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_data_freed = %u", +- htt_stats_buf->local_data_freed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_tried = %u", +- htt_stats_buf->mpdu_tried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "isr_wait_seq_posted = %u", +- htt_stats_buf->isr_wait_seq_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_active_dur_us_low = %u", +- htt_stats_buf->tx_active_dur_us_low); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n", +- htt_stats_buf->tx_active_dur_us_high); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", ++ htt_stats_buf->hw_queued); ++ len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", ++ htt_stats_buf->hw_reaped); ++ len += scnprintf(buf + len, buf_len - len, "underrun = %u\n", ++ htt_stats_buf->underrun); ++ len += scnprintf(buf + len, buf_len - len, "hw_paused = %u\n", ++ htt_stats_buf->hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "hw_flush = %u\n", ++ htt_stats_buf->hw_flush); ++ len += scnprintf(buf + len, buf_len - len, "hw_filt = %u\n", ++ htt_stats_buf->hw_filt); ++ len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", ++ htt_stats_buf->tx_abort); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_requeued = %u\n", ++ htt_stats_buf->mpdu_requeued); ++ len += scnprintf(buf + len, buf_len - len, "tx_xretry = %u\n", ++ htt_stats_buf->tx_xretry); ++ len += scnprintf(buf + len, buf_len - len, "data_rc = %u\n", ++ htt_stats_buf->data_rc); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_dropped_xretry = %u\n", ++ htt_stats_buf->mpdu_dropped_xretry); ++ len += scnprintf(buf + len, buf_len - len, "illegal_rate_phy_err = %u\n", ++ htt_stats_buf->illgl_rate_phy_err); ++ len += scnprintf(buf + len, buf_len - len, "cont_xretry = %u\n", ++ htt_stats_buf->cont_xretry); ++ len += scnprintf(buf + len, buf_len - len, "tx_timeout = %u\n", ++ htt_stats_buf->tx_timeout); ++ len += scnprintf(buf + len, buf_len - len, "pdev_resets = %u\n", ++ htt_stats_buf->pdev_resets); ++ len += scnprintf(buf + len, buf_len - len, "phy_underrun = %u\n", ++ htt_stats_buf->phy_underrun); ++ len += scnprintf(buf + len, buf_len - len, "txop_ovf = %u\n", ++ htt_stats_buf->txop_ovf); ++ len += scnprintf(buf + len, buf_len - len, "seq_posted = %u\n", ++ htt_stats_buf->seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "seq_failed_queueing = %u\n", ++ htt_stats_buf->seq_failed_queueing); ++ len += scnprintf(buf + len, buf_len - len, "seq_completed = %u\n", ++ htt_stats_buf->seq_completed); ++ len += scnprintf(buf + len, buf_len - len, "seq_restarted = %u\n", ++ htt_stats_buf->seq_restarted); ++ len += scnprintf(buf + len, buf_len - len, "mu_seq_posted = %u\n", ++ htt_stats_buf->mu_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "seq_switch_hw_paused = %u\n", ++ htt_stats_buf->seq_switch_hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "next_seq_posted_dsr = %u\n", ++ htt_stats_buf->next_seq_posted_dsr); ++ len += scnprintf(buf + len, buf_len - len, "seq_posted_isr = %u\n", ++ htt_stats_buf->seq_posted_isr); ++ len += scnprintf(buf + len, buf_len - len, "seq_ctrl_cached = %u\n", ++ htt_stats_buf->seq_ctrl_cached); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_count_tqm = %u\n", ++ htt_stats_buf->mpdu_count_tqm); ++ len += scnprintf(buf + len, buf_len - len, "msdu_count_tqm = %u\n", ++ htt_stats_buf->msdu_count_tqm); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_removed_tqm = %u\n", ++ htt_stats_buf->mpdu_removed_tqm); ++ len += scnprintf(buf + len, buf_len - len, "msdu_removed_tqm = %u\n", ++ htt_stats_buf->msdu_removed_tqm); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_sw_flush = %u\n", ++ htt_stats_buf->mpdus_sw_flush); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_hw_filter = %u\n", ++ htt_stats_buf->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_truncated = %u\n", ++ htt_stats_buf->mpdus_truncated); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_ack_failed = %u\n", ++ htt_stats_buf->mpdus_ack_failed); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_expired = %u\n", ++ htt_stats_buf->mpdus_expired); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u\n", ++ htt_stats_buf->mpdus_seq_hw_retry); ++ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", ++ htt_stats_buf->ack_tlv_proc); ++ len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u\n", ++ htt_stats_buf->coex_abort_mpdu_cnt_valid); ++ len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u\n", ++ htt_stats_buf->coex_abort_mpdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u\n", ++ htt_stats_buf->num_total_ppdus_tried_ota); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u\n", ++ htt_stats_buf->num_data_ppdus_tried_ota); ++ len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u\n", ++ htt_stats_buf->local_ctrl_mgmt_enqued); ++ len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u\n", ++ htt_stats_buf->local_ctrl_mgmt_freed); ++ len += scnprintf(buf + len, buf_len - len, "local_data_enqued = %u\n", ++ htt_stats_buf->local_data_enqued); ++ len += scnprintf(buf + len, buf_len - len, "local_data_freed = %u\n", ++ htt_stats_buf->local_data_freed); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_tried = %u\n", ++ htt_stats_buf->mpdu_tried); ++ len += scnprintf(buf + len, buf_len - len, "isr_wait_seq_posted = %u\n", ++ htt_stats_buf->isr_wait_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_low = %u\n", ++ htt_stats_buf->tx_active_dur_us_low); ++ len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n\n", ++ htt_stats_buf->tx_active_dur_us_high); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -193,10 +190,10 @@ htt_print_tx_pdev_stats_urrn_tlv_v(const + char urrn_stats[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_URRN_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(urrn_stats, htt_stats_buf->urrn_stats, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "urrn_stats = %s\n", urrn_stats); ++ len += scnprintf(buf + len, buf_len - len, "urrn_stats = %s\n\n", urrn_stats); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -218,10 +215,10 @@ htt_print_tx_pdev_stats_flush_tlv_v(cons + char flush_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_FLUSH_REASON_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(flush_errs, htt_stats_buf->flush_errs, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_errs = %s\n", flush_errs); ++ len += scnprintf(buf + len, buf_len - len, "flush_errs = %s\n\n", flush_errs); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -243,11 +240,11 @@ htt_print_tx_pdev_stats_sifs_tlv_v(const + char sifs_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sifs_status, htt_stats_buf->sifs_status, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_status = %s\n", +- sifs_status); ++ len += scnprintf(buf + len, buf_len - len, "sifs_status = %s\n\n", ++ sifs_status); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -269,10 +266,10 @@ htt_print_tx_pdev_stats_phy_err_tlv_v(co + char phy_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_PHY_ERR_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(phy_errs, htt_stats_buf->phy_errs, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); ++ len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -294,12 +291,12 @@ htt_print_tx_pdev_stats_sifs_hist_tlv_v( + char sifs_hist_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_hist_status = %s\n", +- sifs_hist_status); ++ len += scnprintf(buf + len, buf_len - len, "sifs_hist_status = %s\n\n", ++ sifs_hist_status); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -318,23 +315,23 @@ htt_print_tx_pdev_stats_tx_ppdu_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_TX_PPDU_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_TX_PPDU_STATS_TLV_V:\n"); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_legacy_su = %u", +- htt_stats_buf->num_data_ppdus_legacy_su); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_legacy_su = %u\n", ++ htt_stats_buf->num_data_ppdus_legacy_su); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ac_su = %u", +- htt_stats_buf->num_data_ppdus_ac_su); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ac_su = %u\n", ++ htt_stats_buf->num_data_ppdus_ac_su); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ax_su = %u", +- htt_stats_buf->num_data_ppdus_ax_su); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ax_su = %u\n", ++ htt_stats_buf->num_data_ppdus_ax_su); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ac_su_txbf = %u", +- htt_stats_buf->num_data_ppdus_ac_su_txbf); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ac_su_txbf = %u\n", ++ htt_stats_buf->num_data_ppdus_ac_su_txbf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ax_su_txbf = %u\n", +- htt_stats_buf->num_data_ppdus_ax_su_txbf); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ax_su_txbf = %u\n\n", ++ htt_stats_buf->num_data_ppdus_ax_su_txbf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -357,20 +354,20 @@ htt_print_tx_pdev_stats_tried_mpdu_cnt_h + u32 num_elements = ((tag_len - sizeof(htt_stats_buf->hist_bin_size)) >> 2); + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u", +- htt_stats_buf->hist_bin_size); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", ++ htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, + htt_stats_buf->tried_mpdu_cnt_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n", +- tried_mpdu_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n\n", ++ tried_mpdu_cnt_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n\n"); + } + + if (len >= buf_len) +@@ -390,14 +387,14 @@ static inline void htt_print_hw_stats_in + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:\n"); + memcpy(hw_intr_name, &(htt_stats_buf->hw_intr_name[0]), + HTT_STATS_MAX_HW_INTR_NAME_LEN); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_intr_name = %s ", hw_intr_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mask = %u", +- htt_stats_buf->mask); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n", +- htt_stats_buf->count); ++ len += scnprintf(buf + len, buf_len - len, "hw_intr_name = %s\n", hw_intr_name); ++ len += scnprintf(buf + len, buf_len - len, "mask = %u\n", ++ htt_stats_buf->mask); ++ len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", ++ htt_stats_buf->count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -417,13 +414,13 @@ htt_print_hw_stats_wd_timeout_tlv(const + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:\n"); + memcpy(hw_module_name, &(htt_stats_buf->hw_module_name[0]), + HTT_STATS_MAX_HW_MODULE_NAME_LEN); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_module_name = %s ", +- hw_module_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u", +- htt_stats_buf->count); ++ len += scnprintf(buf + len, buf_len - len, "hw_module_name = %s\n", ++ hw_module_name); ++ len += scnprintf(buf + len, buf_len - len, "count = %u\n", ++ htt_stats_buf->count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -441,29 +438,29 @@ static inline void htt_print_hw_stats_pd + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u", +- htt_stats_buf->tx_abort); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort_fail_count = %u", +- htt_stats_buf->tx_abort_fail_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_abort = %u", +- htt_stats_buf->rx_abort); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_abort_fail_count = %u", +- htt_stats_buf->rx_abort_fail_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "warm_reset = %u", +- htt_stats_buf->warm_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cold_reset = %u", +- htt_stats_buf->cold_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_flush = %u", +- htt_stats_buf->tx_flush); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_glb_reset = %u", +- htt_stats_buf->tx_glb_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_txq_reset = %u", +- htt_stats_buf->tx_txq_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_timeout_reset = %u\n", +- htt_stats_buf->rx_timeout_reset); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", ++ htt_stats_buf->tx_abort); ++ len += scnprintf(buf + len, buf_len - len, "tx_abort_fail_count = %u\n", ++ htt_stats_buf->tx_abort_fail_count); ++ len += scnprintf(buf + len, buf_len - len, "rx_abort = %u\n", ++ htt_stats_buf->rx_abort); ++ len += scnprintf(buf + len, buf_len - len, "rx_abort_fail_count = %u\n", ++ htt_stats_buf->rx_abort_fail_count); ++ len += scnprintf(buf + len, buf_len - len, "warm_reset = %u\n", ++ htt_stats_buf->warm_reset); ++ len += scnprintf(buf + len, buf_len - len, "cold_reset = %u\n", ++ htt_stats_buf->cold_reset); ++ len += scnprintf(buf + len, buf_len - len, "tx_flush = %u\n", ++ htt_stats_buf->tx_flush); ++ len += scnprintf(buf + len, buf_len - len, "tx_glb_reset = %u\n", ++ htt_stats_buf->tx_glb_reset); ++ len += scnprintf(buf + len, buf_len - len, "tx_txq_reset = %u\n", ++ htt_stats_buf->tx_txq_reset); ++ len += scnprintf(buf + len, buf_len - len, "rx_timeout_reset = %u\n\n", ++ htt_stats_buf->rx_timeout_reset); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -481,35 +478,34 @@ static inline void htt_print_msdu_flow_s + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_MSDU_FLOW_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_update_timestamp = %u", +- htt_stats_buf->last_update_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_add_timestamp = %u", +- htt_stats_buf->last_add_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_remove_timestamp = %u", +- htt_stats_buf->last_remove_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_processed_msdu_count = %u", +- htt_stats_buf->total_processed_msdu_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cur_msdu_count_in_flowq = %u", +- htt_stats_buf->cur_msdu_count_in_flowq); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_flow_no = %u", +- htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >> +- 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "drop_rule = %u", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >> +- 20); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_enqueue_count = %u", +- htt_stats_buf->last_cycle_enqueue_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_dequeue_count = %u", +- htt_stats_buf->last_cycle_dequeue_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_drop_count = %u", +- htt_stats_buf->last_cycle_drop_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_drop_th = %u\n", +- htt_stats_buf->current_drop_th); ++ len += scnprintf(buf + len, buf_len - len, "HTT_MSDU_FLOW_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "last_update_timestamp = %u\n", ++ htt_stats_buf->last_update_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "last_add_timestamp = %u\n", ++ htt_stats_buf->last_add_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "last_remove_timestamp = %u\n", ++ htt_stats_buf->last_remove_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "total_processed_msdu_count = %u\n", ++ htt_stats_buf->total_processed_msdu_count); ++ len += scnprintf(buf + len, buf_len - len, "cur_msdu_count_in_flowq = %u\n", ++ htt_stats_buf->cur_msdu_count_in_flowq); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id); ++ len += scnprintf(buf + len, buf_len - len, "tx_flow_no = %u\n", ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "drop_rule = %u\n", ++ (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >> ++ 20); ++ len += scnprintf(buf + len, buf_len - len, "last_cycle_enqueue_count = %u\n", ++ htt_stats_buf->last_cycle_enqueue_count); ++ len += scnprintf(buf + len, buf_len - len, "last_cycle_dequeue_count = %u\n", ++ htt_stats_buf->last_cycle_dequeue_count); ++ len += scnprintf(buf + len, buf_len - len, "last_cycle_drop_count = %u\n", ++ htt_stats_buf->last_cycle_drop_count); ++ len += scnprintf(buf + len, buf_len - len, "current_drop_th = %u\n\n", ++ htt_stats_buf->current_drop_th); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -528,38 +524,38 @@ static inline void htt_print_tx_tid_stat + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sched_pending = %u", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ppdu_in_hwq = %u", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_flags = 0x%x", +- htt_stats_buf->tid_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_queued = %u", +- htt_stats_buf->hw_queued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_reaped = %u", +- htt_stats_buf->hw_reaped); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_hw_filter = %u", +- htt_stats_buf->mpdus_hw_filter); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_bytes = %u", +- htt_stats_buf->qdepth_bytes); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_msdu = %u", +- htt_stats_buf->qdepth_num_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_mpdu = %u", +- htt_stats_buf->qdepth_num_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_scheduled_tsmp = %u", +- htt_stats_buf->last_scheduled_tsmp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_module_id = %u", +- htt_stats_buf->pause_module_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "block_module_id = %u\n", +- htt_stats_buf->block_module_id); ++ len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", ++ (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & ++ 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", ++ htt_stats_buf->tid_flags); ++ len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", ++ htt_stats_buf->hw_queued); ++ len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", ++ htt_stats_buf->hw_reaped); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_hw_filter = %u\n", ++ htt_stats_buf->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_bytes = %u\n", ++ htt_stats_buf->qdepth_bytes); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_msdu = %u\n", ++ htt_stats_buf->qdepth_num_msdu); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_mpdu = %u\n", ++ htt_stats_buf->qdepth_num_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "last_scheduled_tsmp = %u\n", ++ htt_stats_buf->last_scheduled_tsmp); ++ len += scnprintf(buf + len, buf_len - len, "pause_module_id = %u\n", ++ htt_stats_buf->pause_module_id); ++ len += scnprintf(buf + len, buf_len - len, "block_module_id = %u\n\n", ++ htt_stats_buf->block_module_id); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -578,42 +574,42 @@ static inline void htt_print_tx_tid_stat + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sched_pending = %u", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ppdu_in_hwq = %u", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_flags = 0x%x", +- htt_stats_buf->tid_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "max_qdepth_bytes = %u", +- htt_stats_buf->max_qdepth_bytes); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "max_qdepth_n_msdus = %u", +- htt_stats_buf->max_qdepth_n_msdus); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rsvd = %u", +- htt_stats_buf->rsvd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_bytes = %u", +- htt_stats_buf->qdepth_bytes); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_msdu = %u", +- htt_stats_buf->qdepth_num_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_mpdu = %u", +- htt_stats_buf->qdepth_num_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_scheduled_tsmp = %u", +- htt_stats_buf->last_scheduled_tsmp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_module_id = %u", +- htt_stats_buf->pause_module_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "block_module_id = %u", +- htt_stats_buf->block_module_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "allow_n_flags = 0x%x", +- htt_stats_buf->allow_n_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sendn_frms_allowed = %u\n", +- htt_stats_buf->sendn_frms_allowed); ++ len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", ++ (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & ++ 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", ++ htt_stats_buf->tid_flags); ++ len += scnprintf(buf + len, buf_len - len, "max_qdepth_bytes = %u\n", ++ htt_stats_buf->max_qdepth_bytes); ++ len += scnprintf(buf + len, buf_len - len, "max_qdepth_n_msdus = %u\n", ++ htt_stats_buf->max_qdepth_n_msdus); ++ len += scnprintf(buf + len, buf_len - len, "rsvd = %u\n", ++ htt_stats_buf->rsvd); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_bytes = %u\n", ++ htt_stats_buf->qdepth_bytes); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_msdu = %u\n", ++ htt_stats_buf->qdepth_num_msdu); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_mpdu = %u\n", ++ htt_stats_buf->qdepth_num_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "last_scheduled_tsmp = %u\n", ++ htt_stats_buf->last_scheduled_tsmp); ++ len += scnprintf(buf + len, buf_len - len, "pause_module_id = %u\n", ++ htt_stats_buf->pause_module_id); ++ len += scnprintf(buf + len, buf_len - len, "block_module_id = %u\n", ++ htt_stats_buf->block_module_id); ++ len += scnprintf(buf + len, buf_len - len, "allow_n_flags = 0x%x\n", ++ htt_stats_buf->allow_n_flags); ++ len += scnprintf(buf + len, buf_len - len, "sendn_frms_allowed = %u\n\n", ++ htt_stats_buf->sendn_frms_allowed); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -632,21 +628,21 @@ static inline void htt_print_rx_tid_stat + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_in_reorder = %u", +- htt_stats_buf->dup_in_reorder); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_past_outside_window = %u", +- htt_stats_buf->dup_past_outside_window); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_past_within_window = %u", +- htt_stats_buf->dup_past_within_window); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdesc_err_decrypt = %u\n", +- htt_stats_buf->rxdesc_err_decrypt); ++ len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); ++ len += scnprintf(buf + len, buf_len - len, "dup_in_reorder = %u\n", ++ htt_stats_buf->dup_in_reorder); ++ len += scnprintf(buf + len, buf_len - len, "dup_past_outside_window = %u\n", ++ htt_stats_buf->dup_past_outside_window); ++ len += scnprintf(buf + len, buf_len - len, "dup_past_within_window = %u\n", ++ htt_stats_buf->dup_past_within_window); ++ len += scnprintf(buf + len, buf_len - len, "rxdesc_err_decrypt = %u\n\n", ++ htt_stats_buf->rxdesc_err_decrypt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -665,14 +661,14 @@ static inline void htt_print_counter_tlv + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char counter_name[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_COUNTER_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_COUNTER_TLV:\n"); + + PRINT_ARRAY_TO_BUF(counter_name, + htt_stats_buf->counter_name, + HTT_MAX_COUNTER_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "counter_name = %s ", counter_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n", +- htt_stats_buf->count); ++ len += scnprintf(buf + len, buf_len - len, "counter_name = %s\n", counter_name); ++ len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", ++ htt_stats_buf->count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -690,35 +686,35 @@ static inline void htt_print_peer_stats_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PEER_STATS_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ppdu_cnt = %u", +- htt_stats_buf->ppdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt = %u", +- htt_stats_buf->mpdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_cnt = %u", +- htt_stats_buf->msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_bitmap = %u", +- htt_stats_buf->pause_bitmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "block_bitmap = %u", +- htt_stats_buf->block_bitmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_rssi = %d", +- htt_stats_buf->rssi); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueued_count = %llu", +- htt_stats_buf->peer_enqueued_count_low | +- ((u64)htt_stats_buf->peer_enqueued_count_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dequeued_count = %llu", +- htt_stats_buf->peer_dequeued_count_low | +- ((u64)htt_stats_buf->peer_dequeued_count_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dropped_count = %llu", +- htt_stats_buf->peer_dropped_count_low | +- ((u64)htt_stats_buf->peer_dropped_count_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "transmitted_ppdu_bytes = %llu", +- htt_stats_buf->ppdu_transmitted_bytes_low | +- ((u64)htt_stats_buf->ppdu_transmitted_bytes_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ttl_removed_count = %u", +- htt_stats_buf->peer_ttl_removed_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "inactive_time = %u\n", +- htt_stats_buf->inactive_time); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PEER_STATS_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ppdu_cnt = %u\n", ++ htt_stats_buf->ppdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt = %u\n", ++ htt_stats_buf->mpdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "msdu_cnt = %u\n", ++ htt_stats_buf->msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "pause_bitmap = %u\n", ++ htt_stats_buf->pause_bitmap); ++ len += scnprintf(buf + len, buf_len - len, "block_bitmap = %u\n", ++ htt_stats_buf->block_bitmap); ++ len += scnprintf(buf + len, buf_len - len, "last_rssi = %d\n", ++ htt_stats_buf->rssi); ++ len += scnprintf(buf + len, buf_len - len, "enqueued_count = %llu\n", ++ htt_stats_buf->peer_enqueued_count_low | ++ ((u64)htt_stats_buf->peer_enqueued_count_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "dequeued_count = %llu\n", ++ htt_stats_buf->peer_dequeued_count_low | ++ ((u64)htt_stats_buf->peer_dequeued_count_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "dropped_count = %llu\n", ++ htt_stats_buf->peer_dropped_count_low | ++ ((u64)htt_stats_buf->peer_dropped_count_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "transmitted_ppdu_bytes = %llu\n", ++ htt_stats_buf->ppdu_transmitted_bytes_low | ++ ((u64)htt_stats_buf->ppdu_transmitted_bytes_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "ttl_removed_count = %u\n", ++ htt_stats_buf->peer_ttl_removed_count); ++ len += scnprintf(buf + len, buf_len - len, "inactive_time = %u\n\n", ++ htt_stats_buf->inactive_time); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -736,29 +732,29 @@ static inline void htt_print_peer_detail + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PEER_DETAILS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_type = %u", +- htt_stats_buf->peer_type); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "vdev_id = %u", +- htt_stats_buf->vdev_pdev_ast_idx & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ast_idx = %u", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x", +- htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF), +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_flags = 0x%x", +- htt_stats_buf->peer_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qpeer_flags = 0x%x\n", +- htt_stats_buf->qpeer_flags); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PEER_DETAILS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "peer_type = %u\n", ++ htt_stats_buf->peer_type); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id); ++ len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", ++ htt_stats_buf->vdev_pdev_ast_idx & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", ++ (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "ast_idx = %u\n", ++ (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, ++ "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF, ++ (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8, ++ (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16, ++ (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24, ++ (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF), ++ (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "peer_flags = 0x%x\n", ++ htt_stats_buf->peer_flags); ++ len += scnprintf(buf + len, buf_len - len, "qpeer_flags = 0x%x\n\n", ++ htt_stats_buf->qpeer_flags); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -785,64 +781,64 @@ static inline void htt_print_tx_peer_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_ldpc = %u", +- htt_stats_buf->tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_rssi = %u", +- htt_stats_buf->ack_rssi); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", ++ htt_stats_buf->tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "ack_rssi = %u\n", ++ htt_stats_buf->ack_rssi); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_su_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_su_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_su_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mu_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mu_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_mu_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, + htt_stats_buf->tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, + htt_stats_buf->tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, + HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); + + for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], + htt_stats_buf->tx_gi[j], + HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, + htt_stats_buf->tx_dcm, + HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -880,63 +876,63 @@ static inline void htt_print_rx_peer_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "nsts = %u", +- htt_stats_buf->nsts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ldpc = %u", +- htt_stats_buf->rx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_mgmt = %u", +- htt_stats_buf->rssi_mgmt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_data = %u", +- htt_stats_buf->rssi_data); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_comb = %u", +- htt_stats_buf->rssi_comb); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", ++ htt_stats_buf->nsts); ++ len += scnprintf(buf + len, buf_len - len, "rx_ldpc = %u\n", ++ htt_stats_buf->rx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_mgmt = %u\n", ++ htt_stats_buf->rssi_mgmt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_data = %u\n", ++ htt_stats_buf->rssi_data); ++ len += scnprintf(buf + len, buf_len - len, "rssi_comb = %u\n", ++ htt_stats_buf->rssi_comb); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, + HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, + HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { + PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], + HTT_RX_PEER_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", ++ j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, + HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n\n", str_buf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -962,13 +958,13 @@ htt_print_tx_hwq_mu_mimo_sch_stats_tlv(c + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_SCH_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_posted = %u", +- htt_stats_buf->mu_mimo_sch_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_failed = %u", +- htt_stats_buf->mu_mimo_sch_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n", +- htt_stats_buf->mu_mimo_ppdu_posted); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_SCH_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n", ++ htt_stats_buf->mu_mimo_sch_posted); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n", ++ htt_stats_buf->mu_mimo_sch_failed); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n\n", ++ htt_stats_buf->mu_mimo_ppdu_posted); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -987,22 +983,22 @@ htt_print_tx_hwq_mu_mimo_mpdu_stats_tlv( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_MU_MIMO_MPDU_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_queued_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_tried_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_failed_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_requeued_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_err_no_ba_usr = %u", +- htt_stats_buf->mu_mimo_err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdu_underrun_usr = %u", +- htt_stats_buf->mu_mimo_mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ampdu_underrun_usr = %u\n", +- htt_stats_buf->mu_mimo_ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_MU_MIMO_MPDU_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_queued_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_tried_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_failed_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_requeued_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_err_no_ba_usr = %u\n", ++ htt_stats_buf->mu_mimo_err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdu_underrun_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ampdu_underrun_usr = %u\n\n", ++ htt_stats_buf->mu_mimo_ampdu_underrun_usr); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1021,11 +1017,11 @@ htt_print_tx_hwq_mu_mimo_cmn_stats_tlv(c + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwq_id = %u\n", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__hwq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n\n", ++ (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1044,51 +1040,51 @@ htt_print_tx_hwq_stats_cmn_tlv(const voi + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + /* TODO: HKDBG */ +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwq_id = %u", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "xretry = %u", +- htt_stats_buf->xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun_cnt = %u", +- htt_stats_buf->underrun_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cnt = %u", +- htt_stats_buf->flush_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "filt_cnt = %u", +- htt_stats_buf->filt_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "null_mpdu_bmap = %u", +- htt_stats_buf->null_mpdu_bmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "user_ack_failure = %u", +- htt_stats_buf->user_ack_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u", +- htt_stats_buf->ack_tlv_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_id_proc = %u", +- htt_stats_buf->sched_id_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "null_mpdu_tx_count = %u", +- htt_stats_buf->null_mpdu_tx_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_bmap_not_recvd = %u", +- htt_stats_buf->mpdu_bmap_not_recvd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_bar = %u", +- htt_stats_buf->num_bar); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts = %u", +- htt_stats_buf->rts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cts2self = %u", +- htt_stats_buf->cts2self); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_null = %u", +- htt_stats_buf->qos_null); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_tried_cnt = %u", +- htt_stats_buf->mpdu_tried_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queued_cnt = %u", +- htt_stats_buf->mpdu_queued_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_ack_fail_cnt = %u", +- htt_stats_buf->mpdu_ack_fail_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_filt_cnt = %u", +- htt_stats_buf->mpdu_filt_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "false_mpdu_ack_count = %u", +- htt_stats_buf->false_mpdu_ack_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txq_timeout = %u\n", +- htt_stats_buf->txq_timeout); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__hwq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n", ++ (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "xretry = %u\n", ++ htt_stats_buf->xretry); ++ len += scnprintf(buf + len, buf_len - len, "underrun_cnt = %u\n", ++ htt_stats_buf->underrun_cnt); ++ len += scnprintf(buf + len, buf_len - len, "flush_cnt = %u\n", ++ htt_stats_buf->flush_cnt); ++ len += scnprintf(buf + len, buf_len - len, "filt_cnt = %u\n", ++ htt_stats_buf->filt_cnt); ++ len += scnprintf(buf + len, buf_len - len, "null_mpdu_bmap = %u\n", ++ htt_stats_buf->null_mpdu_bmap); ++ len += scnprintf(buf + len, buf_len - len, "user_ack_failure = %u\n", ++ htt_stats_buf->user_ack_failure); ++ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", ++ htt_stats_buf->ack_tlv_proc); ++ len += scnprintf(buf + len, buf_len - len, "sched_id_proc = %u\n", ++ htt_stats_buf->sched_id_proc); ++ len += scnprintf(buf + len, buf_len - len, "null_mpdu_tx_count = %u\n", ++ htt_stats_buf->null_mpdu_tx_count); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_bmap_not_recvd = %u\n", ++ htt_stats_buf->mpdu_bmap_not_recvd); ++ len += scnprintf(buf + len, buf_len - len, "num_bar = %u\n", ++ htt_stats_buf->num_bar); ++ len += scnprintf(buf + len, buf_len - len, "rts = %u\n", ++ htt_stats_buf->rts); ++ len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n", ++ htt_stats_buf->cts2self); ++ len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n", ++ htt_stats_buf->qos_null); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_tried_cnt = %u\n", ++ htt_stats_buf->mpdu_tried_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_queued_cnt = %u\n", ++ htt_stats_buf->mpdu_queued_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_ack_fail_cnt = %u\n", ++ htt_stats_buf->mpdu_ack_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_filt_cnt = %u\n", ++ htt_stats_buf->mpdu_filt_cnt); ++ len += scnprintf(buf + len, buf_len - len, "false_mpdu_ack_count = %u\n", ++ htt_stats_buf->false_mpdu_ack_count); ++ len += scnprintf(buf + len, buf_len - len, "txq_timeout = %u\n\n", ++ htt_stats_buf->txq_timeout); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1110,15 +1106,15 @@ htt_print_tx_hwq_difs_latency_stats_tlv_ + u16 data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS); + char difs_latency_hist[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hist_intvl = %u", +- htt_stats_buf->hist_intvl); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "hist_intvl = %u\n", ++ htt_stats_buf->hist_intvl); + + PRINT_ARRAY_TO_BUF(difs_latency_hist, htt_stats_buf->difs_latency_hist, + data_len); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "difs_latency_hist = %s\n", +- difs_latency_hist); ++ len += scnprintf(buf + len, buf_len - len, "difs_latency_hist = %s\n\n", ++ difs_latency_hist); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1142,12 +1138,12 @@ htt_print_tx_hwq_cmd_result_stats_tlv_v( + + data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_RESULT_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(cmd_result, htt_stats_buf->cmd_result, data_len); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_result = %s\n", cmd_result); ++ len += scnprintf(buf + len, buf_len - len, "cmd_result = %s\n\n", cmd_result); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1171,11 +1167,11 @@ htt_print_tx_hwq_cmd_stall_stats_tlv_v(c + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_STALL_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_stall_status = %s\n", +- cmd_stall_status); ++ len += scnprintf(buf + len, buf_len - len, "cmd_stall_status = %s\n\n", ++ cmd_stall_status); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1199,11 +1195,11 @@ htt_print_tx_hwq_fes_result_stats_tlv_v( + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_FES_RESULT_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(fes_result, htt_stats_buf->fes_result, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fes_result = %s\n", fes_result); ++ len += scnprintf(buf + len, buf_len - len, "fes_result = %s\n\n", fes_result); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1227,21 +1223,21 @@ htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv + sizeof(htt_stats_buf->hist_bin_size)) >> 2); + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u", +- htt_stats_buf->hist_bin_size); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", ++ htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, + htt_stats_buf->tried_mpdu_cnt_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "tried_mpdu_cnt_hist = %s\n", +- tried_mpdu_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, ++ "tried_mpdu_cnt_hist = %s\n\n", ++ tried_mpdu_cnt_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER "); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n"); + } + + if (len >= buf_len) +@@ -1265,18 +1261,18 @@ htt_print_tx_hwq_txop_used_cnt_hist_tlv_ + u32 num_elements = tag_len >> 2; + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:\n"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(txop_used_cnt_hist, + htt_stats_buf->txop_used_cnt_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n", +- txop_used_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n\n", ++ txop_used_cnt_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER "); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n"); + } + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1300,86 +1296,86 @@ static inline void htt_print_tx_sounding + const u32 *cbf_160 = htt_stats_buf->cbf_160; + + if (htt_stats_buf->tx_sounding_mode == HTT_TX_AC_SOUNDING_MODE) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "\nHTT_TX_AC_SOUNDING_STATS_TLV:\n"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u ", +- cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "\nHTT_TX_AC_SOUNDING_STATS_TLV:\n\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS; i++) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u ", +- i, +- htt_stats_buf->sounding[0], +- htt_stats_buf->sounding[1], +- htt_stats_buf->sounding[2], +- htt_stats_buf->sounding[3]); ++ len += scnprintf(buf + len, buf_len - len, ++ "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u\n", ++ i, ++ htt_stats_buf->sounding[0], ++ htt_stats_buf->sounding[1], ++ htt_stats_buf->sounding[2], ++ htt_stats_buf->sounding[3]); + } + } else if (htt_stats_buf->tx_sounding_mode == HTT_TX_AX_SOUNDING_MODE) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "\nHTT_TX_AX_SOUNDING_STATS_TLV:\n"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u ", +- cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "\nHTT_TX_AX_SOUNDING_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS; i++) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u ", +- i, +- htt_stats_buf->sounding[0], +- htt_stats_buf->sounding[1], +- htt_stats_buf->sounding[2], +- htt_stats_buf->sounding[3]); ++ len += scnprintf(buf + len, buf_len - len, ++ "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u\n", ++ i, ++ htt_stats_buf->sounding[0], ++ htt_stats_buf->sounding[1], ++ htt_stats_buf->sounding[2], ++ htt_stats_buf->sounding[3]); + } + } + +@@ -1400,31 +1396,31 @@ htt_print_tx_selfgen_cmn_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "su_bar = %u", +- htt_stats_buf->su_bar); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts = %u", +- htt_stats_buf->rts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cts2self = %u", +- htt_stats_buf->cts2self); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_null = %u", +- htt_stats_buf->qos_null); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_1 = %u", +- htt_stats_buf->delayed_bar_1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_2 = %u", +- htt_stats_buf->delayed_bar_2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_3 = %u", +- htt_stats_buf->delayed_bar_3); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_4 = %u", +- htt_stats_buf->delayed_bar_4); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_5 = %u", +- htt_stats_buf->delayed_bar_5); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_6 = %u", +- htt_stats_buf->delayed_bar_6); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_7 = %u\n", +- htt_stats_buf->delayed_bar_7); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n", ++ htt_stats_buf->su_bar); ++ len += scnprintf(buf + len, buf_len - len, "rts = %u\n", ++ htt_stats_buf->rts); ++ len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n", ++ htt_stats_buf->cts2self); ++ len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n", ++ htt_stats_buf->qos_null); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_1 = %u\n", ++ htt_stats_buf->delayed_bar_1); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_2 = %u\n", ++ htt_stats_buf->delayed_bar_2); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_3 = %u\n", ++ htt_stats_buf->delayed_bar_3); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_4 = %u\n", ++ htt_stats_buf->delayed_bar_4); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_5 = %u\n", ++ htt_stats_buf->delayed_bar_5); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_6 = %u\n", ++ htt_stats_buf->delayed_bar_6); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_7 = %u\n\n", ++ htt_stats_buf->delayed_bar_7); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1443,21 +1439,21 @@ htt_print_tx_selfgen_ac_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndpa = %u", +- htt_stats_buf->ac_su_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndp = %u", +- htt_stats_buf->ac_su_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndpa = %u", +- htt_stats_buf->ac_mu_mimo_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndp = %u", +- htt_stats_buf->ac_mu_mimo_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_1 = %u", +- htt_stats_buf->ac_mu_mimo_brpoll_1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_2 = %u", +- htt_stats_buf->ac_mu_mimo_brpoll_2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_3 = %u\n", +- htt_stats_buf->ac_mu_mimo_brpoll_3); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa = %u\n", ++ htt_stats_buf->ac_su_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndp = %u\n", ++ htt_stats_buf->ac_su_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brpoll_1 = %u\n", ++ htt_stats_buf->ac_mu_mimo_brpoll_1); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brpoll_2 = %u\n", ++ htt_stats_buf->ac_mu_mimo_brpoll_2); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brpoll_3 = %u\n\n", ++ htt_stats_buf->ac_mu_mimo_brpoll_3); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1476,37 +1472,37 @@ htt_print_tx_selfgen_ax_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndpa = %u", +- htt_stats_buf->ax_su_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndp = %u", +- htt_stats_buf->ax_su_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndpa = %u", +- htt_stats_buf->ax_mu_mimo_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndp = %u", +- htt_stats_buf->ax_mu_mimo_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_1 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_2 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_3 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_3); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_4 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_4); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_5 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_5); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_6 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_6); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_7 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_7); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_basic_trigger = %u", +- htt_stats_buf->ax_basic_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_bsr_trigger = %u", +- htt_stats_buf->ax_bsr_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_bar_trigger = %u", +- htt_stats_buf->ax_mu_bar_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n", +- htt_stats_buf->ax_mu_rts_trigger); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa = %u\n", ++ htt_stats_buf->ax_su_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndp = %u\n", ++ htt_stats_buf->ax_su_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_1 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_1); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_2 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_2); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_3 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_3); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_4 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_4); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_5 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_5); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_6 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_6); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_7 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_7); ++ len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger = %u\n", ++ htt_stats_buf->ax_basic_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger = %u\n", ++ htt_stats_buf->ax_bsr_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger = %u\n", ++ htt_stats_buf->ax_mu_bar_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n\n", ++ htt_stats_buf->ax_mu_rts_trigger); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1525,21 +1521,21 @@ htt_print_tx_selfgen_ac_err_stats_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndp_err = %u", +- htt_stats_buf->ac_su_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndpa_err = %u", +- htt_stats_buf->ac_su_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u", +- htt_stats_buf->ac_mu_mimo_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u", +- htt_stats_buf->ac_mu_mimo_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u", +- htt_stats_buf->ac_mu_mimo_brp1_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u", +- htt_stats_buf->ac_mu_mimo_brp2_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n", +- htt_stats_buf->ac_mu_mimo_brp3_err); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_err = %u\n", ++ htt_stats_buf->ac_su_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_err = %u\n", ++ htt_stats_buf->ac_su_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_brp1_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_brp2_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n\n", ++ htt_stats_buf->ac_mu_mimo_brp3_err); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1558,37 +1554,37 @@ htt_print_tx_selfgen_ax_err_stats_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndp_err = %u", +- htt_stats_buf->ax_su_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndpa_err = %u", +- htt_stats_buf->ax_su_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u", +- htt_stats_buf->ax_mu_mimo_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u", +- htt_stats_buf->ax_mu_mimo_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp1_err = %u", +- htt_stats_buf->ax_mu_mimo_brp1_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp2_err = %u", +- htt_stats_buf->ax_mu_mimo_brp2_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp3_err = %u", +- htt_stats_buf->ax_mu_mimo_brp3_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp4_err = %u", +- htt_stats_buf->ax_mu_mimo_brp4_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp5_err = %u", +- htt_stats_buf->ax_mu_mimo_brp5_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp6_err = %u", +- htt_stats_buf->ax_mu_mimo_brp6_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp7_err = %u", +- htt_stats_buf->ax_mu_mimo_brp7_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_basic_trigger_err = %u", +- htt_stats_buf->ax_basic_trigger_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_bsr_trigger_err = %u", +- htt_stats_buf->ax_bsr_trigger_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u", +- htt_stats_buf->ax_mu_bar_trigger_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n", +- htt_stats_buf->ax_mu_rts_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_err = %u\n", ++ htt_stats_buf->ax_su_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_err = %u\n", ++ htt_stats_buf->ax_su_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp1_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp1_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp2_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp2_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp3_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp3_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp4_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp4_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp5_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp5_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp6_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp6_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp7_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp7_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger_err = %u\n", ++ htt_stats_buf->ax_basic_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger_err = %u\n", ++ htt_stats_buf->ax_bsr_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u\n", ++ htt_stats_buf->ax_mu_bar_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n\n", ++ htt_stats_buf->ax_mu_rts_trigger_err); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1608,35 +1604,35 @@ htt_print_tx_pdev_mu_mimo_sch_stats_tlv( + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 i; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_posted = %u", +- htt_stats_buf->mu_mimo_sch_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_failed = %u", +- htt_stats_buf->mu_mimo_sch_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n", +- htt_stats_buf->mu_mimo_ppdu_posted); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n", ++ htt_stats_buf->mu_mimo_sch_posted); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n", ++ htt_stats_buf->mu_mimo_sch_failed); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n\n", ++ htt_stats_buf->mu_mimo_ppdu_posted); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "11ac MU_MIMO SCH STATS:"); ++ len += scnprintf(buf + len, buf_len - len, "11ac MU_MIMO SCH STATS:\n"); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_sch_nusers_%u = %u", +- i, htt_stats_buf->ac_mu_mimo_sch_nusers[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_sch_nusers_%u = %u\n", ++ i, htt_stats_buf->ac_mu_mimo_sch_nusers[i]); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:"); ++ len += scnprintf(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:\n"); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_sch_nusers_%u = %u", +- i, htt_stats_buf->ax_mu_mimo_sch_nusers[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_sch_nusers_%u = %u\n", ++ i, htt_stats_buf->ax_mu_mimo_sch_nusers[i]); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:"); ++ len += scnprintf(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:\n"); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_ofdma_sch_nusers_%u = %u", +- i, htt_stats_buf->ax_ofdma_sch_nusers[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_sch_nusers_%u = %u\n", ++ i, htt_stats_buf->ax_ofdma_sch_nusers[i]); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1657,114 +1653,114 @@ htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv + + if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC) { + if (!htt_stats_buf->user_index) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n"); + + if (htt_stats_buf->user_index < + HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_queued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_tried_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_failed_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_requeued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_err_no_ba_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdu_underrun_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n", +- htt_stats_buf->user_index, +- htt_stats_buf->ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_queued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_tried_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_failed_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_requeued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_err_no_ba_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdu_underrun_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->ampdu_underrun_usr); + } + } + + if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX) { + if (!htt_stats_buf->user_index) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n"); + + if (htt_stats_buf->user_index < + HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_queued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_tried_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_failed_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_requeued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_err_no_ba_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdu_underrun_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n", +- htt_stats_buf->user_index, +- htt_stats_buf->ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_queued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_tried_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_failed_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_requeued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_err_no_ba_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdu_underrun_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->ampdu_underrun_usr); + } + } + + if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX) { + if (!htt_stats_buf->user_index) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n"); + + if (htt_stats_buf->user_index < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_queued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_tried_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_failed_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_requeued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_err_no_ba_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdu_underrun_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n", +- htt_stats_buf->user_index, +- htt_stats_buf->ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_queued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_tried_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_failed_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_requeued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_err_no_ba_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdu_underrun_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->ampdu_underrun_usr); + } + } + +@@ -1788,12 +1784,12 @@ htt_print_sched_txq_cmd_posted_tlv_v(con + char sched_cmd_posted[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_posted = %s\n", +- sched_cmd_posted); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmd_posted = %s\n\n", ++ sched_cmd_posted); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1815,12 +1811,12 @@ htt_print_sched_txq_cmd_reaped_tlv_v(con + char sched_cmd_reaped[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_reaped = %s\n", +- sched_cmd_reaped); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmd_reaped = %s\n\n", ++ sched_cmd_reaped); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1844,13 +1840,13 @@ htt_print_sched_txq_sched_order_su_tlv_v + u32 sched_order_su_num_entries = + min_t(u32, (tag_len >> 2), HTT_TX_PDEV_NUM_SCHED_ORDER_LOG); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_order_su, htt_stats_buf->sched_order_su, + sched_order_su_num_entries); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_order_su = %s\n", +- sched_order_su); ++ len += scnprintf(buf + len, buf_len - len, "sched_order_su = %s\n\n", ++ sched_order_su); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1873,13 +1869,13 @@ htt_print_sched_txq_sched_ineligibility_ + /* each entry is u32, i.e. 4 bytes */ + u32 sched_ineligibility_num_entries = tag_len >> 2; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_ineligibility, htt_stats_buf->sched_ineligibility, + sched_ineligibility_num_entries); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_ineligibility = %s\n", +- sched_ineligibility); ++ len += scnprintf(buf + len, buf_len - len, "sched_ineligibility = %s\n\n", ++ sched_ineligibility); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1898,54 +1894,54 @@ htt_print_tx_pdev_stats_sched_per_txq_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__txq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txq_id = %u", +- (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_policy = %u", +- htt_stats_buf->sched_policy); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "last_sched_cmd_posted_timestamp = %u", +- htt_stats_buf->last_sched_cmd_posted_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "last_sched_cmd_compl_timestamp = %u", +- htt_stats_buf->last_sched_cmd_compl_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_2_tac_lwm_count = %u", +- htt_stats_buf->sched_2_tac_lwm_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_2_tac_ring_full = %u", +- htt_stats_buf->sched_2_tac_ring_full); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_post_failure = %u", +- htt_stats_buf->sched_cmd_post_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_active_tids = %u", +- htt_stats_buf->num_active_tids); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ps_schedules = %u", +- htt_stats_buf->num_ps_schedules); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmds_pending = %u", +- htt_stats_buf->sched_cmds_pending); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tid_register = %u", +- htt_stats_buf->num_tid_register); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tid_unregister = %u", +- htt_stats_buf->num_tid_unregister); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_qstats_queried = %u", +- htt_stats_buf->num_qstats_queried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qstats_update_pending = %u", +- htt_stats_buf->qstats_update_pending); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_qstats_query_timestamp = %u", +- htt_stats_buf->last_qstats_query_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tqm_cmdq_full = %u", +- htt_stats_buf->num_tqm_cmdq_full); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_de_sched_algo_trigger = %u", +- htt_stats_buf->num_de_sched_algo_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_rt_sched_algo_trigger = %u", +- htt_stats_buf->num_rt_sched_algo_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tqm_sched_algo_trigger = %u", +- htt_stats_buf->num_tqm_sched_algo_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_sched = %u\n", +- htt_stats_buf->notify_sched); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dur_based_sendn_term = %u\n", +- htt_stats_buf->dur_based_sendn_term); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__txq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "txq_id = %u\n", ++ (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sched_policy = %u\n", ++ htt_stats_buf->sched_policy); ++ len += scnprintf(buf + len, buf_len - len, ++ "last_sched_cmd_posted_timestamp = %u\n", ++ htt_stats_buf->last_sched_cmd_posted_timestamp); ++ len += scnprintf(buf + len, buf_len - len, ++ "last_sched_cmd_compl_timestamp = %u\n", ++ htt_stats_buf->last_sched_cmd_compl_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "sched_2_tac_lwm_count = %u\n", ++ htt_stats_buf->sched_2_tac_lwm_count); ++ len += scnprintf(buf + len, buf_len - len, "sched_2_tac_ring_full = %u\n", ++ htt_stats_buf->sched_2_tac_ring_full); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmd_post_failure = %u\n", ++ htt_stats_buf->sched_cmd_post_failure); ++ len += scnprintf(buf + len, buf_len - len, "num_active_tids = %u\n", ++ htt_stats_buf->num_active_tids); ++ len += scnprintf(buf + len, buf_len - len, "num_ps_schedules = %u\n", ++ htt_stats_buf->num_ps_schedules); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmds_pending = %u\n", ++ htt_stats_buf->sched_cmds_pending); ++ len += scnprintf(buf + len, buf_len - len, "num_tid_register = %u\n", ++ htt_stats_buf->num_tid_register); ++ len += scnprintf(buf + len, buf_len - len, "num_tid_unregister = %u\n", ++ htt_stats_buf->num_tid_unregister); ++ len += scnprintf(buf + len, buf_len - len, "num_qstats_queried = %u\n", ++ htt_stats_buf->num_qstats_queried); ++ len += scnprintf(buf + len, buf_len - len, "qstats_update_pending = %u\n", ++ htt_stats_buf->qstats_update_pending); ++ len += scnprintf(buf + len, buf_len - len, "last_qstats_query_timestamp = %u\n", ++ htt_stats_buf->last_qstats_query_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "num_tqm_cmdq_full = %u\n", ++ htt_stats_buf->num_tqm_cmdq_full); ++ len += scnprintf(buf + len, buf_len - len, "num_de_sched_algo_trigger = %u\n", ++ htt_stats_buf->num_de_sched_algo_trigger); ++ len += scnprintf(buf + len, buf_len - len, "num_rt_sched_algo_trigger = %u\n", ++ htt_stats_buf->num_rt_sched_algo_trigger); ++ len += scnprintf(buf + len, buf_len - len, "num_tqm_sched_algo_trigger = %u\n", ++ htt_stats_buf->num_tqm_sched_algo_trigger); ++ len += scnprintf(buf + len, buf_len - len, "notify_sched = %u\n\n", ++ htt_stats_buf->notify_sched); ++ len += scnprintf(buf + len, buf_len - len, "dur_based_sendn_term = %u\n\n", ++ htt_stats_buf->dur_based_sendn_term); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1963,11 +1959,11 @@ static inline void htt_print_stats_tx_sc + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_timestamp = %u\n", +- htt_stats_buf->current_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "current_timestamp = %u\n\n", ++ htt_stats_buf->current_timestamp); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1990,12 +1986,12 @@ htt_print_tx_tqm_gen_mpdu_stats_tlv_v(co + u16 num_elements = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n", +- gen_mpdu_end_reason); ++ len += scnprintf(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n\n", ++ gen_mpdu_end_reason); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2017,13 +2013,13 @@ htt_print_tx_tqm_list_mpdu_stats_tlv_v(c + char list_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n", +- list_mpdu_end_reason); ++ len += scnprintf(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n\n", ++ list_mpdu_end_reason); + if (len >= buf_len) + buf[buf_len - 1] = 0; + else +@@ -2045,12 +2041,12 @@ htt_print_tx_tqm_list_mpdu_cnt_tlv_v(con + u16 num_elems = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n", +- list_mpdu_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n\n", ++ list_mpdu_cnt_hist); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2069,69 +2065,69 @@ htt_print_tx_tqm_pdev_stats_tlv_v(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_PDEV_STATS_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_count = %u", +- htt_stats_buf->msdu_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_count = %u", +- htt_stats_buf->mpdu_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu = %u", +- htt_stats_buf->remove_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu = %u", +- htt_stats_buf->remove_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_ttl = %u", +- htt_stats_buf->remove_msdu_ttl); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_bar = %u", +- htt_stats_buf->send_bar); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "bar_sync = %u", +- htt_stats_buf->bar_sync); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu = %u", +- htt_stats_buf->notify_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sync_cmd = %u", +- htt_stats_buf->sync_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "write_cmd = %u", +- htt_stats_buf->write_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_trigger = %u", +- htt_stats_buf->hwsch_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u", +- htt_stats_buf->ack_tlv_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_cmd = %u", +- htt_stats_buf->gen_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_list_cmd = %u", +- htt_stats_buf->gen_list_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_cmd = %u", +- htt_stats_buf->remove_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_tried_cmd = %u", +- htt_stats_buf->remove_mpdu_tried_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u", +- htt_stats_buf->mpdu_queue_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_head_info_cmd = %u", +- htt_stats_buf->mpdu_head_info_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u", +- htt_stats_buf->msdu_flow_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_cmd = %u", +- htt_stats_buf->remove_msdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_ttl_cmd = %u", +- htt_stats_buf->remove_msdu_ttl_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cache_cmd = %u", +- htt_stats_buf->flush_cache_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "update_mpduq_cmd = %u", +- htt_stats_buf->update_mpduq_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueue = %u", +- htt_stats_buf->enqueue); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueue_notify = %u", +- htt_stats_buf->enqueue_notify); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu_at_head = %u", +- htt_stats_buf->notify_mpdu_at_head); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu_state_valid = %u", +- htt_stats_buf->notify_mpdu_state_valid); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_udp_notify1 = %u", +- htt_stats_buf->sched_udp_notify1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_udp_notify2 = %u", +- htt_stats_buf->sched_udp_notify2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_nonudp_notify1 = %u", +- htt_stats_buf->sched_nonudp_notify1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_nonudp_notify2 = %u\n", +- htt_stats_buf->sched_nonudp_notify2); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_PDEV_STATS_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "msdu_count = %u\n", ++ htt_stats_buf->msdu_count); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_count = %u\n", ++ htt_stats_buf->mpdu_count); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu = %u\n", ++ htt_stats_buf->remove_msdu); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu = %u\n", ++ htt_stats_buf->remove_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_ttl = %u\n", ++ htt_stats_buf->remove_msdu_ttl); ++ len += scnprintf(buf + len, buf_len - len, "send_bar = %u\n", ++ htt_stats_buf->send_bar); ++ len += scnprintf(buf + len, buf_len - len, "bar_sync = %u\n", ++ htt_stats_buf->bar_sync); ++ len += scnprintf(buf + len, buf_len - len, "notify_mpdu = %u\n", ++ htt_stats_buf->notify_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", ++ htt_stats_buf->sync_cmd); ++ len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", ++ htt_stats_buf->write_cmd); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_trigger = %u\n", ++ htt_stats_buf->hwsch_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", ++ htt_stats_buf->ack_tlv_proc); ++ len += scnprintf(buf + len, buf_len - len, "gen_mpdu_cmd = %u\n", ++ htt_stats_buf->gen_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "gen_list_cmd = %u\n", ++ htt_stats_buf->gen_list_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu_cmd = %u\n", ++ htt_stats_buf->remove_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu_tried_cmd = %u\n", ++ htt_stats_buf->remove_mpdu_tried_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u\n", ++ htt_stats_buf->mpdu_queue_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_head_info_cmd = %u\n", ++ htt_stats_buf->mpdu_head_info_cmd); ++ len += scnprintf(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u\n", ++ htt_stats_buf->msdu_flow_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_cmd = %u\n", ++ htt_stats_buf->remove_msdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_ttl_cmd = %u\n", ++ htt_stats_buf->remove_msdu_ttl_cmd); ++ len += scnprintf(buf + len, buf_len - len, "flush_cache_cmd = %u\n", ++ htt_stats_buf->flush_cache_cmd); ++ len += scnprintf(buf + len, buf_len - len, "update_mpduq_cmd = %u\n", ++ htt_stats_buf->update_mpduq_cmd); ++ len += scnprintf(buf + len, buf_len - len, "enqueue = %u\n", ++ htt_stats_buf->enqueue); ++ len += scnprintf(buf + len, buf_len - len, "enqueue_notify = %u\n", ++ htt_stats_buf->enqueue_notify); ++ len += scnprintf(buf + len, buf_len - len, "notify_mpdu_at_head = %u\n", ++ htt_stats_buf->notify_mpdu_at_head); ++ len += scnprintf(buf + len, buf_len - len, "notify_mpdu_state_valid = %u\n", ++ htt_stats_buf->notify_mpdu_state_valid); ++ len += scnprintf(buf + len, buf_len - len, "sched_udp_notify1 = %u\n", ++ htt_stats_buf->sched_udp_notify1); ++ len += scnprintf(buf + len, buf_len - len, "sched_udp_notify2 = %u\n", ++ htt_stats_buf->sched_udp_notify2); ++ len += scnprintf(buf + len, buf_len - len, "sched_nonudp_notify1 = %u\n", ++ htt_stats_buf->sched_nonudp_notify1); ++ len += scnprintf(buf + len, buf_len - len, "sched_nonudp_notify2 = %u\n\n", ++ htt_stats_buf->sched_nonudp_notify2); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2149,23 +2145,23 @@ static inline void htt_print_tx_tqm_cmn_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "max_cmdq_id = %u", +- htt_stats_buf->max_cmdq_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u", +- htt_stats_buf->list_mpdu_cnt_hist_intvl); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "add_msdu = %u", +- htt_stats_buf->add_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_empty = %u", +- htt_stats_buf->q_empty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_not_empty = %u", +- htt_stats_buf->q_not_empty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "drop_notification = %u", +- htt_stats_buf->drop_notification); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "desc_threshold = %u\n", +- htt_stats_buf->desc_threshold); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "max_cmdq_id = %u\n", ++ htt_stats_buf->max_cmdq_id); ++ len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u\n", ++ htt_stats_buf->list_mpdu_cnt_hist_intvl); ++ len += scnprintf(buf + len, buf_len - len, "add_msdu = %u\n", ++ htt_stats_buf->add_msdu); ++ len += scnprintf(buf + len, buf_len - len, "q_empty = %u\n", ++ htt_stats_buf->q_empty); ++ len += scnprintf(buf + len, buf_len - len, "q_not_empty = %u\n", ++ htt_stats_buf->q_not_empty); ++ len += scnprintf(buf + len, buf_len - len, "drop_notification = %u\n", ++ htt_stats_buf->drop_notification); ++ len += scnprintf(buf + len, buf_len - len, "desc_threshold = %u\n\n", ++ htt_stats_buf->desc_threshold); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2183,13 +2179,13 @@ static inline void htt_print_tx_tqm_erro + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_ERROR_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_empty_failure = %u", +- htt_stats_buf->q_empty_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_not_empty_failure = %u", +- htt_stats_buf->q_not_empty_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "add_msdu_failure = %u\n", +- htt_stats_buf->add_msdu_failure); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_ERROR_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "q_empty_failure = %u\n", ++ htt_stats_buf->q_empty_failure); ++ len += scnprintf(buf + len, buf_len - len, "q_not_empty_failure = %u\n", ++ htt_stats_buf->q_not_empty_failure); ++ len += scnprintf(buf + len, buf_len - len, "add_msdu_failure = %u\n\n", ++ htt_stats_buf->add_msdu_failure); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2207,33 +2203,33 @@ static inline void htt_print_tx_tqm_cmdq + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__cmdq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cmdq_id = %u\n", +- (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sync_cmd = %u", +- htt_stats_buf->sync_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "write_cmd = %u", +- htt_stats_buf->write_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_cmd = %u", +- htt_stats_buf->gen_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u", +- htt_stats_buf->mpdu_queue_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_head_info_cmd = %u", +- htt_stats_buf->mpdu_head_info_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u", +- htt_stats_buf->msdu_flow_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_cmd = %u", +- htt_stats_buf->remove_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_cmd = %u", +- htt_stats_buf->remove_msdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cache_cmd = %u", +- htt_stats_buf->flush_cache_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "update_mpduq_cmd = %u", +- htt_stats_buf->update_mpduq_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "update_msduq_cmd = %u\n", +- htt_stats_buf->update_msduq_cmd); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__cmdq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "cmdq_id = %u\n\n", ++ (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", ++ htt_stats_buf->sync_cmd); ++ len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", ++ htt_stats_buf->write_cmd); ++ len += scnprintf(buf + len, buf_len - len, "gen_mpdu_cmd = %u\n", ++ htt_stats_buf->gen_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u\n", ++ htt_stats_buf->mpdu_queue_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_head_info_cmd = %u\n", ++ htt_stats_buf->mpdu_head_info_cmd); ++ len += scnprintf(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u\n", ++ htt_stats_buf->msdu_flow_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu_cmd = %u\n", ++ htt_stats_buf->remove_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_cmd = %u\n", ++ htt_stats_buf->remove_msdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "flush_cache_cmd = %u\n", ++ htt_stats_buf->flush_cache_cmd); ++ len += scnprintf(buf + len, buf_len - len, "update_mpduq_cmd = %u\n", ++ htt_stats_buf->update_mpduq_cmd); ++ len += scnprintf(buf + len, buf_len - len, "update_msduq_cmd = %u\n\n", ++ htt_stats_buf->update_msduq_cmd); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2252,20 +2248,20 @@ htt_print_tx_de_eapol_packets_stats_tlv( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_EAPOL_PACKETS_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m1_packets = %u", +- htt_stats_buf->m1_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m2_packets = %u", +- htt_stats_buf->m2_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m3_packets = %u", +- htt_stats_buf->m3_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m4_packets = %u", +- htt_stats_buf->m4_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "g1_packets = %u", +- htt_stats_buf->g1_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "g2_packets = %u\n", +- htt_stats_buf->g2_packets); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_EAPOL_PACKETS_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "m1_packets = %u\n", ++ htt_stats_buf->m1_packets); ++ len += scnprintf(buf + len, buf_len - len, "m2_packets = %u\n", ++ htt_stats_buf->m2_packets); ++ len += scnprintf(buf + len, buf_len - len, "m3_packets = %u\n", ++ htt_stats_buf->m3_packets); ++ len += scnprintf(buf + len, buf_len - len, "m4_packets = %u\n", ++ htt_stats_buf->m4_packets); ++ len += scnprintf(buf + len, buf_len - len, "g1_packets = %u\n", ++ htt_stats_buf->g1_packets); ++ len += scnprintf(buf + len, buf_len - len, "g2_packets = %u\n\n", ++ htt_stats_buf->g2_packets); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2284,34 +2280,34 @@ htt_print_tx_de_classify_failed_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_CLASSIFY_FAILED_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ap_bss_peer_not_found = %u", +- htt_stats_buf->ap_bss_peer_not_found); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ap_bcast_mcast_no_peer = %u", +- htt_stats_buf->ap_bcast_mcast_no_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sta_delete_in_progress = %u", +- htt_stats_buf->sta_delete_in_progress); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ibss_no_bss_peer = %u", +- htt_stats_buf->ibss_no_bss_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_vdev_type = %u", +- htt_stats_buf->invalid_vdev_type); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_ast_peer_entry = %u", +- htt_stats_buf->invalid_ast_peer_entry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_entry_invalid = %u", +- htt_stats_buf->peer_entry_invalid); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ethertype_not_ip = %u", +- htt_stats_buf->ethertype_not_ip); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "eapol_lookup_failed = %u", +- htt_stats_buf->eapol_lookup_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qpeer_not_allow_data = %u", +- htt_stats_buf->qpeer_not_allow_data); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_tid_override = %u", +- htt_stats_buf->fse_tid_override); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ipv6_jumbogram_zero_length = %u", +- htt_stats_buf->ipv6_jumbogram_zero_length); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_to_non_qos_in_prog = %u\n", +- htt_stats_buf->qos_to_non_qos_in_prog); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_CLASSIFY_FAILED_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ap_bss_peer_not_found = %u\n", ++ htt_stats_buf->ap_bss_peer_not_found); ++ len += scnprintf(buf + len, buf_len - len, "ap_bcast_mcast_no_peer = %u\n", ++ htt_stats_buf->ap_bcast_mcast_no_peer); ++ len += scnprintf(buf + len, buf_len - len, "sta_delete_in_progress = %u\n", ++ htt_stats_buf->sta_delete_in_progress); ++ len += scnprintf(buf + len, buf_len - len, "ibss_no_bss_peer = %u\n", ++ htt_stats_buf->ibss_no_bss_peer); ++ len += scnprintf(buf + len, buf_len - len, "invalid_vdev_type = %u\n", ++ htt_stats_buf->invalid_vdev_type); ++ len += scnprintf(buf + len, buf_len - len, "invalid_ast_peer_entry = %u\n", ++ htt_stats_buf->invalid_ast_peer_entry); ++ len += scnprintf(buf + len, buf_len - len, "peer_entry_invalid = %u\n", ++ htt_stats_buf->peer_entry_invalid); ++ len += scnprintf(buf + len, buf_len - len, "ethertype_not_ip = %u\n", ++ htt_stats_buf->ethertype_not_ip); ++ len += scnprintf(buf + len, buf_len - len, "eapol_lookup_failed = %u\n", ++ htt_stats_buf->eapol_lookup_failed); ++ len += scnprintf(buf + len, buf_len - len, "qpeer_not_allow_data = %u\n", ++ htt_stats_buf->qpeer_not_allow_data); ++ len += scnprintf(buf + len, buf_len - len, "fse_tid_override = %u\n", ++ htt_stats_buf->fse_tid_override); ++ len += scnprintf(buf + len, buf_len - len, "ipv6_jumbogram_zero_length = %u\n", ++ htt_stats_buf->ipv6_jumbogram_zero_length); ++ len += scnprintf(buf + len, buf_len - len, "qos_to_non_qos_in_prog = %u\n\n", ++ htt_stats_buf->qos_to_non_qos_in_prog); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2330,73 +2326,73 @@ htt_print_tx_de_classify_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_CLASSIFY_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "arp_packets = %u", +- htt_stats_buf->arp_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "igmp_packets = %u", +- htt_stats_buf->igmp_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dhcp_packets = %u", +- htt_stats_buf->dhcp_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "host_inspected = %u", +- htt_stats_buf->host_inspected); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_included = %u", +- htt_stats_buf->htt_included); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_mcs = %u", +- htt_stats_buf->htt_valid_mcs); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_nss = %u", +- htt_stats_buf->htt_valid_nss); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_preamble_type = %u", +- htt_stats_buf->htt_valid_preamble_type); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_chainmask = %u", +- htt_stats_buf->htt_valid_chainmask); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_guard_interval = %u", +- htt_stats_buf->htt_valid_guard_interval); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_retries = %u", +- htt_stats_buf->htt_valid_retries); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_bw_info = %u", +- htt_stats_buf->htt_valid_bw_info); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_power = %u", +- htt_stats_buf->htt_valid_power); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_key_flags = 0x%x", +- htt_stats_buf->htt_valid_key_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_no_encryption = %u", +- htt_stats_buf->htt_valid_no_encryption); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_entry_count = %u", +- htt_stats_buf->fse_entry_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_be = %u", +- htt_stats_buf->fse_priority_be); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_high = %u", +- htt_stats_buf->fse_priority_high); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_low = %u", +- htt_stats_buf->fse_priority_low); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_be = %u", +- htt_stats_buf->fse_traffic_ptrn_be); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_over_sub = %u", +- htt_stats_buf->fse_traffic_ptrn_over_sub); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_bursty = %u", +- htt_stats_buf->fse_traffic_ptrn_bursty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_interactive = %u", +- htt_stats_buf->fse_traffic_ptrn_interactive); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_periodic = %u", +- htt_stats_buf->fse_traffic_ptrn_periodic); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_alloc = %u", +- htt_stats_buf->fse_hwqueue_alloc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_created = %u", +- htt_stats_buf->fse_hwqueue_created); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_send_to_host = %u", +- htt_stats_buf->fse_hwqueue_send_to_host); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mcast_entry = %u", +- htt_stats_buf->mcast_entry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "bcast_entry = %u", +- htt_stats_buf->bcast_entry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_update_peer_cache = %u", +- htt_stats_buf->htt_update_peer_cache); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_learning_frame = %u", +- htt_stats_buf->htt_learning_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_invalid_peer = %u", +- htt_stats_buf->fse_invalid_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mec_notify = %u\n", +- htt_stats_buf->mec_notify); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_CLASSIFY_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "arp_packets = %u\n", ++ htt_stats_buf->arp_packets); ++ len += scnprintf(buf + len, buf_len - len, "igmp_packets = %u\n", ++ htt_stats_buf->igmp_packets); ++ len += scnprintf(buf + len, buf_len - len, "dhcp_packets = %u\n", ++ htt_stats_buf->dhcp_packets); ++ len += scnprintf(buf + len, buf_len - len, "host_inspected = %u\n", ++ htt_stats_buf->host_inspected); ++ len += scnprintf(buf + len, buf_len - len, "htt_included = %u\n", ++ htt_stats_buf->htt_included); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_mcs = %u\n", ++ htt_stats_buf->htt_valid_mcs); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_nss = %u\n", ++ htt_stats_buf->htt_valid_nss); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_preamble_type = %u\n", ++ htt_stats_buf->htt_valid_preamble_type); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_chainmask = %u\n", ++ htt_stats_buf->htt_valid_chainmask); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_guard_interval = %u\n", ++ htt_stats_buf->htt_valid_guard_interval); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_retries = %u\n", ++ htt_stats_buf->htt_valid_retries); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_bw_info = %u\n", ++ htt_stats_buf->htt_valid_bw_info); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_power = %u\n", ++ htt_stats_buf->htt_valid_power); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_key_flags = 0x%x\n", ++ htt_stats_buf->htt_valid_key_flags); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_no_encryption = %u\n", ++ htt_stats_buf->htt_valid_no_encryption); ++ len += scnprintf(buf + len, buf_len - len, "fse_entry_count = %u\n", ++ htt_stats_buf->fse_entry_count); ++ len += scnprintf(buf + len, buf_len - len, "fse_priority_be = %u\n", ++ htt_stats_buf->fse_priority_be); ++ len += scnprintf(buf + len, buf_len - len, "fse_priority_high = %u\n", ++ htt_stats_buf->fse_priority_high); ++ len += scnprintf(buf + len, buf_len - len, "fse_priority_low = %u\n", ++ htt_stats_buf->fse_priority_low); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_be = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_be); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_over_sub = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_over_sub); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_bursty = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_bursty); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_interactive = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_interactive); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_periodic = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_periodic); ++ len += scnprintf(buf + len, buf_len - len, "fse_hwqueue_alloc = %u\n", ++ htt_stats_buf->fse_hwqueue_alloc); ++ len += scnprintf(buf + len, buf_len - len, "fse_hwqueue_created = %u\n", ++ htt_stats_buf->fse_hwqueue_created); ++ len += scnprintf(buf + len, buf_len - len, "fse_hwqueue_send_to_host = %u\n", ++ htt_stats_buf->fse_hwqueue_send_to_host); ++ len += scnprintf(buf + len, buf_len - len, "mcast_entry = %u\n", ++ htt_stats_buf->mcast_entry); ++ len += scnprintf(buf + len, buf_len - len, "bcast_entry = %u\n", ++ htt_stats_buf->bcast_entry); ++ len += scnprintf(buf + len, buf_len - len, "htt_update_peer_cache = %u\n", ++ htt_stats_buf->htt_update_peer_cache); ++ len += scnprintf(buf + len, buf_len - len, "htt_learning_frame = %u\n", ++ htt_stats_buf->htt_learning_frame); ++ len += scnprintf(buf + len, buf_len - len, "fse_invalid_peer = %u\n", ++ htt_stats_buf->fse_invalid_peer); ++ len += scnprintf(buf + len, buf_len - len, "mec_notify = %u\n\n", ++ htt_stats_buf->mec_notify); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2415,24 +2411,24 @@ htt_print_tx_de_classify_status_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_CLASSIFY_STATUS_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "eok = %u", +- htt_stats_buf->eok); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "classify_done = %u", +- htt_stats_buf->classify_done); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "lookup_failed = %u", +- htt_stats_buf->lookup_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_dhcp = %u", +- htt_stats_buf->send_host_dhcp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_mcast = %u", +- htt_stats_buf->send_host_mcast); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_unknown_dest = %u", +- htt_stats_buf->send_host_unknown_dest); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host = %u", +- htt_stats_buf->send_host); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "status_invalid = %u\n", +- htt_stats_buf->status_invalid); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_CLASSIFY_STATUS_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "eok = %u\n", ++ htt_stats_buf->eok); ++ len += scnprintf(buf + len, buf_len - len, "classify_done = %u\n", ++ htt_stats_buf->classify_done); ++ len += scnprintf(buf + len, buf_len - len, "lookup_failed = %u\n", ++ htt_stats_buf->lookup_failed); ++ len += scnprintf(buf + len, buf_len - len, "send_host_dhcp = %u\n", ++ htt_stats_buf->send_host_dhcp); ++ len += scnprintf(buf + len, buf_len - len, "send_host_mcast = %u\n", ++ htt_stats_buf->send_host_mcast); ++ len += scnprintf(buf + len, buf_len - len, "send_host_unknown_dest = %u\n", ++ htt_stats_buf->send_host_unknown_dest); ++ len += scnprintf(buf + len, buf_len - len, "send_host = %u\n", ++ htt_stats_buf->send_host); ++ len += scnprintf(buf + len, buf_len - len, "status_invalid = %u\n\n", ++ htt_stats_buf->status_invalid); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2451,14 +2447,14 @@ htt_print_tx_de_enqueue_packets_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_ENQUEUE_PACKETS_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueued_pkts = %u", +- htt_stats_buf->enqueued_pkts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "to_tqm = %u", +- htt_stats_buf->to_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "to_tqm_bypass = %u\n", +- htt_stats_buf->to_tqm_bypass); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_ENQUEUE_PACKETS_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "enqueued_pkts = %u\n", ++ htt_stats_buf->enqueued_pkts); ++ len += scnprintf(buf + len, buf_len - len, "to_tqm = %u\n", ++ htt_stats_buf->to_tqm); ++ len += scnprintf(buf + len, buf_len - len, "to_tqm_bypass = %u\n\n", ++ htt_stats_buf->to_tqm_bypass); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2477,14 +2473,14 @@ htt_print_tx_de_enqueue_discard_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_ENQUEUE_DISCARD_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "discarded_pkts = %u", +- htt_stats_buf->discarded_pkts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_frames = %u", +- htt_stats_buf->local_frames); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "is_ext_msdu = %u\n", +- htt_stats_buf->is_ext_msdu); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_ENQUEUE_DISCARD_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "discarded_pkts = %u\n", ++ htt_stats_buf->discarded_pkts); ++ len += scnprintf(buf + len, buf_len - len, "local_frames = %u\n", ++ htt_stats_buf->local_frames); ++ len += scnprintf(buf + len, buf_len - len, "is_ext_msdu = %u\n\n", ++ htt_stats_buf->is_ext_msdu); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2502,17 +2498,17 @@ static inline void htt_print_tx_de_compl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_COMPL_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl_dummy_frame = %u", +- htt_stats_buf->tcl_dummy_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_dummy_frame = %u", +- htt_stats_buf->tqm_dummy_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_notify_frame = %u", +- htt_stats_buf->tqm_notify_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw2wbm_enq = %u", +- htt_stats_buf->fw2wbm_enq); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_bypass_frame = %u\n", +- htt_stats_buf->tqm_bypass_frame); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_COMPL_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "tcl_dummy_frame = %u\n", ++ htt_stats_buf->tcl_dummy_frame); ++ len += scnprintf(buf + len, buf_len - len, "tqm_dummy_frame = %u\n", ++ htt_stats_buf->tqm_dummy_frame); ++ len += scnprintf(buf + len, buf_len - len, "tqm_notify_frame = %u\n", ++ htt_stats_buf->tqm_notify_frame); ++ len += scnprintf(buf + len, buf_len - len, "fw2wbm_enq = %u\n", ++ htt_stats_buf->fw2wbm_enq); ++ len += scnprintf(buf + len, buf_len - len, "tqm_bypass_frame = %u\n\n", ++ htt_stats_buf->tqm_bypass_frame); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2535,19 +2531,19 @@ htt_print_tx_de_fw2wbm_ring_full_hist_tl + u16 num_elements = tag_len >> 2; + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(fw2wbm_ring_full_hist, + htt_stats_buf->fw2wbm_ring_full_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "fw2wbm_ring_full_hist = %s\n", +- fw2wbm_ring_full_hist); ++ len += scnprintf(buf + len, buf_len - len, ++ "fw2wbm_ring_full_hist = %s\n\n", ++ fw2wbm_ring_full_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER "); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n"); + } + + if (len >= buf_len) +@@ -2566,21 +2562,21 @@ htt_print_tx_de_cmn_stats_tlv(const void + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl2fw_entry_count = %u", +- htt_stats_buf->tcl2fw_entry_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "not_to_fw = %u", +- htt_stats_buf->not_to_fw); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_pdev_vdev_peer = %u", +- htt_stats_buf->invalid_pdev_vdev_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl_res_invalid_addrx = %u", +- htt_stats_buf->tcl_res_invalid_addrx); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm2fw_entry_count = %u", +- htt_stats_buf->wbm2fw_entry_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_pdev = %u\n", +- htt_stats_buf->invalid_pdev); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "tcl2fw_entry_count = %u\n", ++ htt_stats_buf->tcl2fw_entry_count); ++ len += scnprintf(buf + len, buf_len - len, "not_to_fw = %u\n", ++ htt_stats_buf->not_to_fw); ++ len += scnprintf(buf + len, buf_len - len, "invalid_pdev_vdev_peer = %u\n", ++ htt_stats_buf->invalid_pdev_vdev_peer); ++ len += scnprintf(buf + len, buf_len - len, "tcl_res_invalid_addrx = %u\n", ++ htt_stats_buf->tcl_res_invalid_addrx); ++ len += scnprintf(buf + len, buf_len - len, "wbm2fw_entry_count = %u\n", ++ htt_stats_buf->wbm2fw_entry_count); ++ len += scnprintf(buf + len, buf_len - len, "invalid_pdev = %u\n\n", ++ htt_stats_buf->invalid_pdev); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2600,49 +2596,49 @@ static inline void htt_print_ring_if_sta + char low_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; + char high_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr = %u", +- htt_stats_buf->base_addr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "elem_size = %u", +- htt_stats_buf->elem_size); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_elems = %u", +- htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "prefetch_tail_idx = %u", +- (htt_stats_buf->num_elems__prefetch_tail_idx & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "head_idx = %u", +- htt_stats_buf->head_idx__tail_idx & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tail_idx = %u", +- (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "shadow_head_idx = %u", +- htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "shadow_tail_idx = %u", +- (htt_stats_buf->shadow_head_idx__shadow_tail_idx & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tail_incr = %u", +- htt_stats_buf->num_tail_incr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "lwm_thresh = %u", +- htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwm_thresh = %u", +- (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "overrun_hit_count = %u", +- htt_stats_buf->overrun_hit_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun_hit_count = %u", +- htt_stats_buf->underrun_hit_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "prod_blockwait_count = %u", +- htt_stats_buf->prod_blockwait_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cons_blockwait_count = %u", +- htt_stats_buf->cons_blockwait_count); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "base_addr = %u\n", ++ htt_stats_buf->base_addr); ++ len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", ++ htt_stats_buf->elem_size); ++ len += scnprintf(buf + len, buf_len - len, "num_elems = %u\n", ++ htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_tail_idx = %u\n", ++ (htt_stats_buf->num_elems__prefetch_tail_idx & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "head_idx = %u\n", ++ htt_stats_buf->head_idx__tail_idx & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tail_idx = %u\n", ++ (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "shadow_head_idx = %u\n", ++ htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "shadow_tail_idx = %u\n", ++ (htt_stats_buf->shadow_head_idx__shadow_tail_idx & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_tail_incr = %u\n", ++ htt_stats_buf->num_tail_incr); ++ len += scnprintf(buf + len, buf_len - len, "lwm_thresh = %u\n", ++ htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "hwm_thresh = %u\n", ++ (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "overrun_hit_count = %u\n", ++ htt_stats_buf->overrun_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "underrun_hit_count = %u\n", ++ htt_stats_buf->underrun_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "prod_blockwait_count = %u\n", ++ htt_stats_buf->prod_blockwait_count); ++ len += scnprintf(buf + len, buf_len - len, "cons_blockwait_count = %u\n", ++ htt_stats_buf->cons_blockwait_count); + + PRINT_ARRAY_TO_BUF(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, + HTT_STATS_LOW_WM_BINS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "low_wm_hit_count = %s ", +- low_wm_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "low_wm_hit_count = %s\n", ++ low_wm_hit_count); + + PRINT_ARRAY_TO_BUF(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, + HTT_STATS_HIGH_WM_BINS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "high_wm_hit_count = %s\n", +- high_wm_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "high_wm_hit_count = %s\n\n", ++ high_wm_hit_count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2660,11 +2656,11 @@ static inline void htt_print_ring_if_cmn + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n", +- htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", ++ htt_stats_buf->num_records); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2685,13 +2681,13 @@ static inline void htt_print_sfm_client_ + char dwords_used_by_user_n[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = tag_len >> 2; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(dwords_used_by_user_n, + htt_stats_buf->dwords_used_by_user_n, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n", +- dwords_used_by_user_n); ++ len += scnprintf(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n\n", ++ dwords_used_by_user_n); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2709,21 +2705,21 @@ static inline void htt_print_sfm_client_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "client_id = %u", +- htt_stats_buf->client_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_min = %u", +- htt_stats_buf->buf_min); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_max = %u", +- htt_stats_buf->buf_max); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_busy = %u", +- htt_stats_buf->buf_busy); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_alloc = %u", +- htt_stats_buf->buf_alloc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_avail = %u", +- htt_stats_buf->buf_avail); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_users = %u\n", +- htt_stats_buf->num_users); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "client_id = %u\n", ++ htt_stats_buf->client_id); ++ len += scnprintf(buf + len, buf_len - len, "buf_min = %u\n", ++ htt_stats_buf->buf_min); ++ len += scnprintf(buf + len, buf_len - len, "buf_max = %u\n", ++ htt_stats_buf->buf_max); ++ len += scnprintf(buf + len, buf_len - len, "buf_busy = %u\n", ++ htt_stats_buf->buf_busy); ++ len += scnprintf(buf + len, buf_len - len, "buf_alloc = %u\n", ++ htt_stats_buf->buf_alloc); ++ len += scnprintf(buf + len, buf_len - len, "buf_avail = %u\n", ++ htt_stats_buf->buf_avail); ++ len += scnprintf(buf + len, buf_len - len, "num_users = %u\n\n", ++ htt_stats_buf->num_users); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2741,17 +2737,17 @@ static inline void htt_print_sfm_cmn_tlv + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_total = %u", +- htt_stats_buf->buf_total); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mem_empty = %u", +- htt_stats_buf->mem_empty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "deallocate_bufs = %u", +- htt_stats_buf->deallocate_bufs); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n", +- htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n", ++ htt_stats_buf->buf_total); ++ len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n", ++ htt_stats_buf->mem_empty); ++ len += scnprintf(buf + len, buf_len - len, "deallocate_bufs = %u\n", ++ htt_stats_buf->deallocate_bufs); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", ++ htt_stats_buf->num_records); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2769,42 +2765,42 @@ static inline void htt_print_sring_stats + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ring_id = %u", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "arena = %u", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ep = %u", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr_lsb = 0x%x", +- htt_stats_buf->base_addr_lsb); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr_msb = 0x%x", +- htt_stats_buf->base_addr_msb); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ring_size = %u", +- htt_stats_buf->ring_size); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "elem_size = %u", +- htt_stats_buf->elem_size); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_avail_words = %u", +- htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_valid_words = %u", +- (htt_stats_buf->num_avail_words__num_valid_words & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "head_ptr = %u", +- htt_stats_buf->head_ptr__tail_ptr & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tail_ptr = %u", +- (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "consumer_empty = %u", +- htt_stats_buf->consumer_empty__producer_full & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "producer_full = %u", +- (htt_stats_buf->consumer_empty__producer_full & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "prefetch_count = %u", +- htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "internal_tail_ptr = %u\n", +- (htt_stats_buf->prefetch_count__internal_tail_ptr & +- 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n", ++ (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "arena = %u\n", ++ (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "ep = %u\n", ++ (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24); ++ len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n", ++ htt_stats_buf->base_addr_lsb); ++ len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n", ++ htt_stats_buf->base_addr_msb); ++ len += scnprintf(buf + len, buf_len - len, "ring_size = %u\n", ++ htt_stats_buf->ring_size); ++ len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", ++ htt_stats_buf->elem_size); ++ len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n", ++ htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n", ++ (htt_stats_buf->num_avail_words__num_valid_words & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n", ++ htt_stats_buf->head_ptr__tail_ptr & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n", ++ (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n", ++ htt_stats_buf->consumer_empty__producer_full & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n", ++ (htt_stats_buf->consumer_empty__producer_full & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n", ++ htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n", ++ (htt_stats_buf->prefetch_count__internal_tail_ptr & ++ 0xFFFF0000) >> 16); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2822,9 +2818,9 @@ static inline void htt_print_sring_cmn_t + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SRING_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n", +- htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SRING_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", ++ htt_stats_buf->num_records); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2851,156 +2847,156 @@ static inline void htt_print_tx_pdev_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_ldpc = %u", +- htt_stats_buf->tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u", +- htt_stats_buf->ac_mu_mimo_tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_ldpc = %u", +- htt_stats_buf->ax_mu_mimo_tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_ldpc = %u", +- htt_stats_buf->ofdma_tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_success = %u", +- htt_stats_buf->rts_success); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_rssi = %u", +- htt_stats_buf->ack_rssi); +- +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Legacy CCK Rates: 1 Mbps: %u, 2 Mbps: %u, 5.5 Mbps: %u, 11 Mbps: %u", +- htt_stats_buf->tx_legacy_cck_rate[0], +- htt_stats_buf->tx_legacy_cck_rate[1], +- htt_stats_buf->tx_legacy_cck_rate[2], +- htt_stats_buf->tx_legacy_cck_rate[3]); +- +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Legacy OFDM Rates: 6 Mbps: %u, 9 Mbps: %u, 12 Mbps: %u, 18 Mbps: %u\n" +- " 24 Mbps: %u, 36 Mbps: %u, 48 Mbps: %u, 54 Mbps: %u", +- htt_stats_buf->tx_legacy_ofdm_rate[0], +- htt_stats_buf->tx_legacy_ofdm_rate[1], +- htt_stats_buf->tx_legacy_ofdm_rate[2], +- htt_stats_buf->tx_legacy_ofdm_rate[3], +- htt_stats_buf->tx_legacy_ofdm_rate[4], +- htt_stats_buf->tx_legacy_ofdm_rate[5], +- htt_stats_buf->tx_legacy_ofdm_rate[6], +- htt_stats_buf->tx_legacy_ofdm_rate[7]); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", ++ htt_stats_buf->tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u\n", ++ htt_stats_buf->ac_mu_mimo_tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_ldpc = %u\n", ++ htt_stats_buf->ax_mu_mimo_tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_ldpc = %u\n", ++ htt_stats_buf->ofdma_tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rts_success = %u\n", ++ htt_stats_buf->rts_success); ++ len += scnprintf(buf + len, buf_len - len, "ack_rssi = %u\n", ++ htt_stats_buf->ack_rssi); ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "Legacy CCK Rates: 1 Mbps: %u, 2 Mbps: %u, 5.5 Mbps: %u, 11 Mbps: %u\n", ++ htt_stats_buf->tx_legacy_cck_rate[0], ++ htt_stats_buf->tx_legacy_cck_rate[1], ++ htt_stats_buf->tx_legacy_cck_rate[2], ++ htt_stats_buf->tx_legacy_cck_rate[3]); ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "Legacy OFDM Rates: 6 Mbps: %u, 9 Mbps: %u, 12 Mbps: %u, 18 Mbps: %u\n" ++ " 24 Mbps: %u, 36 Mbps: %u, 48 Mbps: %u, 54 Mbps: %u\n", ++ htt_stats_buf->tx_legacy_ofdm_rate[0], ++ htt_stats_buf->tx_legacy_ofdm_rate[1], ++ htt_stats_buf->tx_legacy_ofdm_rate[2], ++ htt_stats_buf->tx_legacy_ofdm_rate[3], ++ htt_stats_buf->tx_legacy_ofdm_rate[4], ++ htt_stats_buf->tx_legacy_ofdm_rate[5], ++ htt_stats_buf->tx_legacy_ofdm_rate[6], ++ htt_stats_buf->tx_legacy_ofdm_rate[7]); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, + HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u", +- htt_stats_buf->tx_he_ltf[1], +- htt_stats_buf->tx_he_ltf[2], +- htt_stats_buf->tx_he_ltf[3]); ++ len += scnprintf(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u\n", ++ htt_stats_buf->tx_he_ltf[1], ++ htt_stats_buf->tx_he_ltf[2], ++ htt_stats_buf->tx_he_ltf[3]); + + /* SU GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + /* AC MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + /* AX MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + /* DL OFDMA GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_dcm, + HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3045,202 +3041,202 @@ static inline void htt_print_rx_pdev_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "nsts = %u", +- htt_stats_buf->nsts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ldpc = %u", +- htt_stats_buf->rx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_mgmt = %u", +- htt_stats_buf->rssi_mgmt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_data = %u", +- htt_stats_buf->rssi_data); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_comb = %u", +- htt_stats_buf->rssi_comb); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_in_dbm = %d", +- htt_stats_buf->rssi_in_dbm); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", ++ htt_stats_buf->nsts); ++ len += scnprintf(buf + len, buf_len - len, "rx_ldpc = %u\n", ++ htt_stats_buf->rx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_mgmt = %u\n", ++ htt_stats_buf->rssi_mgmt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_data = %u\n", ++ htt_stats_buf->rssi_data); ++ len += scnprintf(buf + len, buf_len - len, "rssi_comb = %u\n", ++ htt_stats_buf->rssi_comb); ++ len += scnprintf(buf + len, buf_len - len, "rssi_in_dbm = %d\n", ++ htt_stats_buf->rssi_in_dbm); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, + HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, + HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_evm_nss_count = %u", +- htt_stats_buf->nss_count); ++ len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_evm_nss_count = %u\n", ++ htt_stats_buf->nss_count); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_evm_pilot_count = %u", +- htt_stats_buf->pilot_count); ++ len += scnprintf(buf + len, buf_len - len, "rx_evm_pilot_count = %u\n", ++ htt_stats_buf->pilot_count); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + index = 0; + + for (i = 0; i < HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS; i++) + index += scnprintf(&rx_pilot_evm_db[j][index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_pilot_evm_db[j][i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pilot_evm_dB[%u] = %s ", +- j, rx_pilot_evm_db[j]); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_pilot_evm_db[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB[%u] = %s\n", ++ j, rx_pilot_evm_db[j]); + } + + index = 0; + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + for (i = 0; i < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) + index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", i, htt_stats_buf->rx_pilot_evm_db_mean[i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pilot_evm_dB_mean = %s ", str_buf); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", i, htt_stats_buf->rx_pilot_evm_db_mean[i]); ++ len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB_mean = %s\n", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", ++ j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, + HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_su_ext = %u", +- htt_stats_buf->rx_11ax_su_ext); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ac_mumimo = %u", +- htt_stats_buf->rx_11ac_mumimo); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_mumimo = %u", +- htt_stats_buf->rx_11ax_mumimo); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_ofdma = %u", +- htt_stats_buf->rx_11ax_ofdma); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txbf = %u", +- htt_stats_buf->txbf); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_su_ext = %u\n", ++ htt_stats_buf->rx_11ax_su_ext); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ac_mumimo = %u\n", ++ htt_stats_buf->rx_11ac_mumimo); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_mumimo = %u\n", ++ htt_stats_buf->rx_11ax_mumimo); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_ofdma = %u\n", ++ htt_stats_buf->rx_11ax_ofdma); ++ len += scnprintf(buf + len, buf_len - len, "txbf = %u\n", ++ htt_stats_buf->txbf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_cck_rate, + HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_cck_rate = %s ", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_legacy_cck_rate = %s\n", ++ str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, + HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s ", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s\n", ++ str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_active_dur_us_low = %u", +- htt_stats_buf->rx_active_dur_us_low); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_active_dur_us_high = %u", +- htt_stats_buf->rx_active_dur_us_high); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_ul_ofdma = %u", +- htt_stats_buf->rx_11ax_ul_ofdma); ++ len += scnprintf(buf + len, buf_len - len, "rx_active_dur_us_low = %u\n", ++ htt_stats_buf->rx_active_dur_us_low); ++ len += scnprintf(buf + len, buf_len - len, "rx_active_dur_us_high = %u\n", ++ htt_stats_buf->rx_active_dur_us_high); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_ul_ofdma = %u\n", ++ htt_stats_buf->rx_11ax_ul_ofdma); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s\n", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s\n", ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_nss, + HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_bw, + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s\n", str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u", ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u\n", + htt_stats_buf->ul_ofdma_rx_stbc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_ldpc = %u", ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_ldpc = %u\n", + htt_stats_buf->ul_ofdma_rx_ldpc); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s ", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s\n", ++ str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s ", ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s\n", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s\n", ++ str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + index = 0; + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + for (i = 0; i < HTT_RX_PDEV_MAX_OFDMA_NUM_USER; i++) + index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, htt_stats_buf->rx_ul_fd_rssi[j][i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "rx_ul_fd_rssi: nss[%u] = %s", j, str_buf); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", ++ i, htt_stats_buf->rx_ul_fd_rssi[j][i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_ul_fd_rssi: nss[%u] = %s\n", j, str_buf); + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "per_chain_rssi_pkt_type = %#x", +- htt_stats_buf->per_chain_rssi_pkt_type); ++ len += scnprintf(buf + len, buf_len - len, "per_chain_rssi_pkt_type = %#x\n", ++ htt_stats_buf->per_chain_rssi_pkt_type); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + index = 0; + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + for (i = 0; i < HTT_RX_PDEV_STATS_NUM_BW_COUNTERS; i++) + index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "rx_per_chain_rssi_in_dbm[%u] = %s ", j, str_buf); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_per_chain_rssi_in_dbm[%u] = %s\n", j, str_buf); + } +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3268,34 +3264,34 @@ static inline void htt_print_rx_soc_fw_s + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_SOC_FW_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_reo_ring_data_msdu = %u", +- htt_stats_buf->fw_reo_ring_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_to_host_data_msdu_bcmc = %u", +- htt_stats_buf->fw_to_host_data_msdu_bcmc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_to_host_data_msdu_uc = %u", +- htt_stats_buf->fw_to_host_data_msdu_uc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_remote_data_buf_recycle_cnt = %u", +- htt_stats_buf->ofld_remote_data_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_remote_free_buf_indication_cnt = %u", +- htt_stats_buf->ofld_remote_free_buf_indication_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_buf_to_host_data_msdu_uc = %u", +- htt_stats_buf->ofld_buf_to_host_data_msdu_uc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "reo_fw_ring_to_host_data_msdu_uc = %u", +- htt_stats_buf->reo_fw_ring_to_host_data_msdu_uc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_sw_ring_reap = %u", +- htt_stats_buf->wbm_sw_ring_reap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_forward_to_host_cnt = %u", +- htt_stats_buf->wbm_forward_to_host_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_target_recycle_cnt = %u", +- htt_stats_buf->wbm_target_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "target_refill_ring_recycle_cnt = %u", +- htt_stats_buf->target_refill_ring_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_SOC_FW_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "fw_reo_ring_data_msdu = %u\n", ++ htt_stats_buf->fw_reo_ring_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_to_host_data_msdu_bcmc = %u\n", ++ htt_stats_buf->fw_to_host_data_msdu_bcmc); ++ len += scnprintf(buf + len, buf_len - len, "fw_to_host_data_msdu_uc = %u\n", ++ htt_stats_buf->fw_to_host_data_msdu_uc); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_remote_data_buf_recycle_cnt = %u\n", ++ htt_stats_buf->ofld_remote_data_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_remote_free_buf_indication_cnt = %u\n", ++ htt_stats_buf->ofld_remote_free_buf_indication_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_buf_to_host_data_msdu_uc = %u\n", ++ htt_stats_buf->ofld_buf_to_host_data_msdu_uc); ++ len += scnprintf(buf + len, buf_len - len, ++ "reo_fw_ring_to_host_data_msdu_uc = %u\n", ++ htt_stats_buf->reo_fw_ring_to_host_data_msdu_uc); ++ len += scnprintf(buf + len, buf_len - len, "wbm_sw_ring_reap = %u\n", ++ htt_stats_buf->wbm_sw_ring_reap); ++ len += scnprintf(buf + len, buf_len - len, "wbm_forward_to_host_cnt = %u\n", ++ htt_stats_buf->wbm_forward_to_host_cnt); ++ len += scnprintf(buf + len, buf_len - len, "wbm_target_recycle_cnt = %u\n", ++ htt_stats_buf->wbm_target_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "target_refill_ring_recycle_cnt = %u\n", ++ htt_stats_buf->target_refill_ring_recycle_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3317,14 +3313,14 @@ htt_print_rx_soc_fw_refill_ring_empty_tl + char refill_ring_empty_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(refill_ring_empty_cnt, + htt_stats_buf->refill_ring_empty_cnt, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n", +- refill_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n\n", ++ refill_ring_empty_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3347,14 +3343,14 @@ htt_print_rx_soc_fw_refill_ring_num_rxdm + char rxdma_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_RXDMA_MAX_ERR_CODE); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(rxdma_err_cnt, + htt_stats_buf->rxdma_err, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdma_err = %s\n", +- rxdma_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rxdma_err = %s\n\n", ++ rxdma_err_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3376,14 +3372,14 @@ htt_print_rx_soc_fw_refill_ring_num_reo_ + char reo_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_REO_MAX_ERR_CODE); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(reo_err_cnt, + htt_stats_buf->reo_err, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "reo_err = %s\n", +- reo_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "reo_err = %s\n\n", ++ reo_err_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3402,27 +3398,27 @@ htt_print_rx_reo_debug_stats_tlv_v(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_REO_RESOURCE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sample_id = %u", +- htt_stats_buf->sample_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_max = %u", +- htt_stats_buf->total_max); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_avg = %u", +- htt_stats_buf->total_avg); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_sample = %u", +- htt_stats_buf->total_sample); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "non_zeros_avg = %u", +- htt_stats_buf->non_zeros_avg); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "non_zeros_sample = %u", +- htt_stats_buf->non_zeros_sample); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_max = %u", +- htt_stats_buf->last_non_zeros_max); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_min %u", +- htt_stats_buf->last_non_zeros_min); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_avg %u", +- htt_stats_buf->last_non_zeros_avg); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_sample %u\n", +- htt_stats_buf->last_non_zeros_sample); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_REO_RESOURCE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "sample_id = %u\n", ++ htt_stats_buf->sample_id); ++ len += scnprintf(buf + len, buf_len - len, "total_max = %u\n", ++ htt_stats_buf->total_max); ++ len += scnprintf(buf + len, buf_len - len, "total_avg = %u\n", ++ htt_stats_buf->total_avg); ++ len += scnprintf(buf + len, buf_len - len, "total_sample = %u\n", ++ htt_stats_buf->total_sample); ++ len += scnprintf(buf + len, buf_len - len, "non_zeros_avg = %u\n", ++ htt_stats_buf->non_zeros_avg); ++ len += scnprintf(buf + len, buf_len - len, "non_zeros_sample = %u\n", ++ htt_stats_buf->non_zeros_sample); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_max = %u\n", ++ htt_stats_buf->last_non_zeros_max); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_min %u\n", ++ htt_stats_buf->last_non_zeros_min); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_avg %u\n", ++ htt_stats_buf->last_non_zeros_avg); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_sample %u\n\n", ++ htt_stats_buf->last_non_zeros_sample); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3444,14 +3440,14 @@ htt_print_rx_soc_fw_refill_ring_num_refi + char refill_ring_num_refill[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(refill_ring_num_refill, + htt_stats_buf->refill_ring_num_refill, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_num_refill = %s\n", +- refill_ring_num_refill); ++ len += scnprintf(buf + len, buf_len - len, "refill_ring_num_refill = %s\n\n", ++ refill_ring_num_refill); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3471,110 +3467,110 @@ static inline void htt_print_rx_pdev_fw_ + char fw_ring_mgmt_subtype[HTT_MAX_STRING_LEN] = {0}; + char fw_ring_ctrl_subtype[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ppdu_recvd = %u", +- htt_stats_buf->ppdu_recvd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u", +- htt_stats_buf->mpdu_cnt_fcs_ok); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt_fcs_err = %u", +- htt_stats_buf->mpdu_cnt_fcs_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcp_msdu_cnt = %u", +- htt_stats_buf->tcp_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcp_ack_msdu_cnt = %u", +- htt_stats_buf->tcp_ack_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "udp_msdu_cnt = %u", +- htt_stats_buf->udp_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "other_msdu_cnt = %u", +- htt_stats_buf->other_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u", +- htt_stats_buf->fw_ring_mpdu_ind); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "ppdu_recvd = %u\n", ++ htt_stats_buf->ppdu_recvd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u\n", ++ htt_stats_buf->mpdu_cnt_fcs_ok); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_err = %u\n", ++ htt_stats_buf->mpdu_cnt_fcs_err); ++ len += scnprintf(buf + len, buf_len - len, "tcp_msdu_cnt = %u\n", ++ htt_stats_buf->tcp_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "tcp_ack_msdu_cnt = %u\n", ++ htt_stats_buf->tcp_ack_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "udp_msdu_cnt = %u\n", ++ htt_stats_buf->udp_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "other_msdu_cnt = %u\n", ++ htt_stats_buf->other_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u\n", ++ htt_stats_buf->fw_ring_mpdu_ind); + + PRINT_ARRAY_TO_BUF(fw_ring_mgmt_subtype, + htt_stats_buf->fw_ring_mgmt_subtype, + HTT_STATS_SUBTYPE_MAX); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s ", +- fw_ring_mgmt_subtype); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s\n", ++ fw_ring_mgmt_subtype); + + PRINT_ARRAY_TO_BUF(fw_ring_ctrl_subtype, + htt_stats_buf->fw_ring_ctrl_subtype, + HTT_STATS_SUBTYPE_MAX); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s ", +- fw_ring_ctrl_subtype); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u", +- htt_stats_buf->fw_ring_mcast_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u", +- htt_stats_buf->fw_ring_bcast_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ucast_data_msdu = %u", +- htt_stats_buf->fw_ring_ucast_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_null_data_msdu = %u", +- htt_stats_buf->fw_ring_null_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_drop = %u", +- htt_stats_buf->fw_ring_mpdu_drop); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofld_local_data_ind_cnt = %u", +- htt_stats_buf->ofld_local_data_ind_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_local_data_buf_recycle_cnt = %u", +- htt_stats_buf->ofld_local_data_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "drx_local_data_ind_cnt = %u", +- htt_stats_buf->drx_local_data_ind_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "drx_local_data_buf_recycle_cnt = %u", +- htt_stats_buf->drx_local_data_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_nondata_ind_cnt = %u", +- htt_stats_buf->local_nondata_ind_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_nondata_buf_recycle_cnt = %u", +- htt_stats_buf->local_nondata_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_status_buf_ring_refill_cnt = %u", +- htt_stats_buf->fw_status_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_status_buf_ring_empty_cnt = %u", +- htt_stats_buf->fw_status_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_pkt_buf_ring_refill_cnt = %u", +- htt_stats_buf->fw_pkt_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_pkt_buf_ring_empty_cnt = %u", +- htt_stats_buf->fw_pkt_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_link_buf_ring_refill_cnt = %u", +- htt_stats_buf->fw_link_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_link_buf_ring_empty_cnt = %u", +- htt_stats_buf->fw_link_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "host_pkt_buf_ring_refill_cnt = %u", +- htt_stats_buf->host_pkt_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "host_pkt_buf_ring_empty_cnt = %u", +- htt_stats_buf->host_pkt_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_pkt_buf_ring_refill_cnt = %u", +- htt_stats_buf->mon_pkt_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_pkt_buf_ring_empty_cnt = %u", +- htt_stats_buf->mon_pkt_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "mon_status_buf_ring_refill_cnt = %u", +- htt_stats_buf->mon_status_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_status_buf_ring_empty_cnt = %u", +- htt_stats_buf->mon_status_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_desc_buf_ring_refill_cnt = %u", +- htt_stats_buf->mon_desc_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_desc_buf_ring_empty_cnt = %u", +- htt_stats_buf->mon_desc_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_dest_ring_update_cnt = %u", +- htt_stats_buf->mon_dest_ring_update_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_dest_ring_full_cnt = %u", +- htt_stats_buf->mon_dest_ring_full_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_suspend_cnt = %u", +- htt_stats_buf->rx_suspend_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_suspend_fail_cnt = %u", +- htt_stats_buf->rx_suspend_fail_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_resume_cnt = %u", +- htt_stats_buf->rx_resume_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_resume_fail_cnt = %u", +- htt_stats_buf->rx_resume_fail_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ring_switch_cnt = %u", +- htt_stats_buf->rx_ring_switch_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ring_restore_cnt = %u", +- htt_stats_buf->rx_ring_restore_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_flush_cnt = %u", +- htt_stats_buf->rx_flush_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_recovery_reset_cnt = %u\n", +- htt_stats_buf->rx_recovery_reset_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s\n", ++ fw_ring_ctrl_subtype); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_mcast_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_bcast_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_ucast_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_ucast_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_null_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_null_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_drop = %u\n", ++ htt_stats_buf->fw_ring_mpdu_drop); ++ len += scnprintf(buf + len, buf_len - len, "ofld_local_data_ind_cnt = %u\n", ++ htt_stats_buf->ofld_local_data_ind_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_local_data_buf_recycle_cnt = %u\n", ++ htt_stats_buf->ofld_local_data_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "drx_local_data_ind_cnt = %u\n", ++ htt_stats_buf->drx_local_data_ind_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "drx_local_data_buf_recycle_cnt = %u\n", ++ htt_stats_buf->drx_local_data_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "local_nondata_ind_cnt = %u\n", ++ htt_stats_buf->local_nondata_ind_cnt); ++ len += scnprintf(buf + len, buf_len - len, "local_nondata_buf_recycle_cnt = %u\n", ++ htt_stats_buf->local_nondata_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_status_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->fw_status_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_status_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->fw_status_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_pkt_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->fw_pkt_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_pkt_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->fw_pkt_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_link_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->fw_link_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_link_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->fw_link_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "host_pkt_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->host_pkt_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "host_pkt_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->host_pkt_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_pkt_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->mon_pkt_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_pkt_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->mon_pkt_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "mon_status_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->mon_status_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_status_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->mon_status_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_desc_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->mon_desc_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_desc_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->mon_desc_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_dest_ring_update_cnt = %u\n", ++ htt_stats_buf->mon_dest_ring_update_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_dest_ring_full_cnt = %u\n", ++ htt_stats_buf->mon_dest_ring_full_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_suspend_cnt = %u\n", ++ htt_stats_buf->rx_suspend_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_suspend_fail_cnt = %u\n", ++ htt_stats_buf->rx_suspend_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_resume_cnt = %u\n", ++ htt_stats_buf->rx_resume_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_resume_fail_cnt = %u\n", ++ htt_stats_buf->rx_resume_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_ring_switch_cnt = %u\n", ++ htt_stats_buf->rx_ring_switch_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_ring_restore_cnt = %u\n", ++ htt_stats_buf->rx_ring_restore_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_flush_cnt = %u\n", ++ htt_stats_buf->rx_flush_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_recovery_reset_cnt = %u\n\n", ++ htt_stats_buf->rx_recovery_reset_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3594,14 +3590,14 @@ htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char fw_ring_mpdu_err[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(fw_ring_mpdu_err, + htt_stats_buf->fw_ring_mpdu_err, + HTT_RX_STATS_RXDMA_MAX_ERR); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n", +- fw_ring_mpdu_err); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n\n", ++ fw_ring_mpdu_err); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3623,12 +3619,12 @@ htt_print_rx_pdev_fw_mpdu_drop_tlv_v(con + char fw_mpdu_drop[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_FW_DROP_REASON_MAX); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(fw_mpdu_drop, + htt_stats_buf->fw_mpdu_drop, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_mpdu_drop = %s\n", fw_mpdu_drop); ++ len += scnprintf(buf + len, buf_len - len, "fw_mpdu_drop = %s\n\n", fw_mpdu_drop); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3648,16 +3644,16 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char phy_errs[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id__word = %u", +- htt_stats_buf->mac_id__word); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_phy_err_nct = %u", +- htt_stats_buf->total_phy_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id__word = %u\n", ++ htt_stats_buf->mac_id__word); ++ len += scnprintf(buf + len, buf_len - len, "total_phy_err_nct = %u\n", ++ htt_stats_buf->total_phy_err_cnt); + + PRINT_ARRAY_TO_BUF(phy_errs, + htt_stats_buf->phy_err, + HTT_STATS_PHY_ERR_MAX); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); ++ len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3676,20 +3672,20 @@ htt_print_pdev_cca_stats_hist_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\nHTT_PDEV_CCA_STATS_HIST_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "chan_num = %u", +- htt_stats_buf->chan_num); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u", +- htt_stats_buf->num_records); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x", +- htt_stats_buf->valid_cca_counters_bitmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "collection_interval = %u\n", +- htt_stats_buf->collection_interval); +- +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "| tx_frame| rx_frame| rx_clear| my_rx_frame| cnt| med_rx_idle| med_tx_idle_global| cca_obss|"); ++ len += scnprintf(buf + len, buf_len - len, "\nHTT_PDEV_CCA_STATS_HIST_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n", ++ htt_stats_buf->chan_num); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n", ++ htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x\n", ++ htt_stats_buf->valid_cca_counters_bitmap); ++ len += scnprintf(buf + len, buf_len - len, "collection_interval = %u\n\n", ++ htt_stats_buf->collection_interval); ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "| tx_frame| rx_frame| rx_clear| my_rx_frame| cnt| med_rx_idle| med_tx_idle_global| cca_obss|\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3708,16 +3704,16 @@ htt_print_pdev_stats_cca_counters_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "|%10u| %10u| %10u| %11u| %10u| %11u| %18u| %10u|", +- htt_stats_buf->tx_frame_usec, +- htt_stats_buf->rx_frame_usec, +- htt_stats_buf->rx_clear_usec, +- htt_stats_buf->my_rx_frame_usec, +- htt_stats_buf->usec_cnt, +- htt_stats_buf->med_rx_idle_usec, +- htt_stats_buf->med_tx_idle_global_usec, +- htt_stats_buf->cca_obss_usec); ++ len += scnprintf(buf + len, buf_len - len, ++ "|%10u| %10u| %10u| %11u| %10u| %11u| %18u| %10u|\n", ++ htt_stats_buf->tx_frame_usec, ++ htt_stats_buf->rx_frame_usec, ++ htt_stats_buf->rx_clear_usec, ++ htt_stats_buf->my_rx_frame_usec, ++ htt_stats_buf->usec_cnt, ++ htt_stats_buf->med_rx_idle_usec, ++ htt_stats_buf->med_tx_idle_global_usec, ++ htt_stats_buf->cca_obss_usec); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3735,32 +3731,32 @@ static inline void htt_print_hw_stats_wh + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_unpause_ppdu_id = %u", +- htt_stats_buf->last_unpause_ppdu_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u", +- htt_stats_buf->hwsch_unpause_wait_tqm_write); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_dummy_tlv_skipped = %u", +- htt_stats_buf->hwsch_dummy_tlv_skipped); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "hwsch_misaligned_offset_received = %u", +- htt_stats_buf->hwsch_misaligned_offset_received); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_reset_count = %u", +- htt_stats_buf->hwsch_reset_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_dev_reset_war = %u", +- htt_stats_buf->hwsch_dev_reset_war); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_delayed_pause = %u", +- htt_stats_buf->hwsch_delayed_pause); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_long_delayed_pause = %u", +- htt_stats_buf->hwsch_long_delayed_pause); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_rx_ppdu_no_response = %u", +- htt_stats_buf->sch_rx_ppdu_no_response); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_selfgen_response = %u", +- htt_stats_buf->sch_selfgen_response); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_rx_sifs_resp_trigger= %u\n", +- htt_stats_buf->sch_rx_sifs_resp_trigger); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "last_unpause_ppdu_id = %u\n", ++ htt_stats_buf->last_unpause_ppdu_id); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u\n", ++ htt_stats_buf->hwsch_unpause_wait_tqm_write); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_dummy_tlv_skipped = %u\n", ++ htt_stats_buf->hwsch_dummy_tlv_skipped); ++ len += scnprintf(buf + len, buf_len - len, ++ "hwsch_misaligned_offset_received = %u\n", ++ htt_stats_buf->hwsch_misaligned_offset_received); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_reset_count = %u\n", ++ htt_stats_buf->hwsch_reset_count); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_dev_reset_war = %u\n", ++ htt_stats_buf->hwsch_dev_reset_war); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_delayed_pause = %u\n", ++ htt_stats_buf->hwsch_delayed_pause); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_long_delayed_pause = %u\n", ++ htt_stats_buf->hwsch_long_delayed_pause); ++ len += scnprintf(buf + len, buf_len - len, "sch_rx_ppdu_no_response = %u\n", ++ htt_stats_buf->sch_rx_ppdu_no_response); ++ len += scnprintf(buf + len, buf_len - len, "sch_selfgen_response = %u\n", ++ htt_stats_buf->sch_selfgen_response); ++ len += scnprintf(buf + len, buf_len - len, "sch_rx_sifs_resp_trigger= %u\n\n", ++ htt_stats_buf->sch_rx_sifs_resp_trigger); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3779,11 +3775,11 @@ htt_print_pdev_stats_twt_sessions_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSIONS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u", +- htt_stats_buf->pdev_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sessions = %u\n", +- htt_stats_buf->num_sessions); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSIONS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", ++ htt_stats_buf->pdev_id); ++ len += scnprintf(buf + len, buf_len - len, "num_sessions = %u\n\n", ++ htt_stats_buf->num_sessions); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3802,27 +3798,27 @@ htt_print_pdev_stats_twt_session_tlv(con + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSION_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "vdev_id = %u", +- htt_stats_buf->vdev_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x", +- htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF), +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flow_id_flags = %u", +- htt_stats_buf->flow_id_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dialog_id = %u", +- htt_stats_buf->dialog_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wake_dura_us = %u", +- htt_stats_buf->wake_dura_us); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wake_intvl_us = %u", +- htt_stats_buf->wake_intvl_us); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sp_offset_us = %u\n", +- htt_stats_buf->sp_offset_us); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSION_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", ++ htt_stats_buf->vdev_id); ++ len += scnprintf(buf + len, buf_len - len, ++ "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF, ++ (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8, ++ (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16, ++ (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24, ++ (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF), ++ (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "flow_id_flags = %u\n", ++ htt_stats_buf->flow_id_flags); ++ len += scnprintf(buf + len, buf_len - len, "dialog_id = %u\n", ++ htt_stats_buf->dialog_id); ++ len += scnprintf(buf + len, buf_len - len, "wake_dura_us = %u\n", ++ htt_stats_buf->wake_dura_us); ++ len += scnprintf(buf + len, buf_len - len, "wake_intvl_us = %u\n", ++ htt_stats_buf->wake_intvl_us); ++ len += scnprintf(buf + len, buf_len - len, "sp_offset_us = %u\n\n", ++ htt_stats_buf->sp_offset_us); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3841,21 +3837,21 @@ htt_print_pdev_obss_pd_stats_tlv_v(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "OBSS Tx success PPDU = %u", ++ len += scnprintf(buf + len, buf_len - len, "OBSS Tx success PPDU = %u\n", + htt_stats_buf->num_obss_tx_ppdu_success); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "OBSS Tx failures PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "OBSS Tx failures PPDU = %u\n", + htt_stats_buf->num_obss_tx_ppdu_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG Opportunities = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "Non-SRG Opportunities = %u\n", + htt_stats_buf->num_non_srg_opportunities); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG tried PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "Non-SRG tried PPDU = %u\n", + htt_stats_buf->num_non_srg_ppdu_tried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG success PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "Non-SRG success PPDU = %u\n", + htt_stats_buf->num_non_srg_ppdu_success); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG Opportunities = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "SRG Opportunities = %u\n", + htt_stats_buf->num_srg_opportunities); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG tried PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "SRG tried PPDU = %u\n", + htt_stats_buf->num_srg_ppdu_tried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG success PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "SRG success PPDU = %u\n\n", + htt_stats_buf->num_srg_ppdu_success); + + if (len >= buf_len) +@@ -3878,25 +3874,25 @@ static inline void htt_print_backpressur + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u", +- htt_stats_buf->pdev_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_head_idx = %u", +- htt_stats_buf->current_head_idx); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_tail_idx = %u", +- htt_stats_buf->current_tail_idx); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_htt_msgs_sent = %u", +- htt_stats_buf->num_htt_msgs_sent); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "backpressure_time_ms = %u", +- htt_stats_buf->backpressure_time_ms); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", ++ htt_stats_buf->pdev_id); ++ len += scnprintf(buf + len, buf_len - len, "current_head_idx = %u\n", ++ htt_stats_buf->current_head_idx); ++ len += scnprintf(buf + len, buf_len - len, "current_tail_idx = %u\n", ++ htt_stats_buf->current_tail_idx); ++ len += scnprintf(buf + len, buf_len - len, "num_htt_msgs_sent = %u\n", ++ htt_stats_buf->num_htt_msgs_sent); ++ len += scnprintf(buf + len, buf_len - len, ++ "backpressure_time_ms = %u\n", ++ htt_stats_buf->backpressure_time_ms); + + for (i = 0; i < 5; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "backpressure_hist_%u = %u", +- i + 1, htt_stats_buf->backpressure_hist[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "backpressure_hist_%u = %u\n", ++ i + 1, htt_stats_buf->backpressure_hist[i]); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "============================"); ++ len += scnprintf(buf + len, buf_len - len, ++ "============================\n"); + + if (len >= buf_len) { + buf[buf_len - 1] = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0044-ath11k-Remove-htt-stats-fixed-size-array-usage.patch b/package/kernel/mac80211/patches/ath11k/0044-ath11k-Remove-htt-stats-fixed-size-array-usage.patch new file mode 100644 index 000000000..70e5ea6ae --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0044-ath11k-Remove-htt-stats-fixed-size-array-usage.patch @@ -0,0 +1,1451 @@ +From 74327bab6781a34d96ff4c0a7c59bb032fab1650 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ath11k: Remove htt stats fixed size array usage + +To support the HTT Stats DebugFS interface a single large buffer that +contains the stats must be provided to the DebugFS infrastructure. +In the current code, for each class of stats, the stats are first +formatted in a local on-stack buffer, and then the local buffer is +copied to the large DebugFS buffer. + +This logic has a problem when, for a given class, the formatted +stats exceed the size of the on-stack buffer. When this occurs the +stats for this class is truncated. In addition, this logic is +inefficient since it introduces an unnecessary memory copy. + +To address these issues, update the logic to no longer use a local +on-stack buffer, and instead write the formatted data directly into +the large DebugFS buffer. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01105-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-4-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 838 ++++++------------ + 1 file changed, 264 insertions(+), 574 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -10,20 +10,28 @@ + #include "debug.h" + #include "debugfs_htt_stats.h" + +-#define HTT_MAX_STRING_LEN 256 + #define HTT_MAX_PRINT_CHAR_PER_ELEM 15 + + #define HTT_TLV_HDR_LEN 4 + +-#define PRINT_ARRAY_TO_BUF(out, arr, len) \ ++#define PRINT_ARRAY_TO_BUF(out, buflen, arr, str, len, newline) \ + do { \ +- int index = 0; u8 i; \ ++ int index = 0; u8 i; const char *str_val = str; \ ++ const char *new_line = newline; \ ++ if (str_val) { \ ++ index += scnprintf((out + buflen), \ ++ (ATH11K_HTT_STATS_BUF_SIZE - buflen), \ ++ "%s = ", str_val); \ ++ } \ + for (i = 0; i < len; i++) { \ +- index += scnprintf(out + index, HTT_MAX_STRING_LEN - index, \ +- " %u:%u,", i, arr[i]); \ +- if (index < 0 || index >= HTT_MAX_STRING_LEN) \ +- break; \ ++ index += scnprintf((out + buflen) + index, \ ++ (ATH11K_HTT_STATS_BUF_SIZE - buflen) - index, \ ++ " %u:%u,", i, arr[i]); \ + } \ ++ index += scnprintf((out + buflen) + index, \ ++ (ATH11K_HTT_STATS_BUF_SIZE - buflen) - index, \ ++ "%s", new_line); \ ++ buflen += index; \ + } while (0) + + static inline void htt_print_stats_string_tlv(const void *tag_buf, +@@ -35,22 +43,20 @@ static inline void htt_print_stats_strin + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 i; +- u16 index = 0; +- char data[HTT_MAX_STRING_LEN] = {0}; + + tag_len = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n"); + ++ len += scnprintf(buf + len, buf_len - len, ++ "data = "); + for (i = 0; i < tag_len; i++) { +- index += scnprintf(&data[index], +- HTT_MAX_STRING_LEN - index, +- "%.*s", 4, (char *)&(htt_stats_buf->data[i])); +- if (index >= HTT_MAX_STRING_LEN) +- break; ++ len += scnprintf(buf + len, ++ buf_len - len, ++ "%.*s", 4, (char *)&(htt_stats_buf->data[i])); + } +- +- len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data); ++ /* New lines are added for better display */ ++ len += scnprintf(buf + len, buf_len - len, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -187,13 +193,12 @@ htt_print_tx_pdev_stats_urrn_tlv_v(const + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char urrn_stats[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_URRN_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(urrn_stats, htt_stats_buf->urrn_stats, num_elems); +- len += scnprintf(buf + len, buf_len - len, "urrn_stats = %s\n\n", urrn_stats); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->urrn_stats, "urrn_stats", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -212,13 +217,12 @@ htt_print_tx_pdev_stats_flush_tlv_v(cons + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char flush_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_FLUSH_REASON_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(flush_errs, htt_stats_buf->flush_errs, num_elems); +- len += scnprintf(buf + len, buf_len - len, "flush_errs = %s\n\n", flush_errs); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->flush_errs, "flush_errs", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -237,14 +241,12 @@ htt_print_tx_pdev_stats_sifs_tlv_v(const + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sifs_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sifs_status, htt_stats_buf->sifs_status, num_elems); +- len += scnprintf(buf + len, buf_len - len, "sifs_status = %s\n\n", +- sifs_status); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sifs_status, "sifs_status", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -263,13 +265,12 @@ htt_print_tx_pdev_stats_phy_err_tlv_v(co + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char phy_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_PHY_ERR_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(phy_errs, htt_stats_buf->phy_errs, num_elems); +- len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->phy_errs, "phy_errs", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -288,15 +289,13 @@ htt_print_tx_pdev_stats_sifs_hist_tlv_v( + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sifs_hist_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); +- len += scnprintf(buf + len, buf_len - len, "sifs_hist_status = %s\n\n", +- sifs_hist_status); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sifs_hist_status, ++ "sifs_hist_status", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -350,25 +349,15 @@ htt_print_tx_pdev_stats_tried_mpdu_cnt_h + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char tried_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u32 num_elements = ((tag_len - sizeof(htt_stats_buf->hist_bin_size)) >> 2); +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", + htt_stats_buf->hist_bin_size); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n\n", +- tried_mpdu_cnt_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tried_mpdu_cnt_hist, ++ "tried_mpdu_cnt_hist", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -659,14 +648,12 @@ static inline void htt_print_counter_tlv + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char counter_name[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_COUNTER_TLV:\n"); + +- PRINT_ARRAY_TO_BUF(counter_name, +- htt_stats_buf->counter_name, +- HTT_MAX_COUNTER_NAME); +- len += scnprintf(buf + len, buf_len - len, "counter_name = %s\n", counter_name); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->counter_name, ++ "counter_name", ++ HTT_MAX_COUNTER_NAME, "\n"); + len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", + htt_stats_buf->count); + +@@ -771,16 +758,8 @@ static inline void htt_print_tx_peer_rat + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- char *tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS] = {NULL}; + u8 j; + +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- tx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!tx_gi[j]) +- goto fail; +- } +- + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", + htt_stats_buf->tx_ldpc); +@@ -789,56 +768,30 @@ static inline void htt_print_tx_peer_rat + len += scnprintf(buf + len, buf_len - len, "ack_rssi = %u\n", + htt_stats_buf->ack_rssi); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_su_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_su_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mu_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_mu_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, +- htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, +- htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_mcs, "tx_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_su_mcs, "tx_su_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_mu_mcs, "tx_mu_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_nss, "tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_bw, "tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_stbc, "tx_stbc", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_pream, "tx_pream", ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], +- htt_stats_buf->tx_gi[j], +- HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_gi[j], NULL, ++ HTT_TX_PEER_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, +- htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_dcm, "tx_dcm", ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -847,9 +800,6 @@ static inline void htt_print_tx_peer_rat + + stats_req->buf_len = len; + +-fail: +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) +- kfree(tx_gi[j]); + } + + static inline void htt_print_rx_peer_rate_stats_tlv(const void *tag_buf, +@@ -860,21 +810,6 @@ static inline void htt_print_rx_peer_rat + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 j; +- char *rssi_chain[HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS] = {NULL}; +- char *rx_gi[HTT_RX_PEER_STATS_NUM_GI_COUNTERS] = {NULL}; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { +- rssi_chain[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rssi_chain[j]) +- goto fail; +- } +- +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- rx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rx_gi[j]) +- goto fail; +- } + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", +@@ -890,49 +825,33 @@ static inline void htt_print_rx_peer_rat + len += scnprintf(buf + len, buf_len - len, "rssi_comb = %u\n", + htt_stats_buf->rssi_comb); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_mcs, "rx_mcs", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_nss, "rx_nss", ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_dcm, "rx_dcm", ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_stbc, "rx_stbc", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_bw, "rx_bw", ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { +- PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PEER_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "rssi_chain[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rssi_chain[j], NULL, ++ HTT_RX_PEER_STATS_NUM_BW_COUNTERS, "\n"); + } + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "rx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_gi[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_pream, "rx_pream", ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -940,13 +859,6 @@ static inline void htt_print_rx_peer_rat + buf[len] = 0; + + stats_req->buf_len = len; +- +-fail: +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) +- kfree(rssi_chain[j]); +- +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) +- kfree(rx_gi[j]); + } + + static inline void +@@ -1104,17 +1016,14 @@ htt_print_tx_hwq_difs_latency_stats_tlv_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS); +- char difs_latency_hist[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "hist_intvl = %u\n", + htt_stats_buf->hist_intvl); + +- PRINT_ARRAY_TO_BUF(difs_latency_hist, htt_stats_buf->difs_latency_hist, +- data_len); +- len += scnprintf(buf + len, buf_len - len, "difs_latency_hist = %s\n\n", +- difs_latency_hist); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->difs_latency_hist, ++ "difs_latency_hist", data_len, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1134,16 +1043,14 @@ htt_print_tx_hwq_cmd_result_stats_tlv_v( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 data_len; +- char cmd_result[HTT_MAX_STRING_LEN] = {0}; + + data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_RESULT_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(cmd_result, htt_stats_buf->cmd_result, data_len); +- +- len += scnprintf(buf + len, buf_len - len, "cmd_result = %s\n\n", cmd_result); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->cmd_result, "cmd_result", ++ data_len, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1163,15 +1070,13 @@ htt_print_tx_hwq_cmd_stall_stats_tlv_v(c + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 num_elems; +- char cmd_stall_status[HTT_MAX_STRING_LEN] = {0}; + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_STALL_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); +- len += scnprintf(buf + len, buf_len - len, "cmd_stall_status = %s\n\n", +- cmd_stall_status); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->cmd_stall_status, ++ "cmd_stall_status", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1191,15 +1096,14 @@ htt_print_tx_hwq_fes_result_stats_tlv_v( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 num_elems; +- char fes_result[HTT_MAX_STRING_LEN] = {0}; + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_FES_RESULT_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(fes_result, htt_stats_buf->fes_result, num_elems); +- len += scnprintf(buf + len, buf_len - len, "fes_result = %s\n\n", fes_result); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fes_result, "fes_result", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1218,27 +1122,16 @@ htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char tried_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u32 num_elements = ((tag_len - + sizeof(htt_stats_buf->hist_bin_size)) >> 2); +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", + htt_stats_buf->hist_bin_size); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, +- "tried_mpdu_cnt_hist = %s\n\n", +- tried_mpdu_cnt_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tried_mpdu_cnt_hist, ++ "tried_mpdu_cnt_hist", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1257,23 +1150,14 @@ htt_print_tx_hwq_txop_used_cnt_hist_tlv_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char txop_used_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u32 num_elements = tag_len >> 2; +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:\n"); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(txop_used_cnt_hist, +- htt_stats_buf->txop_used_cnt_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n\n", +- txop_used_cnt_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->txop_used_cnt_hist, ++ "txop_used_cnt_hist", num_elements, "\n\n"); ++ + if (len >= buf_len) + buf[buf_len - 1] = 0; + else +@@ -1781,15 +1665,12 @@ htt_print_sched_txq_cmd_posted_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_cmd_posted[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + + len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "sched_cmd_posted = %s\n\n", +- sched_cmd_posted); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_cmd_posted, ++ "sched_cmd_posted", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1808,15 +1689,12 @@ htt_print_sched_txq_cmd_reaped_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_cmd_reaped[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + + len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "sched_cmd_reaped = %s\n\n", +- sched_cmd_reaped); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_cmd_reaped, ++ "sched_cmd_reaped", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1835,7 +1713,6 @@ htt_print_sched_txq_sched_order_su_tlv_v + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_order_su[HTT_MAX_STRING_LEN] = {0}; + /* each entry is u32, i.e. 4 bytes */ + u32 sched_order_su_num_entries = + min_t(u32, (tag_len >> 2), HTT_TX_PDEV_NUM_SCHED_ORDER_LOG); +@@ -1843,10 +1720,8 @@ htt_print_sched_txq_sched_order_su_tlv_v + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_order_su, htt_stats_buf->sched_order_su, +- sched_order_su_num_entries); +- len += scnprintf(buf + len, buf_len - len, "sched_order_su = %s\n\n", +- sched_order_su); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_order_su, "sched_order_su", ++ sched_order_su_num_entries, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1865,17 +1740,15 @@ htt_print_sched_txq_sched_ineligibility_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_ineligibility[HTT_MAX_STRING_LEN] = {0}; + /* each entry is u32, i.e. 4 bytes */ + u32 sched_ineligibility_num_entries = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_ineligibility, htt_stats_buf->sched_ineligibility, +- sched_ineligibility_num_entries); +- len += scnprintf(buf + len, buf_len - len, "sched_ineligibility = %s\n\n", +- sched_ineligibility); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_ineligibility, ++ "sched_ineligibility", sched_ineligibility_num_entries, ++ "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1982,16 +1855,13 @@ htt_print_tx_tqm_gen_mpdu_stats_tlv_v(co + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char gen_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n\n", +- gen_mpdu_end_reason); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->gen_mpdu_end_reason, ++ "gen_mpdu_end_reason", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2010,16 +1880,14 @@ htt_print_tx_tqm_list_mpdu_stats_tlv_v(c + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char list_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n\n", +- list_mpdu_end_reason); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->list_mpdu_end_reason, ++ "list_mpdu_end_reason", num_elems, "\n\n"); ++ + if (len >= buf_len) + buf[buf_len - 1] = 0; + else +@@ -2037,16 +1905,13 @@ htt_print_tx_tqm_list_mpdu_cnt_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char list_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n\n", +- list_mpdu_cnt_hist); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->list_mpdu_cnt_hist, ++ "list_mpdu_cnt_hist", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2527,24 +2392,13 @@ htt_print_tx_de_fw2wbm_ring_full_hist_tl + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw2wbm_ring_full_hist[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = tag_len >> 2; +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(fw2wbm_ring_full_hist, +- htt_stats_buf->fw2wbm_ring_full_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, +- "fw2wbm_ring_full_hist = %s\n\n", +- fw2wbm_ring_full_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw2wbm_ring_full_hist, ++ "fw2wbm_ring_full_hist", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2593,8 +2447,6 @@ static inline void htt_print_ring_if_sta + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char low_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; +- char high_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "base_addr = %u\n", +@@ -2630,15 +2482,10 @@ static inline void htt_print_ring_if_sta + len += scnprintf(buf + len, buf_len - len, "cons_blockwait_count = %u\n", + htt_stats_buf->cons_blockwait_count); + +- PRINT_ARRAY_TO_BUF(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, +- HTT_STATS_LOW_WM_BINS); +- len += scnprintf(buf + len, buf_len - len, "low_wm_hit_count = %s\n", +- low_wm_hit_count); +- +- PRINT_ARRAY_TO_BUF(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, +- HTT_STATS_HIGH_WM_BINS); +- len += scnprintf(buf + len, buf_len - len, "high_wm_hit_count = %s\n\n", +- high_wm_hit_count); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->low_wm_hit_count, ++ "low_wm_hit_count", HTT_STATS_LOW_WM_BINS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->high_wm_hit_count, ++ "high_wm_hit_count", HTT_STATS_HIGH_WM_BINS, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2678,16 +2525,12 @@ static inline void htt_print_sfm_client_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char dwords_used_by_user_n[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(dwords_used_by_user_n, +- htt_stats_buf->dwords_used_by_user_n, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n\n", +- dwords_used_by_user_n); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->dwords_used_by_user_n, ++ "dwords_used_by_user_n", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2838,14 +2681,6 @@ static inline void htt_print_tx_pdev_rat + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 j; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- char *tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS] = {NULL}; +- +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- tx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!tx_gi[j]) +- goto fail; +- } + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +@@ -2884,75 +2719,37 @@ static inline void htt_print_tx_pdev_rat + htt_stats_buf->tx_legacy_ofdm_rate[6], + htt_stats_buf->tx_legacy_ofdm_rate[7]); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_mcs, "tx_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_mcs, ++ "ac_mu_mimo_tx_mcs", HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_mcs, ++ "ax_mu_mimo_tx_mcs", HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_mcs, "ofdma_tx_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_nss, "tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_nss, ++ "ac_mu_mimo_tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_nss, ++ "ax_mu_mimo_tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_nss, "ofdma_tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_bw, "tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_bw, ++ "ac_mu_mimo_tx_bw", HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_bw, ++ "ax_mu_mimo_tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_bw, "ofdma_tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_stbc, "tx_stbc", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_pream, "tx_pream", ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + len += scnprintf(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u\n", + htt_stats_buf->tx_he_ltf[1], +@@ -2961,42 +2758,38 @@ static inline void htt_print_tx_pdev_rat + + /* SU GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_gi[j], NULL, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + + /* AC MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, +- "ac_mu_mimo_tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "ac_mu_mimo_tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_gi[j], ++ NULL, HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + + /* AX MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, +- "ax_mu_mimo_tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "ax_mu_mimo_tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_gi[j], ++ NULL, HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + + /* DL OFDMA GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "ofdma_tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_gi[j], NULL, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_dcm, "tx_dcm", ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3004,9 +2797,6 @@ static inline void htt_print_tx_pdev_rat + buf[len] = 0; + + stats_req->buf_len = len; +-fail: +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) +- kfree(tx_gi[j]); + } + + static inline void htt_print_rx_pdev_rate_stats_tlv(const void *tag_buf, +@@ -3017,29 +2807,6 @@ static inline void htt_print_rx_pdev_rat + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 i, j; +- u16 index = 0; +- char *rssi_chain[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS] = {NULL}; +- char *rx_gi[HTT_RX_PDEV_STATS_NUM_GI_COUNTERS] = {NULL}; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- char *rx_pilot_evm_db[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS] = {NULL}; +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- rssi_chain[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rssi_chain[j]) +- goto fail; +- } +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- rx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rx_gi[j]) +- goto fail; +- } +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- rx_pilot_evm_db[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rx_pilot_evm_db[j]) +- goto fail; +- } + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +@@ -3059,30 +2826,17 @@ static inline void htt_print_rx_pdev_rat + len += scnprintf(buf + len, buf_len - len, "rssi_in_dbm = %d\n", + htt_stats_buf->rssi_in_dbm); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_mcs, "rx_mcs", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_nss, "rx_nss", ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_dcm, "rx_dcm", ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_stbc, "rx_stbc", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_bw, "rx_bw", ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ + len += scnprintf(buf + len, buf_len - len, "rx_evm_nss_count = %u\n", + htt_stats_buf->nss_count); + +@@ -3090,44 +2844,43 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->pilot_count); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- index = 0; + ++ len += scnprintf(buf + len, buf_len - len, ++ "pilot_evm_db[%u] = ", j); + for (i = 0; i < HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS; i++) +- index += scnprintf(&rx_pilot_evm_db[j][index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_pilot_evm_db[j][i]); +- len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB[%u] = %s\n", +- j, rx_pilot_evm_db[j]); ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_pilot_evm_db[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + } + +- index = 0; +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); ++ len += scnprintf(buf + len, buf_len - len, ++ "pilot_evm_db_mean = "); + for (i = 0; i < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) +- index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", i, htt_stats_buf->rx_pilot_evm_db_mean[i]); +- len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB_mean = %s\n", str_buf); ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", i, ++ htt_stats_buf->rx_pilot_evm_db_mean[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rssi_chain[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rssi_chain[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); + } + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_gi[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_pream, "rx_pream", ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + len += scnprintf(buf + len, buf_len - len, "rx_11ax_su_ext = %u\n", + htt_stats_buf->rx_11ax_su_ext); +@@ -3140,17 +2893,13 @@ static inline void htt_print_rx_pdev_rat + len += scnprintf(buf + len, buf_len - len, "txbf = %u\n", + htt_stats_buf->txbf); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_cck_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); +- len += scnprintf(buf + len, buf_len - len, "rx_legacy_cck_rate = %s\n", +- str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); +- len += scnprintf(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s\n", +- str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_legacy_cck_rate, ++ "rx_legacy_cck_rate", ++ HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_legacy_ofdm_rate, ++ "rx_legacy_ofdm_rate", ++ HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS, "\n"); + + len += scnprintf(buf + len, buf_len - len, "rx_active_dur_us_low = %u\n", + htt_stats_buf->rx_active_dur_us_low); +@@ -3159,82 +2908,66 @@ static inline void htt_print_rx_pdev_rat + len += scnprintf(buf + len, buf_len - len, "rx_11ax_ul_ofdma = %u\n", + htt_stats_buf->rx_11ax_ul_ofdma); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_mcs, ++ "ul_ofdma_rx_mcs", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s\n", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ul_ofdma_rx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_gi[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_nss, ++ "ul_ofdma_rx_nss", ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_bw, "ul_ofdma_rx_bw", ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); + + len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u\n", + htt_stats_buf->ul_ofdma_rx_stbc); + len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_ldpc = %u\n", + htt_stats_buf->ul_ofdma_rx_ldpc); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s\n", +- str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s\n", +- str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s\n", +- str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_non_data_ppdu, ++ "rx_ulofdma_non_data_ppdu", ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_data_ppdu, ++ "rx_ulofdma_data_ppdu", HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_mpdu_ok, ++ "rx_ulofdma_mpdu_ok", HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_mpdu_fail, ++ "rx_ulofdma_mpdu_fail", HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- index = 0; +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- for (i = 0; i < HTT_RX_PDEV_MAX_OFDMA_NUM_USER; i++) +- index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, htt_stats_buf->rx_ul_fd_rssi[j][i]); + len += scnprintf(buf + len, buf_len - len, +- "rx_ul_fd_rssi: nss[%u] = %s\n", j, str_buf); ++ "rx_ul_fd_rssi: nss[%u] = ", j); ++ for (i = 0; i < HTT_RX_PDEV_MAX_OFDMA_NUM_USER; i++) ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", ++ i, htt_stats_buf->rx_ul_fd_rssi[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + } + + len += scnprintf(buf + len, buf_len - len, "per_chain_rssi_pkt_type = %#x\n", + htt_stats_buf->per_chain_rssi_pkt_type); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- index = 0; +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- for (i = 0; i < HTT_RX_PDEV_STATS_NUM_BW_COUNTERS; i++) +- index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); + len += scnprintf(buf + len, buf_len - len, +- "rx_per_chain_rssi_in_dbm[%u] = %s\n", j, str_buf); ++ "rx_per_chain_rssi_in_dbm[%u] = ", j); ++ for (i = 0; i < HTT_RX_PDEV_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + } + len += scnprintf(buf + len, buf_len - len, "\n"); + +@@ -3244,16 +2977,6 @@ static inline void htt_print_rx_pdev_rat + buf[len] = 0; + + stats_req->buf_len = len; +- +-fail: +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) +- kfree(rssi_chain[j]); +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) +- kfree(rx_pilot_evm_db[j]); +- +- for (i = 0; i < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; i++) +- kfree(rx_gi[i]); + } + + static inline void htt_print_rx_soc_fw_stats_tlv(const void *tag_buf, +@@ -3310,17 +3033,13 @@ htt_print_rx_soc_fw_refill_ring_empty_tl + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char refill_ring_empty_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(refill_ring_empty_cnt, +- htt_stats_buf->refill_ring_empty_cnt, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n\n", +- refill_ring_empty_cnt); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->refill_ring_empty_cnt, ++ "refill_ring_empty_cnt", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3340,17 +3059,13 @@ htt_print_rx_soc_fw_refill_ring_num_rxdm + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char rxdma_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_RXDMA_MAX_ERR_CODE); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(rxdma_err_cnt, +- htt_stats_buf->rxdma_err, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "rxdma_err = %s\n\n", +- rxdma_err_cnt); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rxdma_err, "rxdma_err", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3369,17 +3084,13 @@ htt_print_rx_soc_fw_refill_ring_num_reo_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char reo_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_REO_MAX_ERR_CODE); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(reo_err_cnt, +- htt_stats_buf->reo_err, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "reo_err = %s\n\n", +- reo_err_cnt); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->reo_err, "reo_err", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3437,17 +3148,13 @@ htt_print_rx_soc_fw_refill_ring_num_refi + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char refill_ring_num_refill[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(refill_ring_num_refill, +- htt_stats_buf->refill_ring_num_refill, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "refill_ring_num_refill = %s\n\n", +- refill_ring_num_refill); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->refill_ring_num_refill, ++ "refill_ring_num_refill", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3464,8 +3171,6 @@ static inline void htt_print_rx_pdev_fw_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw_ring_mgmt_subtype[HTT_MAX_STRING_LEN] = {0}; +- char fw_ring_ctrl_subtype[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +@@ -3487,17 +3192,12 @@ static inline void htt_print_rx_pdev_fw_ + len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u\n", + htt_stats_buf->fw_ring_mpdu_ind); + +- PRINT_ARRAY_TO_BUF(fw_ring_mgmt_subtype, +- htt_stats_buf->fw_ring_mgmt_subtype, +- HTT_STATS_SUBTYPE_MAX); +- len += scnprintf(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s\n", +- fw_ring_mgmt_subtype); +- +- PRINT_ARRAY_TO_BUF(fw_ring_ctrl_subtype, +- htt_stats_buf->fw_ring_ctrl_subtype, +- HTT_STATS_SUBTYPE_MAX); +- len += scnprintf(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s\n", +- fw_ring_ctrl_subtype); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_ring_mgmt_subtype, ++ "fw_ring_mgmt_subtype", HTT_STATS_SUBTYPE_MAX, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_ring_ctrl_subtype, ++ "fw_ring_ctrl_subtype", HTT_STATS_SUBTYPE_MAX, "\n"); ++ + len += scnprintf(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u\n", + htt_stats_buf->fw_ring_mcast_data_msdu); + len += scnprintf(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u\n", +@@ -3588,16 +3288,12 @@ htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw_ring_mpdu_err[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(fw_ring_mpdu_err, +- htt_stats_buf->fw_ring_mpdu_err, +- HTT_RX_STATS_RXDMA_MAX_ERR); +- len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n\n", +- fw_ring_mpdu_err); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_ring_mpdu_err, ++ "fw_ring_mpdu_err", HTT_RX_STATS_RXDMA_MAX_ERR, "\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3616,15 +3312,12 @@ htt_print_rx_pdev_fw_mpdu_drop_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw_mpdu_drop[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_FW_DROP_REASON_MAX); + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(fw_mpdu_drop, +- htt_stats_buf->fw_mpdu_drop, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "fw_mpdu_drop = %s\n\n", fw_mpdu_drop); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_mpdu_drop, "fw_mpdu_drop", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3642,7 +3335,6 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char phy_errs[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id__word = %u\n", +@@ -3650,10 +3342,8 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + len += scnprintf(buf + len, buf_len - len, "total_phy_err_nct = %u\n", + htt_stats_buf->total_phy_err_cnt); + +- PRINT_ARRAY_TO_BUF(phy_errs, +- htt_stats_buf->phy_err, +- HTT_STATS_PHY_ERR_MAX); +- len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->phy_err, "phy_errs", ++ HTT_STATS_PHY_ERR_MAX, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0045-ath11k-Change-masking-and-shifting-in-htt-stats.patch b/package/kernel/mac80211/patches/ath11k/0045-ath11k-Change-masking-and-shifting-in-htt-stats.patch new file mode 100644 index 000000000..6cd198849 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0045-ath11k-Change-masking-and-shifting-in-htt-stats.patch @@ -0,0 +1,683 @@ +From 6ed731829cf862dc1f73bbd063662d8a6c78a5b7 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ath11k: Change masking and shifting in htt stats + +In debugfs_htt_stats.c, masking and shifting is done to get +stats values. Instead use GENMASK and FIELD_GET to improve +code readability and maintenance. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01105-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-5-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 318 ++++++++++-------- + .../wireless/ath/ath11k/debugfs_htt_stats.h | 54 +++ + drivers/net/wireless/ath/ath11k/dp.h | 7 + + 3 files changed, 243 insertions(+), 136 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -75,8 +75,8 @@ static inline void htt_print_tx_pdev_sta + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", + htt_stats_buf->hw_queued); + len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", +@@ -428,8 +428,8 @@ static inline void htt_print_hw_stats_pd + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", + htt_stats_buf->tx_abort); + len += scnprintf(buf + len, buf_len - len, "tx_abort_fail_count = %u\n", +@@ -480,13 +480,15 @@ static inline void htt_print_msdu_flow_s + htt_stats_buf->cur_msdu_count_in_flowq); + len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", + htt_stats_buf->sw_peer_id); +- len += scnprintf(buf + len, buf_len - len, "tx_flow_no = %u\n", +- htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "drop_rule = %u\n", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >> +- 20); ++ len += scnprintf(buf + len, buf_len - len, "tx_flow_no = %lu\n", ++ FIELD_GET(HTT_MSDU_FLOW_STATS_TX_FLOW_NO, ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_MSDU_FLOW_STATS_TID_NUM, ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule)); ++ len += scnprintf(buf + len, buf_len - len, "drop_rule = %lu\n", ++ FIELD_GET(HTT_MSDU_FLOW_STATS_DROP_RULE, ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule)); + len += scnprintf(buf + len, buf_len - len, "last_cycle_enqueue_count = %u\n", + htt_stats_buf->last_cycle_enqueue_count); + len += scnprintf(buf + len, buf_len - len, "last_cycle_dequeue_count = %u\n", +@@ -516,15 +518,18 @@ static inline void htt_print_tx_tid_stat + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); + len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); +- len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_SW_PEER_ID, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_TID_NUM, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_NUM_SCHED_PENDING, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_NUM_PPDU_IN_HWQ, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); + len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", + htt_stats_buf->tid_flags); + len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", +@@ -566,15 +571,18 @@ static inline void htt_print_tx_tid_stat + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); + len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); +- len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_SW_PEER_ID, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_TID_NUM, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_NUM_SCHED_PENDING, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_NUM_PPDU_IN_HWQ, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); + len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", + htt_stats_buf->tid_flags); + len += scnprintf(buf + len, buf_len - len, "max_qdepth_bytes = %u\n", +@@ -618,10 +626,12 @@ static inline void htt_print_rx_tid_stat + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", ++ FIELD_GET(HTT_RX_TID_STATS_SW_PEER_ID, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_RX_TID_STATS_TID_NUM, ++ htt_stats_buf->sw_peer_id__tid_num)); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); + len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); + len += scnprintf(buf + len, buf_len - len, "dup_in_reorder = %u\n", +@@ -724,20 +734,29 @@ static inline void htt_print_peer_detail + htt_stats_buf->peer_type); + len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", + htt_stats_buf->sw_peer_id); +- len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", +- htt_stats_buf->vdev_pdev_ast_idx & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8); +- len += scnprintf(buf + len, buf_len - len, "ast_idx = %u\n", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, +- "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", +- htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF), +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "vdev_id = %lu\n", ++ FIELD_GET(HTT_PEER_DETAILS_VDEV_ID, ++ htt_stats_buf->vdev_pdev_ast_idx)); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %lu\n", ++ FIELD_GET(HTT_PEER_DETAILS_PDEV_ID, ++ htt_stats_buf->vdev_pdev_ast_idx)); ++ len += scnprintf(buf + len, buf_len - len, "ast_idx = %lu\n", ++ FIELD_GET(HTT_PEER_DETAILS_AST_IDX, ++ htt_stats_buf->vdev_pdev_ast_idx)); ++ len += scnprintf(buf + len, buf_len - len, ++ "mac_addr = %02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n", ++ FIELD_GET(HTT_MAC_ADDR_L32_0, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_1, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_2, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_3, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_H16_0, ++ htt_stats_buf->mac_addr.mac_addr_h16), ++ FIELD_GET(HTT_MAC_ADDR_H16_1, ++ htt_stats_buf->mac_addr.mac_addr_h16)); + len += scnprintf(buf + len, buf_len - len, "peer_flags = 0x%x\n", + htt_stats_buf->peer_flags); + len += scnprintf(buf + len, buf_len - len, "qpeer_flags = 0x%x\n\n", +@@ -799,7 +818,6 @@ static inline void htt_print_tx_peer_rat + buf[len] = 0; + + stats_req->buf_len = len; +- + } + + static inline void htt_print_rx_peer_rate_stats_tlv(const void *tag_buf, +@@ -930,10 +948,12 @@ htt_print_tx_hwq_mu_mimo_cmn_stats_tlv(c + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n\n", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_MAC_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %lu\n\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_HWQ_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -953,10 +973,12 @@ htt_print_tx_hwq_stats_cmn_tlv(const voi + + /* TODO: HKDBG */ + len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_MAC_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %lu\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_HWQ_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); + len += scnprintf(buf + len, buf_len - len, "xretry = %u\n", + htt_stats_buf->xretry); + len += scnprintf(buf + len, buf_len - len, "underrun_cnt = %u\n", +@@ -1281,8 +1303,8 @@ htt_print_tx_selfgen_cmn_stats_tlv(const + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n", + htt_stats_buf->su_bar); + len += scnprintf(buf + len, buf_len - len, "rts = %u\n", +@@ -1769,10 +1791,12 @@ htt_print_tx_pdev_stats_sched_per_txq_tl + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__txq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "txq_id = %u\n", +- (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID, ++ htt_stats_buf->mac_id__txq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "txq_id = %lu\n", ++ FIELD_GET(HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID, ++ htt_stats_buf->mac_id__txq_id__word)); + len += scnprintf(buf + len, buf_len - len, "sched_policy = %u\n", + htt_stats_buf->sched_policy); + len += scnprintf(buf + len, buf_len - len, +@@ -1833,8 +1857,8 @@ static inline void htt_print_stats_tx_sc + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "current_timestamp = %u\n\n", + htt_stats_buf->current_timestamp); + +@@ -2011,8 +2035,8 @@ static inline void htt_print_tx_tqm_cmn_ + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "max_cmdq_id = %u\n", + htt_stats_buf->max_cmdq_id); + len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u\n", +@@ -2069,10 +2093,12 @@ static inline void htt_print_tx_tqm_cmdq + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__cmdq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "cmdq_id = %u\n\n", +- (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_TQM_CMDQ_STATUS_MAC_ID, ++ htt_stats_buf->mac_id__cmdq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "cmdq_id = %lu\n\n", ++ FIELD_GET(HTT_TX_TQM_CMDQ_STATUS_CMDQ_ID, ++ htt_stats_buf->mac_id__cmdq_id__word)); + len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", + htt_stats_buf->sync_cmd); + len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", +@@ -2417,8 +2443,8 @@ htt_print_tx_de_cmn_stats_tlv(const void + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "tcl2fw_entry_count = %u\n", + htt_stats_buf->tcl2fw_entry_count); + len += scnprintf(buf + len, buf_len - len, "not_to_fw = %u\n", +@@ -2453,26 +2479,32 @@ static inline void htt_print_ring_if_sta + htt_stats_buf->base_addr); + len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", + htt_stats_buf->elem_size); +- len += scnprintf(buf + len, buf_len - len, "num_elems = %u\n", +- htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "prefetch_tail_idx = %u\n", +- (htt_stats_buf->num_elems__prefetch_tail_idx & +- 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "head_idx = %u\n", +- htt_stats_buf->head_idx__tail_idx & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tail_idx = %u\n", +- (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "shadow_head_idx = %u\n", +- htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "shadow_tail_idx = %u\n", +- (htt_stats_buf->shadow_head_idx__shadow_tail_idx & +- 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_elems = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_NUM_ELEMS, ++ htt_stats_buf->num_elems__prefetch_tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_tail_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_PREFETCH_TAIL_INDEX, ++ htt_stats_buf->num_elems__prefetch_tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "head_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_HEAD_IDX, ++ htt_stats_buf->head_idx__tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "tail_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_TAIL_IDX, ++ htt_stats_buf->head_idx__tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "shadow_head_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_SHADOW_HEAD_IDX, ++ htt_stats_buf->shadow_head_idx__shadow_tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "shadow_tail_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_SHADOW_TAIL_IDX, ++ htt_stats_buf->shadow_head_idx__shadow_tail_idx)); + len += scnprintf(buf + len, buf_len - len, "num_tail_incr = %u\n", + htt_stats_buf->num_tail_incr); +- len += scnprintf(buf + len, buf_len - len, "lwm_thresh = %u\n", +- htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "hwm_thresh = %u\n", +- (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "lwm_thresh = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_LWM_THRESH, ++ htt_stats_buf->lwm_thresh__hwm_thresh)); ++ len += scnprintf(buf + len, buf_len - len, "hwm_thresh = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_HWM_THRESH, ++ htt_stats_buf->lwm_thresh__hwm_thresh)); + len += scnprintf(buf + len, buf_len - len, "overrun_hit_count = %u\n", + htt_stats_buf->overrun_hit_count); + len += scnprintf(buf + len, buf_len - len, "underrun_hit_count = %u\n", +@@ -2504,8 +2536,8 @@ static inline void htt_print_ring_if_cmn + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", + htt_stats_buf->num_records); + +@@ -2581,8 +2613,8 @@ static inline void htt_print_sfm_cmn_tlv + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n", + htt_stats_buf->buf_total); + len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n", +@@ -2609,14 +2641,18 @@ static inline void htt_print_sring_stats + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8); +- len += scnprintf(buf + len, buf_len - len, "arena = %u\n", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "ep = %u\n", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_MAC_ID, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); ++ len += scnprintf(buf + len, buf_len - len, "ring_id = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_RING_ID, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); ++ len += scnprintf(buf + len, buf_len - len, "arena = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_ARENA, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); ++ len += scnprintf(buf + len, buf_len - len, "ep = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_EP, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); + len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n", + htt_stats_buf->base_addr_lsb); + len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n", +@@ -2625,25 +2661,30 @@ static inline void htt_print_sring_stats + htt_stats_buf->ring_size); + len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", + htt_stats_buf->elem_size); +- len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n", +- htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n", +- (htt_stats_buf->num_avail_words__num_valid_words & +- 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n", +- htt_stats_buf->head_ptr__tail_ptr & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n", +- (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n", +- htt_stats_buf->consumer_empty__producer_full & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n", +- (htt_stats_buf->consumer_empty__producer_full & +- 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n", +- htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n", +- (htt_stats_buf->prefetch_count__internal_tail_ptr & +- 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_avail_words = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_NUM_AVAIL_WORDS, ++ htt_stats_buf->num_avail_words__num_valid_words)); ++ len += scnprintf(buf + len, buf_len - len, "num_valid_words = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_NUM_VALID_WORDS, ++ htt_stats_buf->num_avail_words__num_valid_words)); ++ len += scnprintf(buf + len, buf_len - len, "head_ptr = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_HEAD_PTR, ++ htt_stats_buf->head_ptr__tail_ptr)); ++ len += scnprintf(buf + len, buf_len - len, "tail_ptr = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_TAIL_PTR, ++ htt_stats_buf->head_ptr__tail_ptr)); ++ len += scnprintf(buf + len, buf_len - len, "consumer_empty = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_CONSUMER_EMPTY, ++ htt_stats_buf->consumer_empty__producer_full)); ++ len += scnprintf(buf + len, buf_len - len, "producer_full = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_PRODUCER_FULL, ++ htt_stats_buf->consumer_empty__producer_full)); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_count = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_PREFETCH_COUNT, ++ htt_stats_buf->prefetch_count__internal_tail_ptr)); ++ len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %lu\n\n", ++ FIELD_GET(HTT_SRING_STATS_INTERNAL_TAIL_PTR, ++ htt_stats_buf->prefetch_count__internal_tail_ptr)); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2683,8 +2724,8 @@ static inline void htt_print_tx_pdev_rat + u8 j; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", + htt_stats_buf->tx_ldpc); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u\n", +@@ -2809,8 +2850,8 @@ static inline void htt_print_rx_pdev_rat + u8 i, j; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", + htt_stats_buf->nsts); + len += scnprintf(buf + len, buf_len - len, "rx_ldpc = %u\n", +@@ -2844,7 +2885,6 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->pilot_count); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- + len += scnprintf(buf + len, buf_len - len, + "pilot_evm_db[%u] = ", j); + for (i = 0; i < HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS; i++) +@@ -3173,8 +3213,8 @@ static inline void htt_print_rx_pdev_fw_ + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "ppdu_recvd = %u\n", + htt_stats_buf->ppdu_recvd); + len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u\n", +@@ -3422,8 +3462,8 @@ static inline void htt_print_hw_stats_wh + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "last_unpause_ppdu_id = %u\n", + htt_stats_buf->last_unpause_ppdu_id); + len += scnprintf(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u\n", +@@ -3492,13 +3532,19 @@ htt_print_pdev_stats_twt_session_tlv(con + len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", + htt_stats_buf->vdev_id); + len += scnprintf(buf + len, buf_len - len, +- "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x\n", +- htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF), +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8); ++ "peer_mac = %02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n", ++ FIELD_GET(HTT_MAC_ADDR_L32_0, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_1, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_2, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_3, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_H16_0, ++ htt_stats_buf->peer_mac.mac_addr_h16), ++ FIELD_GET(HTT_MAC_ADDR_H16_1, ++ htt_stats_buf->peer_mac.mac_addr_h16)); + len += scnprintf(buf + len, buf_len - len, "flow_id_flags = %u\n", + htt_stats_buf->flow_id_flags); + len += scnprintf(buf + len, buf_len - len, "dialog_id = %u\n", +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +@@ -137,6 +137,8 @@ struct htt_stats_string_tlv { + u32 data[0]; /* Can be variable length */ + } __packed; + ++#define HTT_STATS_MAC_ID GENMASK(7, 0) ++ + /* == TX PDEV STATS == */ + struct htt_tx_pdev_stats_cmn_tlv { + u32 mac_id__word; +@@ -290,6 +292,10 @@ struct htt_hw_stats_whal_tx_tlv { + }; + + /* ============ PEER STATS ============ */ ++#define HTT_MSDU_FLOW_STATS_TX_FLOW_NO GENMASK(15, 0) ++#define HTT_MSDU_FLOW_STATS_TID_NUM GENMASK(19, 16) ++#define HTT_MSDU_FLOW_STATS_DROP_RULE BIT(20) ++ + struct htt_msdu_flow_stats_tlv { + u32 last_update_timestamp; + u32 last_add_timestamp; +@@ -306,6 +312,11 @@ struct htt_msdu_flow_stats_tlv { + + #define MAX_HTT_TID_NAME 8 + ++#define HTT_TX_TID_STATS_SW_PEER_ID GENMASK(15, 0) ++#define HTT_TX_TID_STATS_TID_NUM GENMASK(31, 16) ++#define HTT_TX_TID_STATS_NUM_SCHED_PENDING GENMASK(7, 0) ++#define HTT_TX_TID_STATS_NUM_PPDU_IN_HWQ GENMASK(15, 8) ++ + /* Tidq stats */ + struct htt_tx_tid_stats_tlv { + /* Stored as little endian */ +@@ -326,6 +337,11 @@ struct htt_tx_tid_stats_tlv { + u32 tid_tx_airtime; + }; + ++#define HTT_TX_TID_STATS_V1_SW_PEER_ID GENMASK(15, 0) ++#define HTT_TX_TID_STATS_V1_TID_NUM GENMASK(31, 16) ++#define HTT_TX_TID_STATS_V1_NUM_SCHED_PENDING GENMASK(7, 0) ++#define HTT_TX_TID_STATS_V1_NUM_PPDU_IN_HWQ GENMASK(15, 8) ++ + /* Tidq stats */ + struct htt_tx_tid_stats_v1_tlv { + /* Stored as little endian */ +@@ -348,6 +364,9 @@ struct htt_tx_tid_stats_v1_tlv { + u32 sendn_frms_allowed; + }; + ++#define HTT_RX_TID_STATS_SW_PEER_ID GENMASK(15, 0) ++#define HTT_RX_TID_STATS_TID_NUM GENMASK(31, 16) ++ + struct htt_rx_tid_stats_tlv { + u32 sw_peer_id__tid_num; + u8 tid_name[MAX_HTT_TID_NAME]; +@@ -386,6 +405,10 @@ struct htt_peer_stats_cmn_tlv { + u32 inactive_time; + }; + ++#define HTT_PEER_DETAILS_VDEV_ID GENMASK(7, 0) ++#define HTT_PEER_DETAILS_PDEV_ID GENMASK(15, 8) ++#define HTT_PEER_DETAILS_AST_IDX GENMASK(31, 16) ++ + struct htt_peer_details_tlv { + u32 peer_type; + u32 sw_peer_id; +@@ -510,6 +533,9 @@ struct htt_tx_hwq_mu_mimo_mpdu_stats_tlv + u32 mu_mimo_ampdu_underrun_usr; + }; + ++#define HTT_TX_HWQ_STATS_MAC_ID GENMASK(7, 0) ++#define HTT_TX_HWQ_STATS_HWQ_ID GENMASK(15, 8) ++ + struct htt_tx_hwq_mu_mimo_cmn_stats_tlv { + u32 mac_id__hwq_id__word; + }; +@@ -789,6 +815,9 @@ struct htt_sched_txq_sched_ineligibility + u32 sched_ineligibility[0]; + }; + ++#define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0) ++#define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID GENMASK(15, 8) ++ + struct htt_tx_pdev_stats_sched_per_txq_tlv { + u32 mac_id__txq_id__word; + u32 sched_policy; +@@ -910,6 +939,9 @@ struct htt_tx_tqm_error_stats_tlv { + }; + + /* == TQM CMDQ stats == */ ++#define HTT_TX_TQM_CMDQ_STATUS_MAC_ID GENMASK(7, 0) ++#define HTT_TX_TQM_CMDQ_STATUS_CMDQ_ID GENMASK(15, 8) ++ + struct htt_tx_tqm_cmdq_status_tlv { + u32 mac_id__cmdq_id__word; + u32 sync_cmd; +@@ -1055,6 +1087,15 @@ struct htt_tx_de_cmn_stats_tlv { + #define HTT_STATS_LOW_WM_BINS 5 + #define HTT_STATS_HIGH_WM_BINS 5 + ++#define HTT_RING_IF_STATS_NUM_ELEMS GENMASK(15, 0) ++#define HTT_RING_IF_STATS_PREFETCH_TAIL_INDEX GENMASK(31, 16) ++#define HTT_RING_IF_STATS_HEAD_IDX GENMASK(15, 0) ++#define HTT_RING_IF_STATS_TAIL_IDX GENMASK(31, 16) ++#define HTT_RING_IF_STATS_SHADOW_HEAD_IDX GENMASK(15, 0) ++#define HTT_RING_IF_STATS_SHADOW_TAIL_IDX GENMASK(31, 16) ++#define HTT_RING_IF_STATS_LWM_THRESH GENMASK(15, 0) ++#define HTT_RING_IF_STATS_HWM_THRESH GENMASK(31, 16) ++ + struct htt_ring_if_stats_tlv { + u32 base_addr; /* DWORD aligned base memory address of the ring */ + u32 elem_size; +@@ -1117,6 +1158,19 @@ struct htt_sfm_cmn_tlv { + }; + + /* == SRNG STATS == */ ++#define HTT_SRING_STATS_MAC_ID GENMASK(7, 0) ++#define HTT_SRING_STATS_RING_ID GENMASK(15, 8) ++#define HTT_SRING_STATS_ARENA GENMASK(23, 16) ++#define HTT_SRING_STATS_EP BIT(24) ++#define HTT_SRING_STATS_NUM_AVAIL_WORDS GENMASK(15, 0) ++#define HTT_SRING_STATS_NUM_VALID_WORDS GENMASK(31, 16) ++#define HTT_SRING_STATS_HEAD_PTR GENMASK(15, 0) ++#define HTT_SRING_STATS_TAIL_PTR GENMASK(31, 16) ++#define HTT_SRING_STATS_CONSUMER_EMPTY GENMASK(15, 0) ++#define HTT_SRING_STATS_PRODUCER_FULL GENMASK(31, 16) ++#define HTT_SRING_STATS_PREFETCH_COUNT GENMASK(15, 0) ++#define HTT_SRING_STATS_INTERNAL_TAIL_PTR GENMASK(31, 16) ++ + struct htt_sring_stats_tlv { + u32 mac_id__ring_id__arena__ep; + u32 base_addr_lsb; /* DWORD aligned base memory address of the ring */ +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -1594,6 +1594,13 @@ struct ath11k_htt_extd_stats_msg { + u8 data[0]; + } __packed; + ++#define HTT_MAC_ADDR_L32_0 GENMASK(7, 0) ++#define HTT_MAC_ADDR_L32_1 GENMASK(15, 8) ++#define HTT_MAC_ADDR_L32_2 GENMASK(23, 16) ++#define HTT_MAC_ADDR_L32_3 GENMASK(31, 24) ++#define HTT_MAC_ADDR_H16_0 GENMASK(7, 0) ++#define HTT_MAC_ADDR_H16_1 GENMASK(15, 8) ++ + struct htt_mac_addr { + u32 mac_addr_l32; + u32 mac_addr_h16; diff --git a/package/kernel/mac80211/patches/ath11k/0046-ath11k-add-HTT-stats-support-for-new-stats.patch b/package/kernel/mac80211/patches/ath11k/0046-ath11k-add-HTT-stats-support-for-new-stats.patch new file mode 100644 index 000000000..b5d2d829f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0046-ath11k-add-HTT-stats-support-for-new-stats.patch @@ -0,0 +1,677 @@ +From ac83b6034cfa3bec010c1e01d6e6b44673135afe Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ath11k: add HTT stats support for new stats + +Add HTT stats support for, + +29-ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS: +Used to dump the control path txrx stats for each connected peer. +Usage: +echo 29 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/netdev\:wlan0/stations/ +/htt_peer_stats. + +31-ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF_STATS: +Used to dump the per pdev tx rate txbf stats. +Usage: +echo 31 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats + +32-ATH11k_DBG_HTT_EXT_STATS_TXBF_OFDMA: +Used to dump the TXBF ofdma stats for all ofdma users. +Usage: +echo 32 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats + +37-ATH11K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS: +Used to dump the mac and phy txrx counts and phy stats like per chain rssi +and ANI level. +Usage: +echo 37 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00486-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-6-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/debugfs.h | 4 + + .../wireless/ath/ath11k/debugfs_htt_stats.c | 368 +++++++++++++++++- + .../wireless/ath/ath11k/debugfs_htt_stats.h | 172 ++++++++ + drivers/net/wireless/ath/ath11k/debugfs_sta.c | 8 +- + 4 files changed, 548 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -38,6 +38,10 @@ enum ath11k_dbg_htt_ext_stats_type { + ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO = 22, + ATH11K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23, + ATH11K_DBG_HTT_EXT_STATS_RING_BACKPRESSURE_STATS = 24, ++ ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS = 29, ++ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF_STATS = 31, ++ ATH11K_DBG_HTT_EXT_STATS_TXBF_OFDMA = 32, ++ ATH11K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37, + + /* keep this last */ + ATH11K_DBG_HTT_NUM_EXT_STATS, +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -3639,6 +3639,334 @@ static inline void htt_print_backpressur + } + } + ++static inline ++void htt_print_pdev_tx_rate_txbf_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_pdev_txrate_txbf_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_STATS_PDEV_TX_RATE_TXBF_STATS:\n"); ++ ++ len += scnprintf(buf + len, buf_len - len, "tx_ol_mcs = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ol_mcs[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ibf_mcs = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ibf_mcs[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_txbf_mcs ="); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_txbf_mcs[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ol_nss = "); ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ol_nss[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ibf_nss = "); ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ibf_nss[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_txbf_nss = "); ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_txbf_nss[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ol_bw = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ol_bw[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ibf_bw = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ibf_bw[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_txbf_bw = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_txbf_bw[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_ndpa_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_ndpa_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_NDPA_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_queued_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_queued[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_tried_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_tried[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_flushed_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_flushed[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_err_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_err[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_ndp_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_ndp_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_NDP_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_queued_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_queued[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_tried_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_tried[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_flushed_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_flushed[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_err_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_err[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_brp_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_brp_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_BRP_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brpoll_queued_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brpoll_queued[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brpoll_tried_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brpoll_tried[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brpoll_flushed_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brpoll_flushed[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brp_err_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brp_err[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brp_err_num_cbf_rcvd_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brp_err_num_cbf_rcvd[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_steer_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_steer_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_STEER_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_ppdu_steer_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_ppdu_steer[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_ppdu_ol_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_ppdu_ol[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_usrs_prefetch_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_usrs_prefetch[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_usrs_sound_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_usrs_sound[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_usrs_force_sound_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_usrs_force_sound[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_phy_counters_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_phy_counters_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, "HTT_PHY_COUNTERS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "rx_ofdma_timing_err_cnt = %u\n", ++ htt_stats_buf->rx_ofdma_timing_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_cck_fail_cnt = %u\n", ++ htt_stats_buf->rx_cck_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mactx_abort_cnt = %u\n", ++ htt_stats_buf->mactx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "macrx_abort_cnt = %u\n", ++ htt_stats_buf->macrx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "phytx_abort_cnt = %u\n", ++ htt_stats_buf->phytx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "phyrx_abort_cnt = %u\n", ++ htt_stats_buf->phyrx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "phyrx_defer_abort_cnt = %u\n", ++ htt_stats_buf->phyrx_defer_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_gain_adj_lstf_event_cnt = %u\n", ++ htt_stats_buf->rx_gain_adj_lstf_event_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_gain_adj_non_legacy_cnt = %u\n", ++ htt_stats_buf->rx_gain_adj_non_legacy_cnt); ++ ++ for (i = 0; i < HTT_MAX_RX_PKT_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, "rx_pkt_cnt[%d] = %u\n", ++ i, htt_stats_buf->rx_pkt_cnt[i]); ++ ++ for (i = 0; i < HTT_MAX_RX_PKT_CRC_PASS_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_pkt_crc_pass_cnt[%d] = %u\n", ++ i, htt_stats_buf->rx_pkt_crc_pass_cnt[i]); ++ ++ for (i = 0; i < HTT_MAX_PER_BLK_ERR_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "per_blk_err_cnt[%d] = %u\n", ++ i, htt_stats_buf->per_blk_err_cnt[i]); ++ ++ for (i = 0; i < HTT_MAX_RX_OTA_ERR_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_ota_err_cnt[%d] = %u\n", ++ i, htt_stats_buf->rx_ota_err_cnt[i]); ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_phy_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_phy_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, "HTT_PHY_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_STATS_MAX_CHAINS; i++) ++ len += scnprintf(buf + len, buf_len - len, "nf_chain[%d] = %d\n", ++ i, htt_stats_buf->nf_chain[i]); ++ ++ len += scnprintf(buf + len, buf_len - len, "false_radar_cnt = %u\n", ++ htt_stats_buf->false_radar_cnt); ++ len += scnprintf(buf + len, buf_len - len, "radar_cs_cnt = %u\n", ++ htt_stats_buf->radar_cs_cnt); ++ len += scnprintf(buf + len, buf_len - len, "ani_level = %d\n", ++ htt_stats_buf->ani_level); ++ len += scnprintf(buf + len, buf_len - len, "fw_run_time = %u\n", ++ htt_stats_buf->fw_run_time); ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_peer_ctrl_path_txrx_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_peer_ctrl_path_txrx_stats_tlv *htt_stat_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ const char *mgmt_frm_type[ATH11K_STATS_MGMT_FRM_TYPE_MAX - 1] = { ++ "assoc_req", "assoc_resp", ++ "reassoc_req", "reassoc_resp", ++ "probe_req", "probe_resp", ++ "timing_advertisement", "reserved", ++ "beacon", "atim", "disassoc", ++ "auth", "deauth", "action", "action_no_ack"}; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "peer_mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ htt_stat_buf->peer_mac_addr[0], htt_stat_buf->peer_mac_addr[1], ++ htt_stat_buf->peer_mac_addr[2], htt_stat_buf->peer_mac_addr[3], ++ htt_stat_buf->peer_mac_addr[4], htt_stat_buf->peer_mac_addr[5]); ++ ++ len += scnprintf(buf + len, buf_len - len, "peer_tx_mgmt_subtype:\n"); ++ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX - 1; i++) ++ len += scnprintf(buf + len, buf_len - len, "%s:%u\n", ++ mgmt_frm_type[i], ++ htt_stat_buf->peer_rx_mgmt_subtype[i]); ++ ++ len += scnprintf(buf + len, buf_len - len, "peer_rx_mgmt_subtype:\n"); ++ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX - 1; i++) ++ len += scnprintf(buf + len, buf_len - len, "%s:%u\n", ++ mgmt_frm_type[i], ++ htt_stat_buf->peer_rx_mgmt_subtype[i]); ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ ++ stats_req->buf_len = len; ++} ++ + static int ath11k_dbg_htt_ext_stats_parse(struct ath11k_base *ab, + u16 tag, u16 len, const void *tag_buf, + void *user_data) +@@ -3990,6 +4318,30 @@ static int ath11k_dbg_htt_ext_stats_pars + case HTT_STATS_RING_BACKPRESSURE_STATS_TAG: + htt_print_backpressure_stats_tlv_v(tag_buf, user_data); + break; ++ case HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG: ++ htt_print_pdev_tx_rate_txbf_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_NDPA_STATS_TAG: ++ htt_print_txbf_ofdma_ndpa_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_NDP_STATS_TAG: ++ htt_print_txbf_ofdma_ndp_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_BRP_STATS_TAG: ++ htt_print_txbf_ofdma_brp_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_STEER_STATS_TAG: ++ htt_print_txbf_ofdma_steer_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_PHY_COUNTERS_TAG: ++ htt_print_phy_counters_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_PHY_STATS_TAG: ++ htt_print_phy_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG: ++ htt_print_peer_ctrl_path_txrx_stats_tlv(tag_buf, stats_req); ++ break; + default: + break; + } +@@ -4077,8 +4429,7 @@ static ssize_t ath11k_write_htt_stats_ty + if (type >= ATH11K_DBG_HTT_NUM_EXT_STATS) + return -E2BIG; + +- if (type == ATH11K_DBG_HTT_EXT_STATS_RESET || +- type == ATH11K_DBG_HTT_EXT_STATS_PEER_INFO) ++ if (type == ATH11K_DBG_HTT_EXT_STATS_RESET) + return -EPERM; + + ar->debug.htt_stats.type = type; +@@ -4139,6 +4490,15 @@ static int ath11k_prep_htt_stats_cfg_par + case ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO: + cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ACTIVE_VDEVS; + break; ++ case ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS: ++ cfg_params->cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR; ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(7, 0), mac_addr[0]); ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(15, 8), mac_addr[1]); ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(23, 16), mac_addr[2]); ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(31, 24), mac_addr[3]); ++ cfg_params->cfg2 |= FIELD_PREP(GENMASK(7, 0), mac_addr[4]); ++ cfg_params->cfg2 |= FIELD_PREP(GENMASK(15, 8), mac_addr[5]); ++ break; + default: + break; + } +@@ -4196,7 +4556,9 @@ static int ath11k_open_htt_stats(struct + u8 type = ar->debug.htt_stats.type; + int ret; + +- if (type == ATH11K_DBG_HTT_EXT_STATS_RESET) ++ if (type == ATH11K_DBG_HTT_EXT_STATS_RESET || ++ type == ATH11K_DBG_HTT_EXT_STATS_PEER_INFO || ++ type == ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) + return -EPERM; + + mutex_lock(&ar->conf_mutex); +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +@@ -102,6 +102,14 @@ enum htt_tlv_tag_t { + HTT_STATS_PDEV_OBSS_PD_TAG = 88, + HTT_STATS_HW_WAR_TAG = 89, + HTT_STATS_RING_BACKPRESSURE_STATS_TAG = 90, ++ HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG = 101, ++ HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG = 108, ++ HTT_STATS_TXBF_OFDMA_NDPA_STATS_TAG = 113, ++ HTT_STATS_TXBF_OFDMA_NDP_STATS_TAG = 114, ++ HTT_STATS_TXBF_OFDMA_BRP_STATS_TAG = 115, ++ HTT_STATS_TXBF_OFDMA_STEER_STATS_TAG = 116, ++ HTT_STATS_PHY_COUNTERS_TAG = 121, ++ HTT_STATS_PHY_STATS_TAG = 122, + + HTT_STATS_MAX_TAG, + }; +@@ -1750,6 +1758,170 @@ struct htt_ring_backpressure_stats_tlv { + u32 backpressure_hist[5]; + }; + ++#define HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS 14 ++#define HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS 5 ++#define HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8 ++ ++struct htt_pdev_txrate_txbf_stats_tlv { ++ /* SU TxBF TX MCS stats */ ++ u32 tx_su_txbf_mcs[HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS]; ++ /* Implicit BF TX MCS stats */ ++ u32 tx_su_ibf_mcs[HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS]; ++ /* Open loop TX MCS stats */ ++ u32 tx_su_ol_mcs[HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS]; ++ /* SU TxBF TX NSS stats */ ++ u32 tx_su_txbf_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; ++ /* Implicit BF TX NSS stats */ ++ u32 tx_su_ibf_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; ++ /* Open loop TX NSS stats */ ++ u32 tx_su_ol_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; ++ /* SU TxBF TX BW stats */ ++ u32 tx_su_txbf_bw[HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS]; ++ /* Implicit BF TX BW stats */ ++ u32 tx_su_ibf_bw[HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS]; ++ /* Open loop TX BW stats */ ++ u32 tx_su_ol_bw[HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS]; ++}; ++ ++struct htt_txbf_ofdma_ndpa_stats_tlv { ++ /* 11AX HE OFDMA NDPA frame queued to the HW */ ++ u32 ax_ofdma_ndpa_queued[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame sent over the air */ ++ u32 ax_ofdma_ndpa_tried[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame flushed by HW */ ++ u32 ax_ofdma_ndpa_flushed[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame completed with error(s) */ ++ u32 ax_ofdma_ndpa_err[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++}; ++ ++struct htt_txbf_ofdma_ndp_stats_tlv { ++ /* 11AX HE OFDMA NDP frame queued to the HW */ ++ u32 ax_ofdma_ndp_queued[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame sent over the air */ ++ u32 ax_ofdma_ndp_tried[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame flushed by HW */ ++ u32 ax_ofdma_ndp_flushed[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame completed with error(s) */ ++ u32 ax_ofdma_ndp_err[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++}; ++ ++struct htt_txbf_ofdma_brp_stats_tlv { ++ /* 11AX HE OFDMA MU BRPOLL frame queued to the HW */ ++ u32 ax_ofdma_brpoll_queued[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA MU BRPOLL frame sent over the air */ ++ u32 ax_ofdma_brpoll_tried[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA MU BRPOLL frame flushed by HW */ ++ u32 ax_ofdma_brpoll_flushed[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA MU BRPOLL frame completed with error(s) */ ++ u32 ax_ofdma_brp_err[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* Number of CBF(s) received when 11AX HE OFDMA MU BRPOLL frame ++ * completed with error(s). ++ */ ++ u32 ax_ofdma_brp_err_num_cbf_rcvd[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS + 1]; ++}; ++ ++struct htt_txbf_ofdma_steer_stats_tlv { ++ /* 11AX HE OFDMA PPDUs that were sent over the air with steering (TXBF + OFDMA) */ ++ u32 ax_ofdma_num_ppdu_steer[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA PPDUs that were sent over the air in open loop */ ++ u32 ax_ofdma_num_ppdu_ol[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA number of users for which CBF prefetch was ++ * initiated to PHY HW during TX. ++ */ ++ u32 ax_ofdma_num_usrs_prefetch[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA number of users for which sounding was initiated during TX */ ++ u32 ax_ofdma_num_usrs_sound[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA number of users for which sounding was forced during TX */ ++ u32 ax_ofdma_num_usrs_force_sound[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++}; ++ ++#define HTT_MAX_RX_PKT_CNT 8 ++#define HTT_MAX_RX_PKT_CRC_PASS_CNT 8 ++#define HTT_MAX_PER_BLK_ERR_CNT 20 ++#define HTT_MAX_RX_OTA_ERR_CNT 14 ++#define HTT_STATS_MAX_CHAINS 8 ++#define ATH11K_STATS_MGMT_FRM_TYPE_MAX 16 ++ ++struct htt_phy_counters_tlv { ++ /* number of RXTD OFDMA OTA error counts except power surge and drop */ ++ u32 rx_ofdma_timing_err_cnt; ++ /* rx_cck_fail_cnt: ++ * number of cck error counts due to rx reception failure because of ++ * timing error in cck ++ */ ++ u32 rx_cck_fail_cnt; ++ /* number of times tx abort initiated by mac */ ++ u32 mactx_abort_cnt; ++ /* number of times rx abort initiated by mac */ ++ u32 macrx_abort_cnt; ++ /* number of times tx abort initiated by phy */ ++ u32 phytx_abort_cnt; ++ /* number of times rx abort initiated by phy */ ++ u32 phyrx_abort_cnt; ++ /* number of rx defered count initiated by phy */ ++ u32 phyrx_defer_abort_cnt; ++ /* number of sizing events generated at LSTF */ ++ u32 rx_gain_adj_lstf_event_cnt; ++ /* number of sizing events generated at non-legacy LTF */ ++ u32 rx_gain_adj_non_legacy_cnt; ++ /* rx_pkt_cnt - ++ * Received EOP (end-of-packet) count per packet type; ++ * [0] = 11a; [1] = 11b; [2] = 11n; [3] = 11ac; [4] = 11ax; [5] = GF ++ * [6-7]=RSVD ++ */ ++ u32 rx_pkt_cnt[HTT_MAX_RX_PKT_CNT]; ++ /* rx_pkt_crc_pass_cnt - ++ * Received EOP (end-of-packet) count per packet type; ++ * [0] = 11a; [1] = 11b; [2] = 11n; [3] = 11ac; [4] = 11ax; [5] = GF ++ * [6-7]=RSVD ++ */ ++ u32 rx_pkt_crc_pass_cnt[HTT_MAX_RX_PKT_CRC_PASS_CNT]; ++ /* per_blk_err_cnt - ++ * Error count per error source; ++ * [0] = unknown; [1] = LSIG; [2] = HTSIG; [3] = VHTSIG; [4] = HESIG; ++ * [5] = RXTD_OTA; [6] = RXTD_FATAL; [7] = DEMF; [8] = ROBE; ++ * [9] = PMI; [10] = TXFD; [11] = TXTD; [12] = PHYRF ++ * [13-19]=RSVD ++ */ ++ u32 per_blk_err_cnt[HTT_MAX_PER_BLK_ERR_CNT]; ++ /* rx_ota_err_cnt - ++ * RXTD OTA (over-the-air) error count per error reason; ++ * [0] = voting fail; [1] = weak det fail; [2] = strong sig fail; ++ * [3] = cck fail; [4] = power surge; [5] = power drop; ++ * [6] = btcf timing timeout error; [7] = btcf packet detect error; ++ * [8] = coarse timing timeout error ++ * [9-13]=RSVD ++ */ ++ u32 rx_ota_err_cnt[HTT_MAX_RX_OTA_ERR_CNT]; ++}; ++ ++struct htt_phy_stats_tlv { ++ /* per chain hw noise floor values in dBm */ ++ s32 nf_chain[HTT_STATS_MAX_CHAINS]; ++ /* number of false radars detected */ ++ u32 false_radar_cnt; ++ /* number of channel switches happened due to radar detection */ ++ u32 radar_cs_cnt; ++ /* ani_level - ++ * ANI level (noise interference) corresponds to the channel ++ * the desense levels range from -5 to 15 in dB units, ++ * higher values indicating more noise interference. ++ */ ++ s32 ani_level; ++ /* running time in minutes since FW boot */ ++ u32 fw_run_time; ++}; ++ ++struct htt_peer_ctrl_path_txrx_stats_tlv { ++ /* peer mac address */ ++ u8 peer_mac_addr[ETH_ALEN]; ++ u8 rsvd[2]; ++ /* Num of tx mgmt frames with subtype on peer level */ ++ u32 peer_tx_mgmt_subtype[ATH11K_STATS_MGMT_FRM_TYPE_MAX]; ++ /* Num of rx mgmt frames with subtype on peer level */ ++ u32 peer_rx_mgmt_subtype[ATH11K_STATS_MGMT_FRM_TYPE_MAX]; ++}; ++ + #ifdef CPTCFG_ATH11K_DEBUGFS + + void ath11k_debugfs_htt_stats_init(struct ath11k *ar); +--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c +@@ -419,15 +419,21 @@ ath11k_dbg_sta_open_htt_peer_stats(struc + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; + struct ath11k *ar = arsta->arvif->ar; + struct debug_htt_stats_req *stats_req; ++ int type = ar->debug.htt_stats.type; + int ret; + ++ if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO && ++ type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) || ++ type == ATH11K_DBG_HTT_EXT_STATS_RESET) ++ return -EPERM; ++ + stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE); + if (!stats_req) + return -ENOMEM; + + mutex_lock(&ar->conf_mutex); + ar->debug.htt_stats.stats_req = stats_req; +- stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO; ++ stats_req->type = type; + memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN); + ret = ath11k_debugfs_htt_stats_req(ar); + mutex_unlock(&ar->conf_mutex); diff --git a/package/kernel/mac80211/patches/ath11k/0048-ath11k-indicate-scan-complete-for-scan-canceled-when.patch b/package/kernel/mac80211/patches/ath11k/0048-ath11k-indicate-scan-complete-for-scan-canceled-when.patch new file mode 100644 index 000000000..b68a200bc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0048-ath11k-indicate-scan-complete-for-scan-canceled-when.patch @@ -0,0 +1,76 @@ +From c677d4b1bcc4f7330043d8f039f494557d720ed4 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ath11k: indicate scan complete for scan canceled when scan + running + +ath11k prints "Received scan event for unknown vdev" when doing the +following test: +1. trigger scan +2. wait 0.2 second +3. iw reg set or 11d scan complete from firmware + +Reason: When iw reg set or 11d scan complete, the new country code will +be set to the firmware, and the new regdomain info indicated to ath11k, +then the new channel list will be sent to the firmware. The firmware +will cancel the current scan after receiving WMI_SCAN_CHAN_LIST_CMDID +which is used for the new channel list, and the state of ath11k is +ATH11K_SCAN_RUNNING, then ath11k_get_ar_on_scan_abort() returns NULL and +ath11k_scan_event() returns at this point and does not indicate scan +completion to mac80211. + +Indicate scan completion to mac80211 and get rid of the "Received scan +event for unknown vdev" print for the above case. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914164226.38843-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -6290,8 +6290,9 @@ exit: + rcu_read_unlock(); + } + +-static struct ath11k *ath11k_get_ar_on_scan_abort(struct ath11k_base *ab, +- u32 vdev_id) ++static struct ath11k *ath11k_get_ar_on_scan_state(struct ath11k_base *ab, ++ u32 vdev_id, ++ enum ath11k_scan_state state) + { + int i; + struct ath11k_pdev *pdev; +@@ -6303,7 +6304,7 @@ static struct ath11k *ath11k_get_ar_on_s + ar = pdev->ar; + + spin_lock_bh(&ar->data_lock); +- if (ar->scan.state == ATH11K_SCAN_ABORTING && ++ if (ar->scan.state == state && + ar->scan.vdev_id == vdev_id) { + spin_unlock_bh(&ar->data_lock); + return ar; +@@ -6333,10 +6334,15 @@ static void ath11k_scan_event(struct ath + * aborting scan's vdev id matches this event info. + */ + if (scan_ev.event_type == WMI_SCAN_EVENT_COMPLETED && +- scan_ev.reason == WMI_SCAN_REASON_CANCELLED) +- ar = ath11k_get_ar_on_scan_abort(ab, scan_ev.vdev_id); +- else ++ scan_ev.reason == WMI_SCAN_REASON_CANCELLED) { ++ ar = ath11k_get_ar_on_scan_state(ab, scan_ev.vdev_id, ++ ATH11K_SCAN_ABORTING); ++ if (!ar) ++ ar = ath11k_get_ar_on_scan_state(ab, scan_ev.vdev_id, ++ ATH11K_SCAN_RUNNING); ++ } else { + ar = ath11k_mac_get_ar_by_vdev_id(ab, scan_ev.vdev_id); ++ } + + if (!ar) { + ath11k_warn(ab, "Received scan event for unknown vdev"); diff --git a/package/kernel/mac80211/patches/ath11k/0049-ath11k-indicate-to-mac80211-scan-complete-with-abort.patch b/package/kernel/mac80211/patches/ath11k/0049-ath11k-indicate-to-mac80211-scan-complete-with-abort.patch new file mode 100644 index 000000000..6b0ad11e9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0049-ath11k-indicate-to-mac80211-scan-complete-with-abort.patch @@ -0,0 +1,71 @@ +From 62db14ea95b1017c53ebb8f724119ea4d90ecc07 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ath11k: indicate to mac80211 scan complete with aborted flag + for ATH11K_SCAN_STARTING state + +Scan failure can not be recovered from when running a loop of the +following steps: +1. run scan: "iw wlan scan". +2. run command: echo assert > /sys/kernel/debug/ath11k/qca6490\ hw2.0/simulate_fw_crash + immediately after step 1. + +result: +scan failed and can not recover even when wlan recovery succeeds: +command failed: Device or resource busy (-16) + +reason: +When scan arrives, WMI_START_SCAN_CMDID is sent to the firmware and +function ath11k_mac_op_hw_scan() returns, then simulate_fw_crash arrives +and the scan started event does not arrive, and then it starts to do +recovery of wlan. __ath11k_mac_scan_finish() which is called from +ath11k_core_halt() is one step of recovery, it will not call +ieee80211_scan_completed() by logic currently because the scan state is +ATH11K_SCAN_STARTING. Thus it leads the scan not being completed in +mac80211, and leads all consecutive scans failing with -EBUSY in +nl80211_trigger_scan even after wlan recovery success. + +Indicate scan complete with aborted flag to mac80211 for +ATH11K_SCAN_STARTING to allow recovery from scan failed with "Device or +resource busy (-16)" after wlan recovery. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914164226.38843-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2987,18 +2987,21 @@ void __ath11k_mac_scan_finish(struct ath + break; + case ATH11K_SCAN_RUNNING: + case ATH11K_SCAN_ABORTING: ++ if (ar->scan.is_roc && ar->scan.roc_notify) ++ ieee80211_remain_on_channel_expired(ar->hw); ++ fallthrough; ++ case ATH11K_SCAN_STARTING: + if (!ar->scan.is_roc) { + struct cfg80211_scan_info info = { +- .aborted = (ar->scan.state == +- ATH11K_SCAN_ABORTING), ++ .aborted = ((ar->scan.state == ++ ATH11K_SCAN_ABORTING) || ++ (ar->scan.state == ++ ATH11K_SCAN_STARTING)), + }; + + ieee80211_scan_completed(ar->hw, &info); +- } else if (ar->scan.roc_notify) { +- ieee80211_remain_on_channel_expired(ar->hw); + } +- fallthrough; +- case ATH11K_SCAN_STARTING: ++ + ar->scan.state = ATH11K_SCAN_IDLE; + ar->scan_channel = NULL; + ar->scan.roc_freq = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0050-ath11k-add-6-GHz-params-in-peer-assoc-command.patch b/package/kernel/mac80211/patches/ath11k/0050-ath11k-add-6-GHz-params-in-peer-assoc-command.patch new file mode 100644 index 000000000..4339ffb70 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0050-ath11k-add-6-GHz-params-in-peer-assoc-command.patch @@ -0,0 +1,94 @@ +From c3a7d7eb4c9853bb457b792cef42ddd4a029a914 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:46 +0300 +Subject: [PATCH] ath11k: add 6 GHz params in peer assoc command + +Currently A-MPDU aggregation parameters are not being configured +during peer association for 6 GHz band. Hence, extract these +parameters from station's capabilities received in association +request and send to firmware. Without this, A-MPDU aggregation +is not happening in 6 GHz band. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913175510.193005-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 50 ++++++++++++++++++++++++++- + 1 file changed, 49 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2021,6 +2021,53 @@ static void ath11k_peer_assoc_h_he(struc + arg->peer_bw_rxnss_override); + } + ++static void ath11k_peer_assoc_h_he_6ghz(struct ath11k *ar, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct peer_assoc_params *arg) ++{ ++ const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; ++ struct cfg80211_chan_def def; ++ enum nl80211_band band; ++ u8 ampdu_factor; ++ ++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) ++ return; ++ ++ band = def.chan->band; ++ ++ if (!arg->he_flag || band != NL80211_BAND_6GHZ || !sta->he_6ghz_capa.capa) ++ return; ++ ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_80) ++ arg->bw_80 = true; ++ ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_160) ++ arg->bw_160 = true; ++ ++ arg->peer_he_caps_6ghz = le16_to_cpu(sta->he_6ghz_capa.capa); ++ arg->peer_mpdu_density = ++ ath11k_parse_mpdudensity(FIELD_GET(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START, ++ arg->peer_he_caps_6ghz)); ++ ++ /* From IEEE Std 802.11ax-2021 - Section 10.12.2: An HE STA shall be capable of ++ * receiving A-MPDU where the A-MPDU pre-EOF padding length is up to the value ++ * indicated by the Maximum A-MPDU Length Exponent Extension field in the HE ++ * Capabilities element and the Maximum A-MPDU Length Exponent field in HE 6 GHz ++ * Band Capabilities element in the 6 GHz band. ++ * ++ * Here, we are extracting the Max A-MPDU Exponent Extension from HE caps and ++ * factor is the Maximum A-MPDU Length Exponent from HE 6 GHZ Band capability. ++ */ ++ ampdu_factor = FIELD_GET(IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK, ++ he_cap->he_cap_elem.mac_cap_info[3]) + ++ FIELD_GET(IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP, ++ arg->peer_he_caps_6ghz); ++ ++ arg->peer_max_mpdu = (1u << (IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR + ++ ampdu_factor)) - 1; ++} ++ + static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, + struct peer_assoc_params *arg) + { +@@ -2310,6 +2357,7 @@ static void ath11k_peer_assoc_prepare(st + ath11k_peer_assoc_h_ht(ar, vif, sta, arg); + ath11k_peer_assoc_h_vht(ar, vif, sta, arg); + ath11k_peer_assoc_h_he(ar, vif, sta, arg); ++ ath11k_peer_assoc_h_he_6ghz(ar, vif, sta, arg); + ath11k_peer_assoc_h_qos(ar, vif, sta, arg); + ath11k_peer_assoc_h_smps(sta, arg); + +@@ -7608,7 +7656,7 @@ static int __ath11k_mac_register(struct + if (cap->nss_ratio_enabled) + ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW); + +- if (ht_cap & WMI_HT_CAP_ENABLED) { ++ if ((ht_cap & WMI_HT_CAP_ENABLED) || ar->supports_6ghz) { + ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER); diff --git a/package/kernel/mac80211/patches/ath11k/0051-ath11k-support-SMPS-configuration-for-6-GHz.patch b/package/kernel/mac80211/patches/ath11k/0051-ath11k-support-SMPS-configuration-for-6-GHz.patch new file mode 100644 index 000000000..518277876 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0051-ath11k-support-SMPS-configuration-for-6-GHz.patch @@ -0,0 +1,93 @@ +From 6f4d70308e5eb63c99702e93f7c0d8e55f360da2 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:46 +0300 +Subject: [PATCH] ath11k: support SMPS configuration for 6 GHz + +Parse SMPS configuration from IEs and configure. Without this, +SMPS is not enabled for 6 GHz band. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913175510.193005-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 31 ++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2074,11 +2074,16 @@ static void ath11k_peer_assoc_h_smps(str + const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + int smps; + +- if (!ht_cap->ht_supported) ++ if (!ht_cap->ht_supported && !sta->he_6ghz_capa.capa) + return; + +- smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; +- smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ if (ht_cap->ht_supported) { ++ smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; ++ smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ } else { ++ smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, ++ le16_to_cpu(sta->he_6ghz_capa.capa)); ++ } + + switch (smps) { + case WLAN_HT_CAP_SM_PS_STATIC: +@@ -2366,15 +2371,20 @@ static void ath11k_peer_assoc_prepare(st + + static int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif, + const u8 *addr, +- const struct ieee80211_sta_ht_cap *ht_cap) ++ const struct ieee80211_sta_ht_cap *ht_cap, ++ u16 he_6ghz_capa) + { + int smps; + +- if (!ht_cap->ht_supported) ++ if (!ht_cap->ht_supported && !he_6ghz_capa) + return 0; + +- smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; +- smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ if (ht_cap->ht_supported) { ++ smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; ++ smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ } else { ++ smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, he_6ghz_capa); ++ } + + if (smps >= ARRAY_SIZE(ath11k_smps_map)) + return -EINVAL; +@@ -2427,7 +2437,8 @@ static void ath11k_bss_assoc(struct ieee + } + + ret = ath11k_setup_peer_smps(ar, arvif, bss_conf->bssid, +- &ap_sta->ht_cap); ++ &ap_sta->ht_cap, ++ le16_to_cpu(ap_sta->he_6ghz_capa.capa)); + if (ret) { + ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -3720,7 +3731,7 @@ static int ath11k_station_assoc(struct a + return 0; + + ret = ath11k_setup_peer_smps(ar, arvif, sta->addr, +- &sta->ht_cap); ++ &sta->ht_cap, le16_to_cpu(sta->he_6ghz_capa.capa)); + if (ret) { + ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -7671,7 +7682,7 @@ static int __ath11k_mac_register(struct + * for each band for a dual band capable radio. It will be tricky to + * handle it when the ht capability different for each band. + */ +- if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) ++ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz) + ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + + ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; diff --git a/package/kernel/mac80211/patches/ath11k/0053-ath11k-Remove-unused-variable-in-ath11k_dp_rx_mon_me.patch b/package/kernel/mac80211/patches/ath11k/0053-ath11k-Remove-unused-variable-in-ath11k_dp_rx_mon_me.patch new file mode 100644 index 000000000..d6a2632e3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0053-ath11k-Remove-unused-variable-in-ath11k_dp_rx_mon_me.patch @@ -0,0 +1,70 @@ +From 7210b4b77fe47697890d2d3b2ce57ac9f767bffc Mon Sep 17 00:00:00 2001 +From: Tim Gardner +Date: Tue, 5 Oct 2021 16:55:54 +0300 +Subject: [PATCH] ath11k: Remove unused variable in + ath11k_dp_rx_mon_merg_msdus() + +Coverity complains that a constant variable guards dead code. In fact, +mpdu_buf is set NULL and never updated. + +4834err_merge_fail: + null: At condition mpdu_buf, the value of mpdu_buf must be NULL. + dead_error_condition: The condition mpdu_buf cannot be true. +CID 92162 (#1 of 1): 'Constant' variable guards dead code (DEADCODE) +dead_error_line: Execution cannot reach the expression decap_format != + DP_RX_DECAP_TYPE_RAW inside this statement: if (mpdu_buf && decap_forma.... +Local variable mpdu_buf is assigned only once, to a constant value, making it + effectively constant throughout its scope. If this is not the intent, examine + the logic to see if there is a missing assignment that would make mpdu_buf not + remain constant. +4835 if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) { + +Fix this by removing mpdu_buf and unreachable code. + +Cc: Kalle Valo +Cc: "David S. Miller" +Cc: Jakub Kicinski +Cc: ath11k@lists.infradead.org +Cc: linux-wireless@vger.kernel.org +Cc: netdev@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Tim Gardner +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210927150743.19816-1-tim.gardner@canonical.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4828,7 +4828,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + struct ieee80211_rx_status *rxs) + { + struct ath11k_base *ab = ar->ab; +- struct sk_buff *msdu, *mpdu_buf, *prev_buf; ++ struct sk_buff *msdu, *prev_buf; + u32 wifi_hdr_len; + struct hal_rx_desc *rx_desc; + char *hdr_desc; +@@ -4836,8 +4836,6 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + struct ieee80211_hdr_3addr *wh; + struct rx_attention *rx_attention; + +- mpdu_buf = NULL; +- + if (!head_msdu) + goto err_merge_fail; + +@@ -4920,12 +4918,6 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + return head_msdu; + + err_merge_fail: +- if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) { +- ath11k_dbg(ab, ATH11K_DBG_DATA, +- "err_merge_fail mpdu_buf %pK", mpdu_buf); +- /* Free the head buffer */ +- dev_kfree_skb_any(mpdu_buf); +- } + return NULL; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0054-ath11k-Fix-spelling-mistake-incompaitiblity-incompat.patch b/package/kernel/mac80211/patches/ath11k/0054-ath11k-Fix-spelling-mistake-incompaitiblity-incompat.patch new file mode 100644 index 000000000..224e92119 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0054-ath11k-Fix-spelling-mistake-incompaitiblity-incompat.patch @@ -0,0 +1,26 @@ +From 567ec33a76c7d8e7fbd7a73c81dd16b9efc7ae6d Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Wed, 6 Oct 2021 09:32:17 +0100 +Subject: [PATCH] ath11k: Fix spelling mistake "incompaitiblity" -> + "incompatibility" + +There is a spelling mistake in an ath11k_warn message. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211006083217.349596-1-colin.king@canonical.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7091,7 +7091,7 @@ ath11k_mac_op_set_bitrate_mask(struct ie + + if (!ath11k_mac_validate_vht_he_fixed_rate_settings(ar, band, mask)) + ath11k_warn(ar->ab, +- "could not update fixed rate settings to all peers due to mcs/nss incompaitiblity\n"); ++ "could not update fixed rate settings to all peers due to mcs/nss incompatibility\n"); + nss = min_t(u32, ar->num_tx_chains, + max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), + ath11k_mac_max_vht_nss(vht_mcs_mask)), diff --git a/package/kernel/mac80211/patches/ath11k/0055-ath11k-fix-m68k-and-xtensa-build-failure-in-ath11k_p.patch b/package/kernel/mac80211/patches/ath11k/0055-ath11k-fix-m68k-and-xtensa-build-failure-in-ath11k_p.patch new file mode 100644 index 000000000..048c87260 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0055-ath11k-fix-m68k-and-xtensa-build-failure-in-ath11k_p.patch @@ -0,0 +1,56 @@ +From 16bdce2ada5a4c3c91b7c4e81780d2de50bd6ab5 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Fri, 8 Oct 2021 17:39:32 +0300 +Subject: [PATCH] ath11k: fix m68k and xtensa build failure in + ath11k_peer_assoc_h_smps() + +Stephen reported that ath11k was failing to build on m68k and xtensa: + +In file included from :0:0: +In function 'ath11k_peer_assoc_h_smps', + inlined from 'ath11k_peer_assoc_prepare' at drivers/net/wireless/ath/ath11k/mac.c:2362:2: +include/linux/compiler_types.h:317:38: error: call to '__compiletime_assert_650' declared with attribute error: FIELD_GET: type of reg too small for mask + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + ^ +include/linux/compiler_types.h:298:4: note: in definition of macro '__compiletime_assert' + prefix ## suffix(); \ + ^ +include/linux/compiler_types.h:317:2: note: in expansion of macro '_compiletime_assert' + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + ^ +include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert' + #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) + ^ +include/linux/bitfield.h:52:3: note: in expansion of macro 'BUILD_BUG_ON_MSG' + BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ + ^ +include/linux/bitfield.h:108:3: note: in expansion of macro '__BF_FIELD_CHECK' + __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ + ^ +drivers/net/wireless/ath/ath11k/mac.c:2079:10: note: in expansion of macro 'FIELD_GET' + smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, + +Fix the issue by using le16_get_bits() to specify the size explicitly. + +Fixes: 6f4d70308e5e ("ath11k: support SMPS configuration for 6 GHz") +Reported-by: Stephen Rothwell +Tested-by: Geert Uytterhoeven +Signed-off-by: Kalle Valo +Signed-off-by: David S. Miller +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2081,8 +2081,8 @@ static void ath11k_peer_assoc_h_smps(str + smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; + smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; + } else { +- smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, +- le16_to_cpu(sta->he_6ghz_capa.capa)); ++ smps = le16_get_bits(sta->he_6ghz_capa.capa, ++ IEEE80211_HE_6GHZ_CAP_SM_PS); + } + + switch (smps) { diff --git a/package/kernel/mac80211/patches/ath11k/0056-ath11k-Remove-redundant-assignment-to-variable-fw_si.patch b/package/kernel/mac80211/patches/ath11k/0056-ath11k-Remove-redundant-assignment-to-variable-fw_si.patch new file mode 100644 index 000000000..0e7054aa7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0056-ath11k-Remove-redundant-assignment-to-variable-fw_si.patch @@ -0,0 +1,28 @@ +From 4f50bdfb4e5fc3d753c8cf94b94b43aaa2c49b95 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Thu, 7 Oct 2021 18:16:24 +0300 +Subject: [PATCH] ath11k: Remove redundant assignment to variable fw_size + +Variable fw_size is being assigned a value that is never read and +being re-assigned a new value in the next statement. The assignment +is redundant and can be removed. + +Addresses-Coverity: ("Unused value") +Fixes: 336e7b53c82f ("ath11k: clean up BDF download functions") +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211006105529.1011239-1-colin.king@canonical.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2135,7 +2135,6 @@ static int ath11k_qmi_load_bdf_qmi(struc + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf_type %d\n", bdf_type); + +- fw_size = bd.len; + fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); + + ret = ath11k_qmi_load_file_target_mem(ab, bd.data, fw_size, bdf_type); diff --git a/package/kernel/mac80211/patches/ath11k/0057-ath11k-Use-kcalloc-instead-of-kzalloc.patch b/package/kernel/mac80211/patches/ath11k/0057-ath11k-Use-kcalloc-instead-of-kzalloc.patch new file mode 100644 index 000000000..53b1fcc6c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0057-ath11k-Use-kcalloc-instead-of-kzalloc.patch @@ -0,0 +1,40 @@ +From ec4363384c3f110561dc5ee2e59adee02dbd9f73 Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Thu, 7 Oct 2021 18:16:24 +0300 +Subject: [PATCH] ath11k: Use kcalloc() instead of kzalloc() + +Use 2-factor multiplication argument form kcalloc() instead +of kzalloc(). + +Link: https://github.com/KSPP/linux/issues/162 +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211006181204.GA913553@embeddedor +--- + drivers/net/wireless/ath/ath11k/wmi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -4066,8 +4066,8 @@ static int ath11k_wmi_tlv_mac_phy_caps_p + + len = min_t(u16, len, sizeof(struct wmi_mac_phy_capabilities)); + if (!svc_rdy_ext->n_mac_phy_caps) { +- svc_rdy_ext->mac_phy_caps = kzalloc((svc_rdy_ext->tot_phy_id) * len, +- GFP_ATOMIC); ++ svc_rdy_ext->mac_phy_caps = kcalloc(svc_rdy_ext->tot_phy_id, ++ len, GFP_ATOMIC); + if (!svc_rdy_ext->mac_phy_caps) + return -ENOMEM; + } +@@ -4467,8 +4467,8 @@ static struct cur_reg_rule + struct cur_reg_rule *reg_rule_ptr; + u32 count; + +- reg_rule_ptr = kzalloc((num_reg_rules * sizeof(*reg_rule_ptr)), +- GFP_ATOMIC); ++ reg_rule_ptr = kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), ++ GFP_ATOMIC); + + if (!reg_rule_ptr) + return NULL; diff --git a/package/kernel/mac80211/patches/ath11k/0058-ath11k-Handle-MSI-enablement-during-rmmod-and-SSR.patch b/package/kernel/mac80211/patches/ath11k/0058-ath11k-Handle-MSI-enablement-during-rmmod-and-SSR.patch new file mode 100644 index 000000000..dcb1c0410 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0058-ath11k-Handle-MSI-enablement-during-rmmod-and-SSR.patch @@ -0,0 +1,139 @@ +From 96527d527b271d950367ad13e3de8b0673545622 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 09:33:08 +0300 +Subject: [PATCH] ath11k: Handle MSI enablement during rmmod and SSR + +When doing "rmmod ath11k_pci", ath11k performs global SOC reset +and MHI reset, where 0 address access is captured by IOMMU. See +log below: + +... +[ 133.953860] ath11k_pci 0000:02:00.0: setting mhi state: DEINIT(1) +[ 133.959714] ath11k_pci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x000a address=0x0 flags=0x0020] +[ 133.973854] ath11k_pci 0000:02:00.0: MHISTATUS 0xff04 +[ 133.974095] ath11k_pci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x000a address=0x0 flags=0x0020] +... + +This issue is also observed in SSR process, cause a similar +sequence as above is performed. + +Such an invalid access occurs because, during rmmod or SSR, MSI +address is cleared but HW MSI functionality not disabled, thus HW +target is able to raise an MSI transaction with 0 as MSI address. + +So it can be fixed by simply disabling MSI before reset. For SSR, +since MSI functionality is still needed after target is brought +back, we need to reenable it. + +Also change naming of some interfaces related. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913180246.193388-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 41 +++++++++++++++++++++++---- + 1 file changed, 36 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -861,7 +861,32 @@ static void ath11k_pci_ce_irqs_enable(st + } + } + +-static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) ++static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) ++{ ++ struct pci_dev *dev = ab_pci->pdev; ++ u16 control; ++ ++ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); ++ ++ if (enable) ++ control |= PCI_MSI_FLAGS_ENABLE; ++ else ++ control &= ~PCI_MSI_FLAGS_ENABLE; ++ ++ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); ++} ++ ++static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) ++{ ++ ath11k_pci_msi_config(ab_pci, true); ++} ++ ++static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) ++{ ++ ath11k_pci_msi_config(ab_pci, false); ++} ++ ++static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) + { + struct ath11k_base *ab = ab_pci->ab; + const struct ath11k_msi_config *msi_config = ab_pci->msi_config; +@@ -882,6 +907,7 @@ static int ath11k_pci_enable_msi(struct + else + return num_vectors; + } ++ ath11k_pci_msi_disable(ab_pci); + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); + if (!msi_desc) { +@@ -904,7 +930,7 @@ free_msi_vector: + return ret; + } + +-static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) ++static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) + { + pci_free_irq_vectors(ab_pci->pdev); + } +@@ -1025,6 +1051,8 @@ static int ath11k_pci_power_up(struct at + */ + ath11k_pci_aspm_disable(ab_pci); + ++ ath11k_pci_msi_enable(ab_pci); ++ + ret = ath11k_mhi_start(ab_pci); + if (ret) { + ath11k_err(ab, "failed to start mhi: %d\n", ret); +@@ -1045,6 +1073,9 @@ static void ath11k_pci_power_down(struct + ath11k_pci_aspm_restore(ab_pci); + + ath11k_pci_force_wake(ab_pci->ab); ++ ++ ath11k_pci_msi_disable(ab_pci); ++ + ath11k_mhi_stop(ab_pci); + clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); + ath11k_pci_sw_reset(ab_pci->ab, false); +@@ -1279,7 +1310,7 @@ static int ath11k_pci_probe(struct pci_d + goto err_pci_free_region; + } + +- ret = ath11k_pci_enable_msi(ab_pci); ++ ret = ath11k_pci_alloc_msi(ab_pci); + if (ret) { + ath11k_err(ab, "failed to enable msi: %d\n", ret); + goto err_pci_free_region; +@@ -1333,7 +1364,7 @@ err_mhi_unregister: + ath11k_mhi_unregister(ab_pci); + + err_pci_disable_msi: +- ath11k_pci_disable_msi(ab_pci); ++ ath11k_pci_free_msi(ab_pci); + + err_pci_free_region: + ath11k_pci_free_region(ab_pci); +@@ -1364,7 +1395,7 @@ qmi_fail: + ath11k_mhi_unregister(ab_pci); + + ath11k_pci_free_irq(ab); +- ath11k_pci_disable_msi(ab_pci); ++ ath11k_pci_free_msi(ab_pci); + ath11k_pci_free_region(ab_pci); + + ath11k_hal_srng_deinit(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0059-ath11k-Change-number-of-TCL-rings-to-one-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0059-ath11k-Change-number-of-TCL-rings-to-one-for-QCA6390.patch new file mode 100644 index 000000000..add021679 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0059-ath11k-Change-number-of-TCL-rings-to-one-for-QCA6390.patch @@ -0,0 +1,241 @@ +From 31582373a4a8e888b29ed759d28330a1995f2162 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 09:33:09 +0300 +Subject: [PATCH] ath11k: Change number of TCL rings to one for QCA6390 + +Some targets, QCA6390 for example, use only one TCL ring, it is better to +initialize only one ring and leave others untouched for such targets. + +This is a theoretical fix found during code review, no visible impact. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914163726.38604-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 10 +++++----- + drivers/net/wireless/ath/ath11k/debugfs.c | 2 +- + drivers/net/wireless/ath/ath11k/dp.c | 10 +++++----- + drivers/net/wireless/ath/ath11k/dp.h | 1 + + drivers/net/wireless/ath/ath11k/dp_tx.c | 13 +++++-------- + drivers/net/wireless/ath/ath11k/hw.h | 2 +- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 7 files changed, 19 insertions(+), 21 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -58,7 +58,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = false, + .vdev_start_delay = false, + .htt_peer_map_v2 = true, +- .tcl_0_only = false, + + .spectral = { + .fft_sz = 2, +@@ -81,6 +80,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -109,7 +109,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = false, + .vdev_start_delay = false, + .htt_peer_map_v2 = true, +- .tcl_0_only = false, + + .spectral = { + .fft_sz = 4, +@@ -129,6 +128,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX, + }, + { + .name = "qca6390 hw2.0", +@@ -157,7 +157,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, +- .tcl_0_only = true, + + .spectral = { + .fft_sz = 0, +@@ -176,6 +175,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + }, + { + .name = "qcn9074 hw1.0", +@@ -203,7 +203,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = false, + .vdev_start_delay = false, + .htt_peer_map_v2 = true, +- .tcl_0_only = false, + + .spectral = { + .fft_sz = 2, +@@ -223,6 +222,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX, + }, + { + .name = "wcn6855 hw2.0", +@@ -251,7 +251,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, +- .tcl_0_only = true, + + .spectral = { + .fft_sz = 0, +@@ -270,6 +269,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -806,7 +806,7 @@ static ssize_t ath11k_debugfs_dump_soc_d + len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n"); + len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n"); + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) + len += scnprintf(buf + len, size - len, "ring%d: %u\n", + i, soc_stats->tx_err.desc_na[i]); + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -311,7 +311,7 @@ void ath11k_dp_stop_shadow_timers(struct + if (!ab->hw_params.supports_shadow_regs) + return; + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) + ath11k_dp_shadow_stop_timer(ab, &ab->dp.tx_ring_timer[i]); + + ath11k_dp_shadow_stop_timer(ab, &ab->dp.reo_cmd_timer); +@@ -326,7 +326,7 @@ static void ath11k_dp_srng_common_cleanu + ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring); + ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring); + ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring); +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring); + ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring); + } +@@ -366,7 +366,7 @@ static int ath11k_dp_srng_common_setup(s + goto err; + } + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring, + HAL_TCL_DATA, i, 0, + DP_TCL_DATA_RING_SIZE); +@@ -996,7 +996,7 @@ void ath11k_dp_free(struct ath11k_base * + + ath11k_dp_reo_cmd_list_cleanup(ab); + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + spin_lock_bh(&dp->tx_ring[i].tx_idr_lock); + idr_for_each(&dp->tx_ring[i].txbuf_idr, + ath11k_dp_tx_pending_cleanup, ab); +@@ -1046,7 +1046,7 @@ int ath11k_dp_alloc(struct ath11k_base * + + size = sizeof(struct hal_wbm_release_ring) * DP_TX_COMP_RING_SIZE; + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + idr_init(&dp->tx_ring[i].txbuf_idr); + spin_lock_init(&dp->tx_ring[i].tx_idr_lock); + dp->tx_ring[i].tcl_data_ring_id = i; +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -170,6 +170,7 @@ struct ath11k_pdev_dp { + #define DP_BA_WIN_SZ_MAX 256 + + #define DP_TCL_NUM_RING_MAX 3 ++#define DP_TCL_NUM_RING_MAX_QCA6390 1 + + #define DP_IDLE_SCATTER_BUFS_MAX 16 + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -115,11 +115,8 @@ int ath11k_dp_tx(struct ath11k *ar, stru + + tcl_ring_sel: + tcl_ring_retry = false; +- /* For some chip, it can only use tcl0 to tx */ +- if (ar->ab->hw_params.tcl_0_only) +- ti.ring_id = 0; +- else +- ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX; ++ ++ ti.ring_id = ring_selector % ab->hw_params.max_tx_ring; + + ring_map |= BIT(ti.ring_id); + +@@ -131,7 +128,7 @@ tcl_ring_sel: + spin_unlock_bh(&tx_ring->tx_idr_lock); + + if (ret < 0) { +- if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) { ++ if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1)) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + return -ENOSPC; + } +@@ -248,8 +245,8 @@ tcl_ring_sel: + * checking this ring earlier for each pkt tx. + * Restart ring selection if some rings are not checked yet. + */ +- if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1) && +- !ar->ab->hw_params.tcl_0_only) { ++ if (ring_map != (BIT(ab->hw_params.max_tx_ring) - 1) && ++ ab->hw_params.max_tx_ring > 1) { + tcl_ring_retry = true; + ring_selector++; + } +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -152,7 +152,6 @@ struct ath11k_hw_params { + bool rx_mac_buf_ring; + bool vdev_start_delay; + bool htt_peer_map_v2; +- bool tcl_0_only; + + struct { + u8 fft_sz; +@@ -170,6 +169,7 @@ struct ath11k_hw_params { + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; ++ u8 max_tx_ring; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5807,7 +5807,7 @@ err_vdev_del: + idr_for_each(&ar->txmgmt_idr, + ath11k_mac_vif_txmgmt_idr_remove, vif); + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock); + idr_for_each(&ab->dp.tx_ring[i].txbuf_idr, + ath11k_mac_vif_unref, vif); diff --git a/package/kernel/mac80211/patches/ath11k/0060-ath11k-Identify-DFS-channel-when-sending-scan-channe.patch b/package/kernel/mac80211/patches/ath11k/0060-ath11k-Identify-DFS-channel-when-sending-scan-channe.patch new file mode 100644 index 000000000..1c762ff25 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0060-ath11k-Identify-DFS-channel-when-sending-scan-channe.patch @@ -0,0 +1,33 @@ +From 8cd5c0847160aa9482d7f93ed63c4d72bad70cdf Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 18:18:00 +0300 +Subject: [PATCH] ath11k: Identify DFS channel when sending scan channel list + command + +WMI_CHAN_INFO_DFS flag should be set when configuring a DFS channel +included in scan channel list. Without it, firmware will not send a +probe request frame which is needed in connection to an AP configured +with hidden SSID/network_id. So fix this to allow probe request frames +to be sent in cases where a beacon frame has been seen on the channel +first. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211011054919.77071-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2372,6 +2372,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(s + chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE; + if (tchan_info->psc_channel) + chan_info->info |= WMI_CHAN_INFO_PSC; ++ if (tchan_info->dfs_set) ++ chan_info->info |= WMI_CHAN_INFO_DFS; + + chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, + tchan_info->phy_mode); diff --git a/package/kernel/mac80211/patches/ath11k/0061-ath11k-change-return-buffer-manager-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0061-ath11k-change-return-buffer-manager-for-QCA6390.patch new file mode 100644 index 000000000..2c7153301 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0061-ath11k-change-return-buffer-manager-for-QCA6390.patch @@ -0,0 +1,299 @@ +From 734223d78428de3c7c7d7bc04daf258085780d90 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 20 Oct 2021 11:59:06 +0300 +Subject: [PATCH] ath11k: change return buffer manager for QCA6390 + +QCA6390 firmware uses HAL_RX_BUF_RBM_SW1_BM, not HAL_RX_BUF_RBM_SW3_BM. This is +needed to fix a case where an A-MSDU has an unexpected LLC/SNAP header in the +first subframe (CVE-2020-24588). + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914163726.38604-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++++ + drivers/net/wireless/ath/ath11k/dp.c | 4 +++- + drivers/net/wireless/ath/ath11k/dp_rx.c | 29 +++++++++++++++--------- + drivers/net/wireless/ath/ath11k/hal_rx.c | 6 +++-- + drivers/net/wireless/ath/ath11k/hw.c | 11 ++++++++- + drivers/net/wireless/ath/ath11k/hw.h | 9 ++++++++ + 6 files changed, 49 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -81,6 +81,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -129,6 +130,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, + }, + { + .name = "qca6390 hw2.0", +@@ -176,6 +178,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, ++ .hal_params = &ath11k_hw_hal_params_qca6390, + }, + { + .name = "qcn9074 hw1.0", +@@ -223,6 +226,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, + }, + { + .name = "wcn6855 hw2.0", +@@ -270,6 +274,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, ++ .hal_params = &ath11k_hw_hal_params_qca6390, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -739,6 +739,7 @@ int ath11k_dp_service_srng(struct ath11k + int budget) + { + struct napi_struct *napi = &irq_grp->napi; ++ const struct ath11k_hw_hal_params *hal_params; + int grp_id = irq_grp->grp_id; + int work_done = 0; + int i = 0, j; +@@ -821,8 +822,9 @@ int ath11k_dp_service_srng(struct ath11k + struct ath11k_pdev_dp *dp = &ar->dp; + struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + ++ hal_params = ab->hw_params.hal_params; + ath11k_dp_rxbufs_replenish(ab, id, rx_ring, 0, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + } + } + } +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -499,7 +499,7 @@ static int ath11k_dp_rxdma_ring_buf_setu + + rx_ring->bufs_max = num_entries; + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries, +- HAL_RX_BUF_RBM_SW3_BM); ++ ar->ab->hw_params.hal_params->rx_buf_rbm); + return 0; + } + +@@ -2756,7 +2756,7 @@ try_again: + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + } + + ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, +@@ -2949,6 +2949,7 @@ static int ath11k_dp_rx_reap_mon_status_ + int *budget, struct sk_buff_head *skb_list) + { + struct ath11k *ar; ++ const struct ath11k_hw_hal_params *hal_params; + struct ath11k_pdev_dp *dp; + struct dp_rxdma_ring *rx_ring; + struct hal_srng *srng; +@@ -3019,8 +3020,9 @@ move_next: + &buf_id); + + if (!skb) { ++ hal_params = ab->hw_params.hal_params; + ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + num_buffs_reaped++; + break; + } +@@ -3030,7 +3032,8 @@ move_next: + FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); + + ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr, +- cookie, HAL_RX_BUF_RBM_SW3_BM); ++ cookie, ++ ab->hw_params.hal_params->rx_buf_rbm); + ath11k_hal_srng_src_get_next_entry(ab, srng); + num_buffs_reaped++; + } +@@ -3419,7 +3422,8 @@ static int ath11k_dp_rx_h_defrag_reo_rei + cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, dp->mac_id) | + FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); + +- ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, HAL_RX_BUF_RBM_SW3_BM); ++ ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, ++ ab->hw_params.hal_params->rx_buf_rbm); + + /* Fill mpdu details into reo entrace ring */ + srng = &ab->hal.srng_list[ab->dp.reo_reinject_ring.ring_id]; +@@ -3796,7 +3800,7 @@ int ath11k_dp_process_rx_err(struct ath1 + ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, + &rbm); + if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST && +- rbm != HAL_RX_BUF_RBM_SW3_BM) { ++ rbm != ab->hw_params.hal_params->rx_buf_rbm) { + ab->soc_stats.invalid_rbm++; + ath11k_warn(ab, "invalid return buffer manager %d\n", rbm); + ath11k_dp_rx_link_desc_return(ab, desc, +@@ -3852,7 +3856,7 @@ exit: + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, n_bufs_reaped[i], +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + } + + return tot_n_bufs_reaped; +@@ -4148,7 +4152,7 @@ int ath11k_dp_rx_process_wbm_err(struct + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + } + + rcu_read_lock(); +@@ -4257,7 +4261,7 @@ int ath11k_dp_process_rxdma_err(struct a + + if (num_buf_freed) + ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buf_freed, +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + + return budget - quota; + } +@@ -4976,6 +4980,7 @@ static void ath11k_dp_rx_mon_dest_proces + { + struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; ++ const struct ath11k_hw_hal_params *hal_params; + void *ring_entry; + void *mon_dst_srng; + u32 ppdu_id; +@@ -5039,16 +5044,18 @@ static void ath11k_dp_rx_mon_dest_proces + + if (rx_bufs_used) { + rx_mon_stats->dest_ppdu_done++; ++ hal_params = ar->ab->hw_params.hal_params; ++ + if (ar->ab->hw_params.rxdma1_enable) + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, + &dp->rxdma_mon_buf_ring, + rx_bufs_used, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + else + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, + &dp->rx_refill_buf_ring, + rx_bufs_used, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + } + } + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -356,6 +356,7 @@ int ath11k_hal_wbm_desc_parse_err(struct + struct hal_wbm_release_ring *wbm_desc = desc; + enum hal_wbm_rel_desc_type type; + enum hal_wbm_rel_src_module rel_src; ++ enum hal_rx_buf_return_buf_manager ret_buf_mgr; + + type = FIELD_GET(HAL_WBM_RELEASE_INFO0_DESC_TYPE, + wbm_desc->info0); +@@ -371,8 +372,9 @@ int ath11k_hal_wbm_desc_parse_err(struct + rel_src != HAL_WBM_REL_SRC_MODULE_REO) + return -EINVAL; + +- if (FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, +- wbm_desc->buf_addr_info.info1) != HAL_RX_BUF_RBM_SW3_BM) { ++ ret_buf_mgr = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, ++ wbm_desc->buf_addr_info.info1); ++ if (ret_buf_mgr != ab->hw_params.hal_params->rx_buf_rbm) { + ab->soc_stats.invalid_rbm++; + return -EINVAL; + } +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -7,10 +7,11 @@ + #include + #include + +-#include "hw.h" + #include "core.h" + #include "ce.h" + #include "hif.h" ++#include "hal.h" ++#include "hw.h" + + /* Map from pdev index to hw mac index */ + static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx) +@@ -2122,3 +2123,11 @@ const struct ath11k_hw_regs wcn6855_regs + .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac, + .pcie_pcs_osc_dtct_config_base = 0x01e0c628, + }; ++ ++const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = { ++ .rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM, ++}; ++ ++const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390 = { ++ .rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM, ++}; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -6,6 +6,7 @@ + #ifndef ATH11K_HW_H + #define ATH11K_HW_H + ++#include "hal.h" + #include "wmi.h" + + /* Target configuration defines */ +@@ -119,6 +120,10 @@ struct ath11k_hw_ring_mask { + u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + }; + ++struct ath11k_hw_hal_params { ++ enum hal_rx_buf_return_buf_manager rx_buf_rbm; ++}; ++ + struct ath11k_hw_params { + const char *name; + u16 hw_rev; +@@ -170,6 +175,7 @@ struct ath11k_hw_params { + u32 hal_desc_sz; + bool fix_l1ss; + u8 max_tx_ring; ++ const struct ath11k_hw_hal_params *hal_params; + }; + + struct ath11k_hw_ops { +@@ -223,6 +229,9 @@ extern const struct ath11k_hw_ring_mask + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074; + ++extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074; ++extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390; ++ + static inline + int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, + int pdev_idx) diff --git a/package/kernel/mac80211/patches/ath11k/0062-ath11k-set-correct-NL80211_FEATURE_DYNAMIC_SMPS-for-.patch b/package/kernel/mac80211/patches/ath11k/0062-ath11k-set-correct-NL80211_FEATURE_DYNAMIC_SMPS-for-.patch new file mode 100644 index 000000000..9c8b84a67 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0062-ath11k-set-correct-NL80211_FEATURE_DYNAMIC_SMPS-for-.patch @@ -0,0 +1,93 @@ +From 82c434c103408842a87404e873992b7698b6df2b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Thu, 28 Oct 2021 10:46:28 +0300 +Subject: [PATCH] ath11k: set correct NL80211_FEATURE_DYNAMIC_SMPS for WCN6855 + +Commit 6f4d70308e5e ("ath11k: support SMPS configuration for 6 GHz") changed +"if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS)" to "if (ht_cap & +WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz)" which means +NL80211_FEATURE_DYNAMIC_SMPS is enabled for all chips which support 6 GHz. +However, WCN6855 supports 6 GHz but it does not support feature +NL80211_FEATURE_DYNAMIC_SMPS, and this can lead to MU-MIMO test failures for +WCN6855. + +Disable NL80211_FEATURE_DYNAMIC_SMPS for WCN6855 since its ht_cap does not +support WMI_HT_CAP_DYNAMIC_SMPS. Enable the feature only on QCN9074 as that's +the only other device supporting 6 GHz band. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914163726.38604-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 3 ++- + 3 files changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -82,6 +82,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .supports_dynamic_smps_6ghz = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -131,6 +132,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .supports_dynamic_smps_6ghz = false, + }, + { + .name = "qca6390 hw2.0", +@@ -179,6 +181,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, ++ .supports_dynamic_smps_6ghz = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -227,6 +230,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .supports_dynamic_smps_6ghz = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -275,6 +279,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, ++ .supports_dynamic_smps_6ghz = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -176,6 +176,7 @@ struct ath11k_hw_params { + bool fix_l1ss; + u8 max_tx_ring; + const struct ath11k_hw_hal_params *hal_params; ++ bool supports_dynamic_smps_6ghz; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7682,7 +7682,8 @@ static int __ath11k_mac_register(struct + * for each band for a dual band capable radio. It will be tricky to + * handle it when the ht capability different for each band. + */ +- if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz) ++ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ++ (ar->supports_6ghz && ab->hw_params.supports_dynamic_smps_6ghz)) + ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + + ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; diff --git a/package/kernel/mac80211/patches/ath11k/0063-ath11k-convert-ath11k_wmi_pdev_set_ps_mode-to-use-en.patch b/package/kernel/mac80211/patches/ath11k/0063-ath11k-convert-ath11k_wmi_pdev_set_ps_mode-to-use-en.patch new file mode 100644 index 000000000..7d130b0c4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0063-ath11k-convert-ath11k_wmi_pdev_set_ps_mode-to-use-en.patch @@ -0,0 +1,73 @@ +From af3d89649bb69bd5be273cf6c001cd19c2604ca2 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Mon, 8 Nov 2021 14:38:25 +0200 +Subject: [PATCH] ath11k: convert ath11k_wmi_pdev_set_ps_mode() to use enum + wmi_sta_ps_mode + +It's more descriptive to use the actual enum used by the firmware instead of a +boolean so change ath11k_wmi_pdev_set_ps_mode() to use a boolean. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211108123826.8463-1-kvalo@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 ++- + drivers/net/wireless/ath/ath11k/wmi.c | 7 ++++--- + drivers/net/wireless/ath/ath11k/wmi.h | 3 ++- + 3 files changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5648,7 +5648,8 @@ static int ath11k_mac_op_add_interface(s + goto err_peer_del; + } + +- ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, false); ++ ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, ++ WMI_STA_PS_MODE_DISABLED); + if (ret) { + ath11k_warn(ar->ab, "failed to disable vdev %d ps mode: %d\n", + arvif->vdev_id, ret); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1244,7 +1244,8 @@ int ath11k_wmi_pdev_set_param(struct ath + return ret; + } + +-int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable) ++int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, ++ enum wmi_sta_ps_mode psmode) + { + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_pdev_set_ps_mode_cmd *cmd; +@@ -1259,7 +1260,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct a + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_STA_POWERSAVE_MODE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; +- cmd->sta_ps_mode = enable; ++ cmd->sta_ps_mode = psmode; + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_MODE_CMDID); + if (ret) { +@@ -1269,7 +1270,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct a + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI vdev set psmode %d vdev id %d\n", +- enable, vdev_id); ++ psmode, vdev_id); + + return ret; + } +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5351,7 +5351,8 @@ int ath11k_wmi_set_peer_param(struct ath + u32 vdev_id, u32 param_id, u32 param_val); + int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, + u32 param_value, u8 pdev_id); +-int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable); ++int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, ++ enum wmi_sta_ps_mode psmode); + int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab); + int ath11k_wmi_cmd_init(struct ath11k_base *ab); + int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab); diff --git a/package/kernel/mac80211/patches/ath11k/0064-ath11k-enable-802.11-power-save-mode-in-station-mode.patch b/package/kernel/mac80211/patches/ath11k/0064-ath11k-enable-802.11-power-save-mode-in-station-mode.patch new file mode 100644 index 000000000..e2a6a4f92 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0064-ath11k-enable-802.11-power-save-mode-in-station-mode.patch @@ -0,0 +1,192 @@ +From b2beffa7d9a67b59b085616a27f1d10b1e80784f Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 8 Nov 2021 14:38:26 +0200 +Subject: [PATCH] ath11k: enable 802.11 power save mode in station mode + +To reduce power consumption enable 802.11 power save mode in station mode. This +allows both radio and CPU to sleep more. + +Only enable the mode on QCA6390 and WCN6855, it's unknown how other hardware +families support this feature. + +To test that power save mode is running run "iw dev wls1 set power_save off", +check there is no NULL Data frame seen by a sniffer. And run "iw dev wls1 set power_save +on" and check there is a NULL Data frame in sniffer. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211108123826.8463-2-kvalo@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++ + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 87 ++++++++++++++++++++++++++ + 4 files changed, 94 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -76,6 +76,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = true, + .supports_shadow_regs = false, + .idle_ps = false, ++ .supports_sta_ps = false, + .cold_boot_calib = true, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +@@ -126,6 +127,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = true, + .supports_shadow_regs = false, + .idle_ps = false, ++ .supports_sta_ps = false, + .cold_boot_calib = true, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +@@ -175,6 +177,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = false, + .supports_shadow_regs = true, + .idle_ps = true, ++ .supports_sta_ps = true, + .cold_boot_calib = false, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +@@ -224,6 +227,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = true, + .supports_shadow_regs = false, + .idle_ps = false, ++ .supports_sta_ps = false, + .cold_boot_calib = false, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), +@@ -273,6 +277,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = false, + .supports_shadow_regs = true, + .idle_ps = true, ++ .supports_sta_ps = true, + .cold_boot_calib = false, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -246,6 +246,7 @@ struct ath11k_vif { + bool is_started; + bool is_up; + bool spectral_enabled; ++ bool ps; + u32 aid; + u8 bssid[ETH_ALEN]; + struct cfg80211_bitrate_mask bitrate_mask; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -170,6 +170,7 @@ struct ath11k_hw_params { + bool supports_monitor; + bool supports_shadow_regs; + bool idle_ps; ++ bool supports_sta_ps; + bool cold_boot_calib; + bool supports_suspend; + u32 hal_desc_sz; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1050,6 +1050,83 @@ static int ath11k_mac_monitor_stop(struc + return 0; + } + ++static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) ++{ ++ struct ath11k *ar = arvif->ar; ++ struct ieee80211_vif *vif = arvif->vif; ++ struct ieee80211_conf *conf = &ar->hw->conf; ++ enum wmi_sta_powersave_param param; ++ enum wmi_sta_ps_mode psmode; ++ int ret; ++ int timeout; ++ bool enable_ps; ++ ++ lockdep_assert_held(&arvif->ar->conf_mutex); ++ ++ if (arvif->vif->type != NL80211_IFTYPE_STATION) ++ return 0; ++ ++ enable_ps = arvif->ps; ++ ++ if (!arvif->is_started) { ++ /* mac80211 can update vif powersave state while disconnected. ++ * Firmware doesn't behave nicely and consumes more power than ++ * necessary if PS is disabled on a non-started vdev. Hence ++ * force-enable PS for non-running vdevs. ++ */ ++ psmode = WMI_STA_PS_MODE_ENABLED; ++ } else if (enable_ps) { ++ psmode = WMI_STA_PS_MODE_ENABLED; ++ param = WMI_STA_PS_PARAM_INACTIVITY_TIME; ++ ++ timeout = conf->dynamic_ps_timeout; ++ if (timeout == 0) { ++ /* firmware doesn't like 0 */ ++ timeout = ieee80211_tu_to_usec(vif->bss_conf.beacon_int) / 1000; ++ } ++ ++ ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, ++ timeout); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } else { ++ psmode = WMI_STA_PS_MODE_DISABLED; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d psmode %s\n", ++ arvif->vdev_id, psmode ? "enable" : "disable"); ++ ++ ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", ++ psmode, arvif->vdev_id, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ath11k_mac_config_ps(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ int ret = 0; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath11k_mac_vif_setup_ps(arvif); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to setup powersave: %d\n", ret); ++ break; ++ } ++ } ++ ++ return ret; ++} ++ + static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) + { + struct ath11k *ar = hw->priv; +@@ -2947,6 +3024,16 @@ static void ath11k_mac_op_bss_info_chang + ath11k_mac_txpower_recalc(ar); + } + ++ if (changed & BSS_CHANGED_PS && ++ ar->ab->hw_params.supports_sta_ps) { ++ arvif->ps = vif->bss_conf.ps; ++ ++ ret = ath11k_mac_config_ps(ar); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to setup ps on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ } ++ + if (changed & BSS_CHANGED_MCAST_RATE && + !ath11k_mac_vif_chan(arvif->vif, &def)) { + band = def.chan->band; diff --git a/package/kernel/mac80211/patches/ath11k/0066-ath11k-Clear-auth-flag-only-for-actual-association-i.patch b/package/kernel/mac80211/patches/ath11k/0066-ath11k-Clear-auth-flag-only-for-actual-association-i.patch new file mode 100644 index 000000000..60e76e53a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0066-ath11k-Clear-auth-flag-only-for-actual-association-i.patch @@ -0,0 +1,72 @@ +From c802b6d7815d7c3f556efea28d0b79ef57ebcfd4 Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Mon, 25 Oct 2021 21:33:06 +0530 +Subject: [PATCH] ath11k: Clear auth flag only for actual association in + security mode + +AUTH flag is needed when peer assoc command is sent from host in +security mode for non-assoc cases. Firmware will handle AUTH flag +when client is associating as AUTH flag will be set after key exchange. +For internally provided peer assoc commands from host, there won't be +any key exchange, so AUTH flag is expected to be set in host. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635177786-20854-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + drivers/net/wireless/ath/ath11k/wmi.h | 1 + + 3 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2500,6 +2500,7 @@ static void ath11k_bss_assoc(struct ieee + + rcu_read_unlock(); + ++ peer_arg.is_assoc = true; + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (ret) { + ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", +@@ -3778,6 +3779,7 @@ static int ath11k_station_assoc(struct a + + ath11k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); + ++ peer_arg.is_assoc = true; + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (ret) { + ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", +@@ -3989,6 +3991,7 @@ static void ath11k_sta_rc_update_wk(stru + ath11k_peer_assoc_prepare(ar, arvif->vif, sta, + &peer_arg, true); + ++ peer_arg.is_assoc = false; + err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (err) + ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1764,7 +1764,7 @@ ath11k_wmi_copy_peer_flags(struct wmi_pe + cmd->peer_flags |= WMI_PEER_AUTH; + if (param->need_ptk_4_way) { + cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; +- if (!hw_crypto_disabled) ++ if (!hw_crypto_disabled && param->is_assoc) + cmd->peer_flags &= ~WMI_PEER_AUTH; + } + if (param->need_gtk_2_way) +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3617,6 +3617,7 @@ struct peer_assoc_params { + u32 peer_he_tx_mcs_set[WMI_HOST_MAX_HE_RATE_SET]; + bool twt_responder; + bool twt_requester; ++ bool is_assoc; + struct ath11k_ppe_threshold peer_ppet; + }; + diff --git a/package/kernel/mac80211/patches/ath11k/0067-ath11k-fix-fw-crash-due-to-peer-get-authorized-befor.patch b/package/kernel/mac80211/patches/ath11k/0067-ath11k-fix-fw-crash-due-to-peer-get-authorized-befor.patch new file mode 100644 index 000000000..5413ae8e6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0067-ath11k-fix-fw-crash-due-to-peer-get-authorized-befor.patch @@ -0,0 +1,114 @@ +From 85f36923be47b6990215ad444545a6a85133a0c6 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 12 Nov 2021 10:03:40 +0200 +Subject: [PATCH] ath11k: fix fw crash due to peer get authorized before key + install + +Firmware expects host to authorize the peer after the successful key +install. But host authorize the peer before the key install, this trigger +the firmware assert which leads to Q6 crash. To avoid this Q6 crash, host +should authorize the peer after the key install. So introduce is_authorized +in peer object to identify that peer is authorize or not. When +IEEE80211_STA_CONTROL_PORT flag is unset, peer move to authorize state +before the vdev up. When the same flag is set then peer move to authorize +state after vdev up. So added authorise check in ath11k_bss_assoc() to +handle the earlier state transition case. Also added the WMI authorize +procedure in ath11k_mac_op_sta_state() to handle the non-earlier state +transition case. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636554200-12345-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 53 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/peer.h | 1 + + 2 files changed, 47 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2479,6 +2479,8 @@ static void ath11k_bss_assoc(struct ieee + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct peer_assoc_params peer_arg; + struct ieee80211_sta *ap_sta; ++ struct ath11k_peer *peer; ++ bool is_auth = false; + int ret; + + lockdep_assert_held(&ar->conf_mutex); +@@ -2541,13 +2543,22 @@ static void ath11k_bss_assoc(struct ieee + "mac vdev %d up (associated) bssid %pM aid %d\n", + arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + +- /* Authorize BSS Peer */ +- ret = ath11k_wmi_set_peer_param(ar, arvif->bssid, +- arvif->vdev_id, +- WMI_PEER_AUTHORIZE, +- 1); +- if (ret) +- ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); ++ spin_lock_bh(&ar->ab->base_lock); ++ ++ peer = ath11k_peer_find(ar->ab, arvif->vdev_id, arvif->bssid); ++ if (peer && peer->is_authorized) ++ is_auth = true; ++ ++ spin_unlock_bh(&ar->ab->base_lock); ++ ++ if (is_auth) { ++ ret = ath11k_wmi_set_peer_param(ar, arvif->bssid, ++ arvif->vdev_id, ++ WMI_PEER_AUTHORIZE, ++ 1); ++ if (ret) ++ ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); ++ } + + ret = ath11k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id, + &bss_conf->he_obss_pd); +@@ -4227,6 +4238,34 @@ static int ath11k_mac_op_sta_state(struc + ath11k_warn(ar->ab, "Failed to associate station: %pM\n", + sta->addr); + } else if (old_state == IEEE80211_STA_ASSOC && ++ new_state == IEEE80211_STA_AUTHORIZED) { ++ spin_lock_bh(&ar->ab->base_lock); ++ ++ peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); ++ if (peer) ++ peer->is_authorized = true; ++ ++ spin_unlock_bh(&ar->ab->base_lock); ++ ++ if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) { ++ ret = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_AUTHORIZE, ++ 1); ++ if (ret) ++ ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", ++ sta->addr, arvif->vdev_id, ret); ++ } ++ } else if (old_state == IEEE80211_STA_AUTHORIZED && ++ new_state == IEEE80211_STA_ASSOC) { ++ spin_lock_bh(&ar->ab->base_lock); ++ ++ peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); ++ if (peer) ++ peer->is_authorized = false; ++ ++ spin_unlock_bh(&ar->ab->base_lock); ++ } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH && + (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT || +--- a/drivers/net/wireless/ath/ath11k/peer.h ++++ b/drivers/net/wireless/ath/ath11k/peer.h +@@ -28,6 +28,7 @@ struct ath11k_peer { + u8 ucast_keyidx; + u16 sec_type; + u16 sec_type_grp; ++ bool is_authorized; + }; + + void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id); diff --git a/package/kernel/mac80211/patches/ath11k/0068-ath11k-fix-error-routine-when-fallback-of-add-interf.patch b/package/kernel/mac80211/patches/ath11k/0068-ath11k-fix-error-routine-when-fallback-of-add-interf.patch new file mode 100644 index 000000000..b9e95c6d2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0068-ath11k-fix-error-routine-when-fallback-of-add-interf.patch @@ -0,0 +1,60 @@ +From 4ea03443ecdac6920eb7aa3a9da2cd0b8cc6dfc8 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 10 Nov 2021 21:05:57 +0530 +Subject: [PATCH] ath11k: fix error routine when fallback of add interface + fails + +When there is an error in add interface process from +ath11k_mac_set_kickout(), the code attempts to handle a +fallback for add_interface. When this fallback succeeds, the +driver returns zero rather than error code. This leads to +success for the non created VAP. In cleanup, driver gets +remove interface callback for the non created VAP and +proceeds to self peer delete request which leads to FW assert. +Since it was already deleted on the fallback of add interface, +return the actual error code instead of fallback return code. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636558557-2874-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5623,7 +5623,7 @@ static int ath11k_mac_op_add_interface(s + u32 param_id, param_value; + u16 nss; + int i; +- int ret; ++ int ret, fbret; + int bit; + + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; +@@ -5826,17 +5826,17 @@ err_peer_del: + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + reinit_completion(&ar->peer_delete_done); + +- ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, +- arvif->vdev_id); +- if (ret) { ++ fbret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, ++ arvif->vdev_id); ++ if (fbret) { + ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", + arvif->vdev_id, vif->addr); + goto err; + } + +- ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, +- vif->addr); +- if (ret) ++ fbret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, ++ vif->addr); ++ if (fbret) + goto err; + + ar->num_peers--; diff --git a/package/kernel/mac80211/patches/ath11k/0069-ath11k-avoid-unnecessary-BH-disable-lock-in-STA-kick.patch b/package/kernel/mac80211/patches/ath11k/0069-ath11k-avoid-unnecessary-BH-disable-lock-in-STA-kick.patch new file mode 100644 index 000000000..cf9adcada --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0069-ath11k-avoid-unnecessary-BH-disable-lock-in-STA-kick.patch @@ -0,0 +1,57 @@ +From 4c375743c5fe1ef84d1dd7269dd12585957f403e Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 10 Nov 2021 21:36:28 +0530 +Subject: [PATCH] ath11k: avoid unnecessary BH disable lock in STA kickout + event + +In STA kickout event processing, the peer object is protected +under spin lock BH. Release this lock after picking up the vdev_id +from the peer object instead after ieee80211_report_low_ack(). +This will minimize the lock hold period which will improve +performance since base_lock is used across the data path. +This was found in code review. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636560388-24955-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -6400,6 +6400,7 @@ static void ath11k_peer_sta_kickout_even + struct ieee80211_sta *sta; + struct ath11k_peer *peer; + struct ath11k *ar; ++ u32 vdev_id; + + if (ath11k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) { + ath11k_warn(ab, "failed to extract peer sta kickout event"); +@@ -6415,10 +6416,15 @@ static void ath11k_peer_sta_kickout_even + if (!peer) { + ath11k_warn(ab, "peer not found %pM\n", + arg.mac_addr); ++ spin_unlock_bh(&ab->base_lock); + goto exit; + } + +- ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id); ++ vdev_id = peer->vdev_id; ++ ++ spin_unlock_bh(&ab->base_lock); ++ ++ ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath11k_warn(ab, "invalid vdev id in peer sta kickout ev %d", + peer->vdev_id); +@@ -6439,7 +6445,6 @@ static void ath11k_peer_sta_kickout_even + ieee80211_report_low_ack(sta, 10); + + exit: +- spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + } + diff --git a/package/kernel/mac80211/patches/ath11k/0070-ath11k-fix-DMA-memory-free-in-CE-pipe-cleanup.patch b/package/kernel/mac80211/patches/ath11k/0070-ath11k-fix-DMA-memory-free-in-CE-pipe-cleanup.patch new file mode 100644 index 000000000..8fceae59a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0070-ath11k-fix-DMA-memory-free-in-CE-pipe-cleanup.patch @@ -0,0 +1,74 @@ +From 31aeaf547d7e3b64ba5d5442dabc530bdb9e216e Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 10 Nov 2021 21:51:30 +0530 +Subject: [PATCH] ath11k: fix DMA memory free in CE pipe cleanup + +In CE pipe cleanup, DMA memory gets freed by the aligned address +(base_addr_owner_space) which is wrong. It needs to be freed +by the address (base_addr_owner_space_unaligned) returned by +dma_alloc. So free the dma memory by the proper address. +This was found in code review. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636561290-18966-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ce.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -953,6 +953,7 @@ int ath11k_ce_init_pipes(struct ath11k_b + void ath11k_ce_free_pipes(struct ath11k_base *ab) + { + struct ath11k_ce_pipe *pipe; ++ struct ath11k_ce_ring *ce_ring; + int desc_sz; + int i; + +@@ -964,22 +965,24 @@ void ath11k_ce_free_pipes(struct ath11k_ + + if (pipe->src_ring) { + desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); ++ ce_ring = pipe->src_ring; + dma_free_coherent(ab->dev, + pipe->src_ring->nentries * desc_sz + + CE_DESC_RING_ALIGN, +- pipe->src_ring->base_addr_owner_space, +- pipe->src_ring->base_addr_ce_space); ++ ce_ring->base_addr_owner_space_unaligned, ++ ce_ring->base_addr_ce_space_unaligned); + kfree(pipe->src_ring); + pipe->src_ring = NULL; + } + + if (pipe->dest_ring) { + desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); ++ ce_ring = pipe->dest_ring; + dma_free_coherent(ab->dev, + pipe->dest_ring->nentries * desc_sz + + CE_DESC_RING_ALIGN, +- pipe->dest_ring->base_addr_owner_space, +- pipe->dest_ring->base_addr_ce_space); ++ ce_ring->base_addr_owner_space_unaligned, ++ ce_ring->base_addr_ce_space_unaligned); + kfree(pipe->dest_ring); + pipe->dest_ring = NULL; + } +@@ -987,11 +990,12 @@ void ath11k_ce_free_pipes(struct ath11k_ + if (pipe->status_ring) { + desc_sz = + ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); ++ ce_ring = pipe->status_ring; + dma_free_coherent(ab->dev, + pipe->status_ring->nentries * desc_sz + + CE_DESC_RING_ALIGN, +- pipe->status_ring->base_addr_owner_space, +- pipe->status_ring->base_addr_ce_space); ++ ce_ring->base_addr_owner_space_unaligned, ++ ce_ring->base_addr_ce_space_unaligned); + kfree(pipe->status_ring); + pipe->status_ring = NULL; + } diff --git a/package/kernel/mac80211/patches/ath11k/0071-ath11k-Fix-unused-but-set-parameter-error.patch b/package/kernel/mac80211/patches/ath11k/0071-ath11k-Fix-unused-but-set-parameter-error.patch new file mode 100644 index 000000000..7fb7011df --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0071-ath11k-Fix-unused-but-set-parameter-error.patch @@ -0,0 +1,30 @@ +From 624e0a3170309eeb5b729f7a43c1ba3234325f02 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Thu, 11 Nov 2021 11:22:47 +0530 +Subject: [PATCH] ath11k: Fix 'unused-but-set-parameter' error + +Below compilation error is reported when built with W=1, + +drivers/net/wireless/ath/ath11k/mac.c:5408:22: error: parameter 'changed_flags' set but not used [-Werror,-Wunused-but-set-parameter] + +changed_flags is set, but left unused. So, remove unnecessary set. +Compile tested only. + +Reported-by: kernel test robot +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636609967-5114-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5971,7 +5971,6 @@ static void ath11k_mac_op_configure_filt + + mutex_lock(&ar->conf_mutex); + +- changed_flags &= SUPPORTED_FILTERS; + *total_flags &= SUPPORTED_FILTERS; + ar->filter_flags = *total_flags; + diff --git a/package/kernel/mac80211/patches/ath11k/0072-ath11k-fix-firmware-crash-during-channel-switch.patch b/package/kernel/mac80211/patches/ath11k/0072-ath11k-fix-firmware-crash-during-channel-switch.patch new file mode 100644 index 000000000..02c3314b3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0072-ath11k-fix-firmware-crash-during-channel-switch.patch @@ -0,0 +1,65 @@ +From f187fe8e3bc65cc4d7b0916947e2d6cd65d9cd3a Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Thu, 11 Nov 2021 20:50:02 +0530 +Subject: [PATCH] ath11k: fix firmware crash during channel switch + +Currently the updated bandwidth for the peer will be configured +to the firmware after channel switch from the sta_rc_update_wk. +If the updated bandwidth is greater than the configured peer phymode +during the peer assoc may result firmware assert. + +For example, initially AP is in HE40 mode and the peer phymode is +configured as MODE_11AX_HE40 during peer assoc. Now user change the +channel width to HE80 then, the peer bandwidth will be updated as +HE80 to the firmware. + +This will trigger firmware assert due to peer bandwidth is greater than +the peer phymode. + +Fix this issue by sending peer assoc command before setting the updated +peer bandwith to firmware. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636644002-25446-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3930,11 +3930,27 @@ static void ath11k_sta_rc_update_wk(stru + ath11k_mac_max_he_nss(he_mcs_mask))); + + if (changed & IEEE80211_RC_BW_CHANGED) { +- err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, +- WMI_PEER_CHWIDTH, bw); +- if (err) +- ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", +- sta->addr, bw, err); ++ /* Send peer assoc command before set peer bandwidth param to ++ * avoid the mismatch between the peer phymode and the peer ++ * bandwidth. ++ */ ++ ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); ++ ++ peer_arg.is_assoc = false; ++ err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); ++ if (err) { ++ ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n", ++ sta->addr, arvif->vdev_id, err); ++ } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { ++ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, ++ WMI_PEER_CHWIDTH, bw); ++ if (err) ++ ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", ++ sta->addr, bw, err); ++ } else { ++ ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", ++ sta->addr, arvif->vdev_id); ++ } + } + + if (changed & IEEE80211_RC_NSS_CHANGED) { diff --git a/package/kernel/mac80211/patches/ath11k/0073-ath11k-disable-unused-CE8-interrupts-for-ipq8074.patch b/package/kernel/mac80211/patches/ath11k/0073-ath11k-disable-unused-CE8-interrupts-for-ipq8074.patch new file mode 100644 index 000000000..f05e91cad --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0073-ath11k-disable-unused-CE8-interrupts-for-ipq8074.patch @@ -0,0 +1,38 @@ +From 2c5545bfa29dd5305fa770959890a23ea39b5e69 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:01:18 +0200 +Subject: [PATCH] ath11k: disable unused CE8 interrupts for ipq8074 + +Host driver doesn't need to process CE8 interrupts (used +by target independently) + +The volume of interrupts is huge within short interval, + CPU0 CPU1 CPU2 CPU3 +14022188 0 0 0 GIC 71 Edge ce8 + +Hence disabling unused CE8 interrupt will improve CPU usage. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-2-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/ce.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -77,7 +77,7 @@ const struct ce_attr ath11k_host_ce_conf + + /* CE8: target autonomous hif_memcpy */ + { +- .flags = CE_ATTR_FLAGS, ++ .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, diff --git a/package/kernel/mac80211/patches/ath11k/0074-ath11k-allocate-dst-ring-descriptors-from-cacheable-.patch b/package/kernel/mac80211/patches/ath11k/0074-ath11k-allocate-dst-ring-descriptors-from-cacheable-.patch new file mode 100644 index 000000000..ea2c35daa --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0074-ath11k-allocate-dst-ring-descriptors-from-cacheable-.patch @@ -0,0 +1,227 @@ +From 6452f0a3d5651bb7edfd9c709e78973aaa4d3bfc Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:01:26 +0200 +Subject: [PATCH] ath11k: allocate dst ring descriptors from cacheable memory + +tcl_data and reo_dst rings are currently being allocated using +dma_allocate_coherent() which is non cacheable. + +Allocating ring memory from cacheable memory area allows cached descriptor +access and prefetch next descriptors to optimize CPU usage during +descriptor processing on NAPI. Based on the hardware param we can enable +or disable this feature for the corresponding platform. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Pradeep Kumar Chitrapu +Signed-off-by: Pradeep Kumar Chitrapu +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-3-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++++ + drivers/net/wireless/ath/ath11k/dp.c | 38 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/dp.h | 1 + + drivers/net/wireless/ath/ath11k/hal.c | 28 +++++++++++++++++-- + drivers/net/wireless/ath/ath11k/hal.h | 1 + + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 6 files changed, 67 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -84,6 +84,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = true, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -135,6 +136,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = true, + }, + { + .name = "qca6390 hw2.0", +@@ -185,6 +187,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -235,6 +238,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, ++ .alloc_cacheable_memory = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -285,6 +289,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -101,8 +101,11 @@ void ath11k_dp_srng_cleanup(struct ath11 + if (!ring->vaddr_unaligned) + return; + +- dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, +- ring->paddr_unaligned); ++ if (ring->cached) ++ kfree(ring->vaddr_unaligned); ++ else ++ dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, ++ ring->paddr_unaligned); + + ring->vaddr_unaligned = NULL; + } +@@ -222,6 +225,7 @@ int ath11k_dp_srng_setup(struct ath11k_b + int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); + int max_entries = ath11k_hal_srng_get_max_entries(ab, type); + int ret; ++ bool cached = false; + + if (max_entries < 0 || entry_sz < 0) + return -EINVAL; +@@ -230,9 +234,28 @@ int ath11k_dp_srng_setup(struct ath11k_b + num_entries = max_entries; + + ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1; +- ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, +- &ring->paddr_unaligned, +- GFP_KERNEL); ++ ++ if (ab->hw_params.alloc_cacheable_memory) { ++ /* Allocate the reo dst and tx completion rings from cacheable memory */ ++ switch (type) { ++ case HAL_REO_DST: ++ cached = true; ++ break; ++ default: ++ cached = false; ++ } ++ ++ if (cached) { ++ ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL); ++ ring->paddr_unaligned = virt_to_phys(ring->vaddr_unaligned); ++ } ++ } ++ ++ if (!cached) ++ ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, ++ &ring->paddr_unaligned, ++ GFP_KERNEL); ++ + if (!ring->vaddr_unaligned) + return -ENOMEM; + +@@ -292,6 +315,11 @@ int ath11k_dp_srng_setup(struct ath11k_b + return -EINVAL; + } + ++ if (cached) { ++ params.flags |= HAL_SRNG_FLAGS_CACHED; ++ ring->cached = 1; ++ } ++ + ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms); + if (ret < 0) { + ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -64,6 +64,7 @@ struct dp_srng { + dma_addr_t paddr; + int size; + u32 ring_id; ++ u8 cached; + }; + + struct dp_rxdma_ring { +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -627,6 +627,21 @@ u32 *ath11k_hal_srng_dst_peek(struct ath + return NULL; + } + ++static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab, ++ struct hal_srng *srng) ++{ ++ u32 *desc; ++ ++ /* prefetch only if desc is available */ ++ desc = ath11k_hal_srng_dst_peek(ab, srng); ++ if (likely(desc)) { ++ dma_sync_single_for_cpu(ab->dev, virt_to_phys(desc), ++ (srng->entry_size * sizeof(u32)), ++ DMA_FROM_DEVICE); ++ prefetch(desc); ++ } ++} ++ + u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab, + struct hal_srng *srng) + { +@@ -642,6 +657,10 @@ u32 *ath11k_hal_srng_dst_get_next_entry( + srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) % + srng->ring_size; + ++ /* Try to prefetch the next descriptor in the ring */ ++ if (srng->flags & HAL_SRNG_FLAGS_CACHED) ++ ath11k_hal_srng_prefetch_desc(ab, srng); ++ + return desc; + } + +@@ -775,11 +794,16 @@ void ath11k_hal_srng_access_begin(struct + { + lockdep_assert_held(&srng->lock); + +- if (srng->ring_dir == HAL_SRNG_DIR_SRC) ++ if (srng->ring_dir == HAL_SRNG_DIR_SRC) { + srng->u.src_ring.cached_tp = + *(volatile u32 *)srng->u.src_ring.tp_addr; +- else ++ } else { + srng->u.dst_ring.cached_hp = *srng->u.dst_ring.hp_addr; ++ ++ /* Try to prefetch the next descriptor in the ring */ ++ if (srng->flags & HAL_SRNG_FLAGS_CACHED) ++ ath11k_hal_srng_prefetch_desc(ab, srng); ++ } + } + + /* Update cached ring head/tail pointers to HW. ath11k_hal_srng_access_begin() +--- a/drivers/net/wireless/ath/ath11k/hal.h ++++ b/drivers/net/wireless/ath/ath11k/hal.h +@@ -513,6 +513,7 @@ enum hal_srng_dir { + #define HAL_SRNG_FLAGS_DATA_TLV_SWAP 0x00000020 + #define HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN 0x00010000 + #define HAL_SRNG_FLAGS_MSI_INTR 0x00020000 ++#define HAL_SRNG_FLAGS_CACHED 0x20000000 + #define HAL_SRNG_FLAGS_LMAC_RING 0x80000000 + + #define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1) +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -178,6 +178,7 @@ struct ath11k_hw_params { + u8 max_tx_ring; + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; ++ bool alloc_cacheable_memory; + }; + + struct ath11k_hw_ops { diff --git a/package/kernel/mac80211/patches/ath11k/0075-ath11k-modify-dp_rx-desc-access-wrapper-calls-inline.patch b/package/kernel/mac80211/patches/ath11k/0075-ath11k-modify-dp_rx-desc-access-wrapper-calls-inline.patch new file mode 100644 index 000000000..9a610f9b8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0075-ath11k-modify-dp_rx-desc-access-wrapper-calls-inline.patch @@ -0,0 +1,285 @@ +From 5e76fe03dbf9f9dbc4fd454283b02594226c0718 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:03 +0200 +Subject: [PATCH] ath11k: modify dp_rx desc access wrapper calls inline + +In data path, to reduce the CPU cycles spending on descriptor access +wrapper function, changed those functions as static inline. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-4-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 114 ++++++++++++------------ + 1 file changed, 59 insertions(+), 55 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -20,13 +20,15 @@ + + #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) + +-static u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) ++static inline ++u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_hdr_status(desc); + } + +-static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline ++enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + if (!ab->hw_params.hw_ops->rx_desc_encrypt_valid(desc)) + return HAL_ENCRYPT_TYPE_OPEN; +@@ -34,32 +36,34 @@ static enum hal_encrypt_type ath11k_dp_r + return ab->hw_params.hw_ops->rx_desc_get_encrypt_type(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_decap_type(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline ++u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mesh_ctl(desc); + } + +-static bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline ++bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); + } + +-static bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_fc_valid(desc); + } + +-static bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, +- struct sk_buff *skb) ++static inline bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, ++ struct sk_buff *skb) + { + struct ieee80211_hdr *hdr; + +@@ -67,8 +71,8 @@ static bool ath11k_dp_rx_h_mpdu_start_mo + return ieee80211_has_morefrags(hdr->frame_control); + } + +-static u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, +- struct sk_buff *skb) ++static inline u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, ++ struct sk_buff *skb) + { + struct ieee80211_hdr *hdr; + +@@ -76,37 +80,37 @@ static u16 ath11k_dp_rx_h_mpdu_start_fra + return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + } + +-static u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_start_seq_no(desc); + } + +-static void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_attention(desc); + } + +-static bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) + { + return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE, + __le32_to_cpu(attn->info2)); + } + +-static bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) + { + return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL, + __le32_to_cpu(attn->info1)); + } + +-static bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) + { + return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL, + __le32_to_cpu(attn->info1)); + } + +-static bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) + { + return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE, + __le32_to_cpu(attn->info2)) == +@@ -154,68 +158,68 @@ static bool ath11k_dp_rx_h_attn_msdu_len + return errmap & DP_RX_MPDU_ERR_MSDU_LEN; + } + +-static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_len(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_sgi(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_rate_mcs(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_rx_bw(desc); + } + +-static u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_freq(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_pkt_type(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return hweight8(ab->hw_params.hw_ops->rx_desc_get_msdu_nss(desc)); + } + +-static u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_tid(desc); + } + +-static u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_peer_id(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_l3_pad_bytes(desc); + } + +-static bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_first_msdu(desc); + } +@@ -233,14 +237,14 @@ static void ath11k_dp_rx_desc_end_tlv_co + ab->hw_params.hw_ops->rx_desc_copy_attn_end_tlv(fdesc, ldesc); + } + +-static u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) ++static inline u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) + { + return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR, + __le32_to_cpu(attn->info1)); + } + +-static u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, +- struct hal_rx_desc *rx_desc) ++static inline u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, ++ struct hal_rx_desc *rx_desc) + { + u8 *rx_pkt_hdr; + +@@ -249,8 +253,8 @@ static u8 *ath11k_dp_rxdesc_get_80211hdr + return rx_pkt_hdr; + } + +-static bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, +- struct hal_rx_desc *rx_desc) ++static inline bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *rx_desc) + { + u32 tlv_tag; + +@@ -259,15 +263,15 @@ static bool ath11k_dp_rxdesc_mpdu_valid( + return tlv_tag == HAL_RX_MPDU_START; + } + +-static u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, +- struct hal_rx_desc *rx_desc) ++static inline u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, ++ struct hal_rx_desc *rx_desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_ppdu_id(rx_desc); + } + +-static void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, +- struct hal_rx_desc *desc, +- u16 len) ++static inline void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, ++ struct hal_rx_desc *desc, ++ u16 len) + { + ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len); + } diff --git a/package/kernel/mac80211/patches/ath11k/0076-ath11k-avoid-additional-access-to-ath11k_hal_srng_ds.patch b/package/kernel/mac80211/patches/ath11k/0076-ath11k-avoid-additional-access-to-ath11k_hal_srng_ds.patch new file mode 100644 index 000000000..d8a5b30eb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0076-ath11k-avoid-additional-access-to-ath11k_hal_srng_ds.patch @@ -0,0 +1,55 @@ +From a1775e732eb90486519de3813b83a11b7fcee2d0 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:12 +0200 +Subject: [PATCH] ath11k: avoid additional access to + ath11k_hal_srng_dst_num_free + +In ath11k_dp_process_rx(), after processing rx_desc from +ath11k_hal_srng_dst_get_next_entry(), ath11k_hal_srng_dst_num_free() +is accessed everytime because of done flag is not set. + +To avoid this additional access to ath11k_hal_srng_dst_num_free(), +increment total_msdu_reaped only when continuation is not set and +update done flag correspondingly. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-5-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2701,7 +2701,6 @@ try_again: + DMA_FROM_DEVICE); + + num_buffs_reaped[mac_id]++; +- total_msdu_reaped++; + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, + desc.info0); +@@ -2728,10 +2727,15 @@ try_again: + rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list, msdu); + +- if (total_msdu_reaped >= quota && !rxcb->is_continuation) { ++ if (rxcb->is_continuation) { ++ done = false; ++ } else { ++ total_msdu_reaped++; + done = true; +- break; + } ++ ++ if (total_msdu_reaped >= budget) ++ break; + } + + /* Hw might have updated the head pointer after we cached it. diff --git a/package/kernel/mac80211/patches/ath11k/0077-ath11k-avoid-active-pdev-check-for-each-msdu.patch b/package/kernel/mac80211/patches/ath11k/0077-ath11k-avoid-active-pdev-check-for-each-msdu.patch new file mode 100644 index 000000000..16ca89400 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0077-ath11k-avoid-active-pdev-check-for-each-msdu.patch @@ -0,0 +1,174 @@ +From c4d12cb37ea2e6c2b70880350d7bf1bbbd825c6c Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:18 +0200 +Subject: [PATCH] ath11k: avoid active pdev check for each msdu + +The Active Pdev and CAC check are done for each msdu in +ath11k_dp_rx_process_received_packets which is a overhead. +To avoid this overhead, collect all msdus in a per mac msdu +list and pass to function. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-6-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 70 ++++++++++++------------- + 1 file changed, 34 insertions(+), 36 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2600,13 +2600,11 @@ free_out: + static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, + struct napi_struct *napi, + struct sk_buff_head *msdu_list, +- int *quota, int ring_id) ++ int *quota, int mac_id) + { +- struct ath11k_skb_rxcb *rxcb; + struct sk_buff *msdu; + struct ath11k *ar; + struct ieee80211_rx_status rx_status = {0}; +- u8 mac_id; + int ret; + + if (skb_queue_empty(msdu_list)) +@@ -2614,20 +2612,20 @@ static void ath11k_dp_rx_process_receive + + rcu_read_lock(); + +- while (*quota && (msdu = __skb_dequeue(msdu_list))) { +- rxcb = ATH11K_SKB_RXCB(msdu); +- mac_id = rxcb->mac_id; +- ar = ab->pdevs[mac_id].ar; +- if (!rcu_dereference(ab->pdevs_active[mac_id])) { +- dev_kfree_skb_any(msdu); +- continue; +- } ++ ar = ab->pdevs[mac_id].ar; ++ if (!rcu_dereference(ab->pdevs_active[mac_id])) { ++ __skb_queue_purge(msdu_list); ++ rcu_read_unlock(); ++ return; ++ } + +- if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { +- dev_kfree_skb_any(msdu); +- continue; +- } ++ if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { ++ __skb_queue_purge(msdu_list); ++ rcu_read_unlock(); ++ return; ++ } + ++ while ((msdu = __skb_dequeue(msdu_list))) { + ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_DATA, +@@ -2649,7 +2647,7 @@ int ath11k_dp_process_rx(struct ath11k_b + struct ath11k_dp *dp = &ab->dp; + struct dp_rxdma_ring *rx_ring; + int num_buffs_reaped[MAX_RADIOS] = {0}; +- struct sk_buff_head msdu_list; ++ struct sk_buff_head msdu_list[MAX_RADIOS]; + struct ath11k_skb_rxcb *rxcb; + int total_msdu_reaped = 0; + struct hal_srng *srng; +@@ -2658,10 +2656,13 @@ int ath11k_dp_process_rx(struct ath11k_b + bool done = false; + int buf_id, mac_id; + struct ath11k *ar; +- u32 *rx_desc; ++ struct hal_reo_dest_ring *desc; ++ enum hal_reo_dest_ring_push_reason push_reason; ++ u32 cookie; + int i; + +- __skb_queue_head_init(&msdu_list); ++ for (i = 0; i < MAX_RADIOS; i++) ++ __skb_queue_head_init(&msdu_list[i]); + + srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; + +@@ -2670,13 +2671,11 @@ int ath11k_dp_process_rx(struct ath11k_b + ath11k_hal_srng_access_begin(ab, srng); + + try_again: +- while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { +- struct hal_reo_dest_ring desc = *(struct hal_reo_dest_ring *)rx_desc; +- enum hal_reo_dest_ring_push_reason push_reason; +- u32 cookie; +- ++ while (likely(desc = ++ (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, ++ srng))) { + cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, +- desc.buf_addr_info.info1); ++ desc->buf_addr_info.info1); + buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, + cookie); + mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); +@@ -2703,7 +2702,7 @@ try_again: + num_buffs_reaped[mac_id]++; + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, +- desc.info0); ++ desc->info0); + if (push_reason != + HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { + dev_kfree_skb_any(msdu); +@@ -2711,21 +2710,21 @@ try_again: + continue; + } + +- rxcb->is_first_msdu = !!(desc.rx_msdu_info.info0 & ++ rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); +- rxcb->is_last_msdu = !!(desc.rx_msdu_info.info0 & ++ rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); +- rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & ++ rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); + rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, +- desc.rx_mpdu_info.meta_data); ++ desc->rx_mpdu_info.meta_data); + rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, +- desc.rx_mpdu_info.info0); ++ desc->rx_mpdu_info.info0); + rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, +- desc.info0); ++ desc->info0); + + rxcb->mac_id = mac_id; +- __skb_queue_tail(&msdu_list, msdu); ++ __skb_queue_tail(&msdu_list[mac_id], msdu); + + if (rxcb->is_continuation) { + done = false; +@@ -2760,16 +2759,15 @@ try_again: + if (!num_buffs_reaped[i]) + continue; + ++ ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], ++ "a, i); ++ + ar = ab->pdevs[i].ar; + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], + ab->hw_params.hal_params->rx_buf_rbm); + } +- +- ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, +- "a, ring_id); +- + exit: + return budget - quota; + } diff --git a/package/kernel/mac80211/patches/ath11k/0078-ath11k-remove-usage-quota-while-processing-rx-packet.patch b/package/kernel/mac80211/patches/ath11k/0078-ath11k-remove-usage-quota-while-processing-rx-packet.patch new file mode 100644 index 000000000..80a610349 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0078-ath11k-remove-usage-quota-while-processing-rx-packet.patch @@ -0,0 +1,69 @@ +From db2ecf9f0567a8f1a96f23a392cc5a30eaec4369 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:24 +0200 +Subject: [PATCH] ath11k: remove usage quota while processing rx packets + +The usage of quota variable inside ath11k_dp_rx_process_received_packets() +is redundant. Since we would queue only max packets to the list before +calling this function so it would never exceed quota. Hence removing +usage of quota variable. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-7-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2600,7 +2600,7 @@ free_out: + static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, + struct napi_struct *napi, + struct sk_buff_head *msdu_list, +- int *quota, int mac_id) ++ int mac_id) + { + struct sk_buff *msdu; + struct ath11k *ar; +@@ -2635,7 +2635,6 @@ static void ath11k_dp_rx_process_receive + } + + ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); +- (*quota)--; + } + + rcu_read_unlock(); +@@ -2652,7 +2651,6 @@ int ath11k_dp_process_rx(struct ath11k_b + int total_msdu_reaped = 0; + struct hal_srng *srng; + struct sk_buff *msdu; +- int quota = budget; + bool done = false; + int buf_id, mac_id; + struct ath11k *ar; +@@ -2759,8 +2757,7 @@ try_again: + if (!num_buffs_reaped[i]) + continue; + +- ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], +- "a, i); ++ ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], i); + + ar = ab->pdevs[i].ar; + rx_ring = &ar->dp.rx_refill_buf_ring; +@@ -2769,7 +2766,7 @@ try_again: + ab->hw_params.hal_params->rx_buf_rbm); + } + exit: +- return budget - quota; ++ return total_msdu_reaped; + } + + static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta, diff --git a/package/kernel/mac80211/patches/ath11k/0079-ath11k-add-branch-predictors-in-process_rx.patch b/package/kernel/mac80211/patches/ath11k/0079-ath11k-add-branch-predictors-in-process_rx.patch new file mode 100644 index 000000000..ca2c55540 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0079-ath11k-add-branch-predictors-in-process_rx.patch @@ -0,0 +1,102 @@ +From 400588039a17a460292eb974ebba5811b8cbdb91 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:31 +0200 +Subject: [PATCH] ath11k: add branch predictors in process_rx + +In datapath, add branch predictors where required in the process rx(). +This protects high value rx path without having performance overhead. +Also while processing rx packets, the pointer that is returned by +rcu_dereference() is not dereferenced. so it is preferable to use +rcu_access_pointer() here. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-8-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2610,24 +2610,20 @@ static void ath11k_dp_rx_process_receive + if (skb_queue_empty(msdu_list)) + return; + +- rcu_read_lock(); +- +- ar = ab->pdevs[mac_id].ar; +- if (!rcu_dereference(ab->pdevs_active[mac_id])) { ++ if (unlikely(!rcu_access_pointer(ab->pdevs_active[mac_id]))) { + __skb_queue_purge(msdu_list); +- rcu_read_unlock(); + return; + } + +- if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { ++ ar = ab->pdevs[mac_id].ar; ++ if (unlikely(test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags))) { + __skb_queue_purge(msdu_list); +- rcu_read_unlock(); + return; + } + + while ((msdu = __skb_dequeue(msdu_list))) { + ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); +- if (ret) { ++ if (unlikely(ret)) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "Unable to process msdu %d", ret); + dev_kfree_skb_any(msdu); +@@ -2636,8 +2632,6 @@ static void ath11k_dp_rx_process_receive + + ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); + } +- +- rcu_read_unlock(); + } + + int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, +@@ -2682,7 +2676,7 @@ try_again: + rx_ring = &ar->dp.rx_refill_buf_ring; + spin_lock_bh(&rx_ring->idr_lock); + msdu = idr_find(&rx_ring->bufs_idr, buf_id); +- if (!msdu) { ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "frame rx with invalid buf_id %d\n", + buf_id); + spin_unlock_bh(&rx_ring->idr_lock); +@@ -2701,8 +2695,8 @@ try_again: + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, + desc->info0); +- if (push_reason != +- HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { ++ if (unlikely(push_reason != ++ HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { + dev_kfree_skb_any(msdu); + ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; + continue; +@@ -2741,7 +2735,7 @@ try_again: + * head pointer so that we can reap complete MPDU in the current + * rx processing. + */ +- if (!done && ath11k_hal_srng_dst_num_free(ab, srng, true)) { ++ if (unlikely(!done && ath11k_hal_srng_dst_num_free(ab, srng, true))) { + ath11k_hal_srng_access_end(ab, srng); + goto try_again; + } +@@ -2750,7 +2744,7 @@ try_again: + + spin_unlock_bh(&srng->lock); + +- if (!total_msdu_reaped) ++ if (unlikely(!total_msdu_reaped)) + goto exit; + + for (i = 0; i < ab->num_radios; i++) { diff --git a/package/kernel/mac80211/patches/ath11k/0080-ath11k-allocate-HAL_WBM2SW_RELEASE-ring-from-cacheab.patch b/package/kernel/mac80211/patches/ath11k/0080-ath11k-allocate-HAL_WBM2SW_RELEASE-ring-from-cacheab.patch new file mode 100644 index 000000000..f1c0513cf --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0080-ath11k-allocate-HAL_WBM2SW_RELEASE-ring-from-cacheab.patch @@ -0,0 +1,32 @@ +From d0e2523bfa9cb391fe966b0b6948c7e438981361 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:38 +0200 +Subject: [PATCH] ath11k: allocate HAL_WBM2SW_RELEASE ring from cacheable + memory + +Similar to REO destination ring, also allocate HAL_WBM2SW_RELEASE +from cacheable memory so that descriptors could be prefetched during +tx completion handling. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-9-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -239,6 +239,7 @@ int ath11k_dp_srng_setup(struct ath11k_b + /* Allocate the reo dst and tx completion rings from cacheable memory */ + switch (type) { + case HAL_REO_DST: ++ case HAL_WBM2SW_RELEASE: + cached = true; + break; + default: diff --git a/package/kernel/mac80211/patches/ath11k/0081-ath11k-remove-mod-operator-in-dst-ring-processing.patch b/package/kernel/mac80211/patches/ath11k/0081-ath11k-remove-mod-operator-in-dst-ring-processing.patch new file mode 100644 index 000000000..b00a73a1c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0081-ath11k-remove-mod-operator-in-dst-ring-processing.patch @@ -0,0 +1,36 @@ +From a8508bf7ced2e43f30b46333f09cbc79a1675616 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:45 +0200 +Subject: [PATCH] ath11k: remove mod operator in dst ring processing + +Replace use of mod operator with a manual wrap around +to avoid additional cost of using mod operation. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-10-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/hal.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -654,8 +654,11 @@ u32 *ath11k_hal_srng_dst_get_next_entry( + + desc = srng->ring_base_vaddr + srng->u.dst_ring.tp; + +- srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) % +- srng->ring_size; ++ srng->u.dst_ring.tp += srng->entry_size; ++ ++ /* wrap around to start of ring*/ ++ if (srng->u.dst_ring.tp == srng->ring_size) ++ srng->u.dst_ring.tp = 0; + + /* Try to prefetch the next descriptor in the ring */ + if (srng->flags & HAL_SRNG_FLAGS_CACHED) diff --git a/package/kernel/mac80211/patches/ath11k/0082-ath11k-avoid-while-loop-in-ring-selection-of-tx-comp.patch b/package/kernel/mac80211/patches/ath11k/0082-ath11k-avoid-while-loop-in-ring-selection-of-tx-comp.patch new file mode 100644 index 000000000..dae9e00c3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0082-ath11k-avoid-while-loop-in-ring-selection-of-tx-comp.patch @@ -0,0 +1,43 @@ +From cbfbed495d3289d5a0bc7c614cea639008086cfe Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:05:58 +0200 +Subject: [PATCH] ath11k: avoid while loop in ring selection of tx completion + interrupt + +Currently while loop is used to find the tx completion ring number and +it is not required since the tx ring mask and the group id can be combined +to directly fetch the ring number. Hence remove the while loop +and directly get the ring number from tx mask and group id. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-11-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -771,13 +771,12 @@ int ath11k_dp_service_srng(struct ath11k + const struct ath11k_hw_hal_params *hal_params; + int grp_id = irq_grp->grp_id; + int work_done = 0; +- int i = 0, j; ++ int i, j; + int tot_work_done = 0; + +- while (ab->hw_params.ring_mask->tx[grp_id] >> i) { +- if (ab->hw_params.ring_mask->tx[grp_id] & BIT(i)) +- ath11k_dp_tx_completion_handler(ab, i); +- i++; ++ if (ab->hw_params.ring_mask->tx[grp_id]) { ++ i = __fls(ab->hw_params.ring_mask->tx[grp_id]); ++ ath11k_dp_tx_completion_handler(ab, i); + } + + if (ab->hw_params.ring_mask->rx_err[grp_id]) { diff --git a/package/kernel/mac80211/patches/ath11k/0083-ath11k-add-branch-predictors-in-dp_tx-path.patch b/package/kernel/mac80211/patches/ath11k/0083-ath11k-add-branch-predictors-in-dp_tx-path.patch new file mode 100644 index 000000000..e09322f8a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0083-ath11k-add-branch-predictors-in-dp_tx-path.patch @@ -0,0 +1,201 @@ +From bcef57ea400cc20a5389fa0e38d61063331558f8 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:06:04 +0200 +Subject: [PATCH] ath11k: add branch predictors in dp_tx path + +Add branch prediction in dp_tx code path in tx and tx completion handlers. +Also in ath11k_dp_tx_complete_msdu , the pointer that is returned by +rcu_dereference() is not dereferenced. so it is preferable to use +rcu_access_pointer() here. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-12-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 52 ++++++++++++------------- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 2 files changed, 25 insertions(+), 29 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -95,11 +95,11 @@ int ath11k_dp_tx(struct ath11k *ar, stru + u8 ring_selector = 0, ring_map = 0; + bool tcl_ring_retry; + +- if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) ++ if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))) + return -ESHUTDOWN; + +- if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && +- !ieee80211_is_data(hdr->frame_control)) ++ if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && ++ !ieee80211_is_data(hdr->frame_control))) + return -ENOTSUPP; + + pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); +@@ -127,7 +127,7 @@ tcl_ring_sel: + DP_TX_IDR_SIZE - 1, GFP_ATOMIC); + spin_unlock_bh(&tx_ring->tx_idr_lock); + +- if (ret < 0) { ++ if (unlikely(ret < 0)) { + if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1)) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + return -ENOSPC; +@@ -152,7 +152,7 @@ tcl_ring_sel: + ti.meta_data_flags = arvif->tcl_metadata; + } + +- if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { ++ if (unlikely(ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW)) { + if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { + ti.encrypt_type = + ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); +@@ -173,8 +173,8 @@ tcl_ring_sel: + ti.bss_ast_idx = arvif->ast_idx; + ti.dscp_tid_tbl_idx = 0; + +- if (skb->ip_summed == CHECKSUM_PARTIAL && +- ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) { ++ if (likely(skb->ip_summed == CHECKSUM_PARTIAL && ++ ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW)) { + ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) | +@@ -211,7 +211,7 @@ tcl_ring_sel: + } + + ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); +- if (dma_mapping_error(ab->dev, ti.paddr)) { ++ if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + ath11k_warn(ab, "failed to DMA map data Tx buffer\n"); + ret = -ENOMEM; +@@ -231,7 +231,7 @@ tcl_ring_sel: + ath11k_hal_srng_access_begin(ab, tcl_ring); + + hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring); +- if (!hal_tcl_desc) { ++ if (unlikely(!hal_tcl_desc)) { + /* NOTE: It is highly unlikely we'll be running out of tcl_ring + * desc because the desc is directly enqueued onto hw queue. + */ +@@ -245,7 +245,7 @@ tcl_ring_sel: + * checking this ring earlier for each pkt tx. + * Restart ring selection if some rings are not checked yet. + */ +- if (ring_map != (BIT(ab->hw_params.max_tx_ring) - 1) && ++ if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) && + ab->hw_params.max_tx_ring > 1) { + tcl_ring_retry = true; + ring_selector++; +@@ -327,7 +327,7 @@ ath11k_dp_tx_htt_tx_complete_buf(struct + + spin_lock_bh(&tx_ring->tx_idr_lock); + msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id); +- if (!msdu) { ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n", + ts->msdu_id); + spin_unlock_bh(&tx_ring->tx_idr_lock); +@@ -435,16 +435,14 @@ static void ath11k_dp_tx_complete_msdu(s + + dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + +- rcu_read_lock(); +- +- if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) { ++ if (unlikely(!rcu_access_pointer(ab->pdevs_active[ar->pdev_idx]))) { + dev_kfree_skb_any(msdu); +- goto exit; ++ return; + } + +- if (!skb_cb->vif) { ++ if (unlikely(!skb_cb->vif)) { + dev_kfree_skb_any(msdu); +- goto exit; ++ return; + } + + info = IEEE80211_SKB_CB(msdu); +@@ -465,7 +463,7 @@ static void ath11k_dp_tx_complete_msdu(s + (info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + +- if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) { ++ if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) { + if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) { + if (ar->last_ppdu_id == 0) { + ar->last_ppdu_id = ts->ppdu_id; +@@ -494,9 +492,6 @@ static void ath11k_dp_tx_complete_msdu(s + */ + + ieee80211_tx_status(ar->hw, msdu); +- +-exit: +- rcu_read_unlock(); + } + + static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, +@@ -505,11 +500,11 @@ static inline void ath11k_dp_tx_status_p + { + ts->buf_rel_source = + FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0); +- if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && +- ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) ++ if (unlikely(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && ++ ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) + return; + +- if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) ++ if (unlikely(ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) + return; + + ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, +@@ -556,8 +551,9 @@ void ath11k_dp_tx_completion_handler(str + ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head); + } + +- if ((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && +- (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { ++ if (unlikely((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && ++ (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == ++ tx_ring->tx_status_tail))) { + /* TODO: Process pending tx_status messages when kfifo_is_full() */ + ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); + } +@@ -580,7 +576,7 @@ void ath11k_dp_tx_completion_handler(str + mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id); + msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id); + +- if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) { ++ if (unlikely(ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) { + ath11k_dp_tx_process_htt_tx_complete(ab, + (void *)tx_status, + mac_id, msdu_id, +@@ -590,7 +586,7 @@ void ath11k_dp_tx_completion_handler(str + + spin_lock_bh(&tx_ring->tx_idr_lock); + msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); +- if (!msdu) { ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); + spin_unlock_bh(&tx_ring->tx_idr_lock); +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5293,7 +5293,7 @@ static void ath11k_mac_op_tx(struct ieee + arsta = (struct ath11k_sta *)control->sta->drv_priv; + + ret = ath11k_dp_tx(ar, arvif, arsta, skb); +- if (ret) { ++ if (unlikely(ret)) { + ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret); + ieee80211_free_txskb(ar->hw, skb); + } diff --git a/package/kernel/mac80211/patches/ath11k/0084-ath11k-avoid-unnecessary-lock-contention-in-tx_compl.patch b/package/kernel/mac80211/patches/ath11k/0084-ath11k-avoid-unnecessary-lock-contention-in-tx_compl.patch new file mode 100644 index 000000000..7eb791212 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0084-ath11k-avoid-unnecessary-lock-contention-in-tx_compl.patch @@ -0,0 +1,102 @@ +From be8867cb47652418e488170785bd9ffbadae3f1f Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:06:11 +0200 +Subject: [PATCH] ath11k: avoid unnecessary lock contention in tx_completion + path + +Avoid unnecessary idr_find calls before the idr_remove calls. Because +idr_remove gives the valid ptr if id is valid otherwise return NULL ptr. +So removed the idr_find before idr_remove in tx completion path. Also no +need to disable the bottom half preempt if it is already in the +bottom half context, so modify the spin_lock_bh to spin_lock in the +data tx completion path. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Karthikeyan Periyasamy +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-13-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 32 +++++++++++-------------- + 1 file changed, 14 insertions(+), 18 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -293,20 +293,18 @@ static void ath11k_dp_tx_free_txbuf(stru + struct sk_buff *msdu; + struct ath11k_skb_cb *skb_cb; + +- spin_lock_bh(&tx_ring->tx_idr_lock); +- msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); +- if (!msdu) { ++ spin_lock(&tx_ring->tx_idr_lock); ++ msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); ++ spin_unlock(&tx_ring->tx_idr_lock); ++ ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); + return; + } + + skb_cb = ATH11K_SKB_CB(msdu); + +- idr_remove(&tx_ring->txbuf_idr, msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); +- + dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + dev_kfree_skb_any(msdu); + +@@ -325,12 +323,13 @@ ath11k_dp_tx_htt_tx_complete_buf(struct + struct ath11k_skb_cb *skb_cb; + struct ath11k *ar; + +- spin_lock_bh(&tx_ring->tx_idr_lock); +- msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id); ++ spin_lock(&tx_ring->tx_idr_lock); ++ msdu = idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); ++ spin_unlock(&tx_ring->tx_idr_lock); ++ + if (unlikely(!msdu)) { + ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n", + ts->msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); + return; + } + +@@ -339,9 +338,6 @@ ath11k_dp_tx_htt_tx_complete_buf(struct + + ar = skb_cb->ar; + +- idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); +- + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); + +@@ -584,16 +580,16 @@ void ath11k_dp_tx_completion_handler(str + continue; + } + +- spin_lock_bh(&tx_ring->tx_idr_lock); +- msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); ++ spin_lock(&tx_ring->tx_idr_lock); ++ msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); + if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); ++ spin_unlock(&tx_ring->tx_idr_lock); + continue; + } +- idr_remove(&tx_ring->txbuf_idr, msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); ++ ++ spin_unlock(&tx_ring->tx_idr_lock); + + ar = ab->pdevs[mac_id].ar; + diff --git a/package/kernel/mac80211/patches/ath11k/0085-ath11k-enable-IEEE80211_VHT_EXT_NSS_BW_CAPABLE-if-NS.patch b/package/kernel/mac80211/patches/ath11k/0085-ath11k-enable-IEEE80211_VHT_EXT_NSS_BW_CAPABLE-if-NS.patch new file mode 100644 index 000000000..036779d5d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0085-ath11k-enable-IEEE80211_VHT_EXT_NSS_BW_CAPABLE-if-NS.patch @@ -0,0 +1,48 @@ +From 78406044bdd0cc8987bc082b76867c63ab1c6af8 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 13 Oct 2021 03:37:04 -0400 +Subject: [PATCH] ath11k: enable IEEE80211_VHT_EXT_NSS_BW_CAPABLE if NSS ratio + enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When NSS ratio enabled reported by firmware, SUPPORTS_VHT_EXT_NSS_BW +is set in ath11k, meanwhile IEEE80211_VHT_EXT_NSS_BW_CAPABLE also +need to be set, otherwise it is invalid because spec in IEEE Std +802.11™‐2020 as below. + +Table 9-273-Supported VHT-MCS and NSS Set subfields, it has subfield +VHT Extended NSS BW Capable, its definition is: +Indicates whether the STA is capable of interpreting the Extended NSS +BW Support subfield of the VHT Capabilities Information field. + +dmesg have a message without this patch: + +ieee80211 phy0: copying sband (band 1) due to VHT EXT NSS BW flag + +It means mac80211 will set IEEE80211_VHT_EXT_NSS_BW_CAPABLE if ath11k not +set it in ieee80211_register_hw(). So it is better to set it in ath11k. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211013073704.15888-1-wgong@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4712,6 +4712,10 @@ ath11k_create_vht_cap(struct ath11k *ar, + vht_cap.vht_supported = 1; + vht_cap.cap = ar->pdev->cap.vht_cap; + ++ if (ar->pdev->cap.nss_ratio_enabled) ++ vht_cap.vht_mcs.tx_highest |= ++ cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); ++ + ath11k_set_vht_txbf_cap(ar, &vht_cap.cap); + + rxmcs_map = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0086-ath11k-remove-return-for-empty-tx-bitrate-in-mac_op_.patch b/package/kernel/mac80211/patches/ath11k/0086-ath11k-remove-return-for-empty-tx-bitrate-in-mac_op_.patch new file mode 100644 index 000000000..69991617f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0086-ath11k-remove-return-for-empty-tx-bitrate-in-mac_op_.patch @@ -0,0 +1,66 @@ +From 1d795645e1eef97fe5d409e3dd5747a942f00e08 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 11 Oct 2021 04:49:57 -0400 +Subject: [PATCH] ath11k: remove return for empty tx bitrate in + mac_op_sta_statistics + +Currently in ath11k_mac_op_sta_statistics() there is the following +logic: + + if (!arsta->txrate.legacy && !arsta->txrate.nss) + return; + +Unfortunately if this condition is true then the function returns without +setting parameters that follow the txrate. To address this issue remove the +return and instead invert the logic to set the txrate logic if +(arsta->txrate.legacy || arsta->txrate.nss). + +The same was done also in ath10k in commit 1cd6ba8ae33e ("ath10k: remove return +for NL80211_STA_INFO_TX_BITRATE"). + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211011084957.31024-1-wgong@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 29 +++++++++++++-------------- + 1 file changed, 14 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7436,21 +7436,20 @@ static void ath11k_mac_op_sta_statistics + sinfo->tx_duration = arsta->tx_duration; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); + +- if (!arsta->txrate.legacy && !arsta->txrate.nss) +- return; +- +- if (arsta->txrate.legacy) { +- sinfo->txrate.legacy = arsta->txrate.legacy; +- } else { +- sinfo->txrate.mcs = arsta->txrate.mcs; +- sinfo->txrate.nss = arsta->txrate.nss; +- sinfo->txrate.bw = arsta->txrate.bw; +- sinfo->txrate.he_gi = arsta->txrate.he_gi; +- sinfo->txrate.he_dcm = arsta->txrate.he_dcm; +- sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; ++ if (arsta->txrate.legacy || arsta->txrate.nss) { ++ if (arsta->txrate.legacy) { ++ sinfo->txrate.legacy = arsta->txrate.legacy; ++ } else { ++ sinfo->txrate.mcs = arsta->txrate.mcs; ++ sinfo->txrate.nss = arsta->txrate.nss; ++ sinfo->txrate.bw = arsta->txrate.bw; ++ sinfo->txrate.he_gi = arsta->txrate.he_gi; ++ sinfo->txrate.he_dcm = arsta->txrate.he_dcm; ++ sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; ++ } ++ sinfo->txrate.flags = arsta->txrate.flags; ++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + } +- sinfo->txrate.flags = arsta->txrate.flags; +- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + + /* TODO: Use real NF instead of default one. */ + sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; diff --git a/package/kernel/mac80211/patches/ath11k/0087-ath11k-fix-the-value-of-msecs_to_jiffies-in-ath11k_d.patch b/package/kernel/mac80211/patches/ath11k/0087-ath11k-fix-the-value-of-msecs_to_jiffies-in-ath11k_d.patch new file mode 100644 index 000000000..de1e350a2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0087-ath11k-fix-the-value-of-msecs_to_jiffies-in-ath11k_d.patch @@ -0,0 +1,28 @@ +From c8f2d41bbff6794329d681d108a817366aed0ba7 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 25 Oct 2021 23:20:14 -0400 +Subject: [PATCH] ath11k: fix the value of msecs_to_jiffies in + ath11k_debugfs_fw_stats_request + +parameter of msecs_to_jiffies should be (3 * 1000) instead of (3 * HZ) + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026032014.27010-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -195,7 +195,7 @@ static int ath11k_debugfs_fw_stats_reque + * received 'update stats' event, we keep a 3 seconds timeout in case, + * fw_stats_done is not marked yet + */ +- timeout = jiffies + msecs_to_jiffies(3 * HZ); ++ timeout = jiffies + msecs_to_jiffies(3 * 1000); + + ath11k_debugfs_fw_stats_reset(ar); + diff --git a/package/kernel/mac80211/patches/ath11k/0088-ath11k-move-peer-delete-after-vdev-stop-of-station-f.patch b/package/kernel/mac80211/patches/ath11k/0088-ath11k-move-peer-delete-after-vdev-stop-of-station-f.patch new file mode 100644 index 000000000..2cbc69a4a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0088-ath11k-move-peer-delete-after-vdev-stop-of-station-f.patch @@ -0,0 +1,89 @@ +From b4a0f54156ac7720de1750b6ea06657c91c52163 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 27 Oct 2021 05:38:25 -0400 +Subject: [PATCH] ath11k: move peer delete after vdev stop of station for + QCA6390 and WCN6855 + +When station connect to AP, the wmi command sequence is: + +peer_create->vdev_start->vdev_up + +and sequence of station disconnect fo AP is: + +peer_delete->vdev_down->vdev_stop + +The sequence of disconnect is not opposite of connect, it caused firmware +crash when it handle wmi vdev stop cmd when the AP is support TWT of +802.11 ax, because firmware need access the bss peer for vdev stop cmd. + +[ 390.438564] ath11k_pci 0000:05:00.0: wmi cmd send 0x6001 ret 0 +[ 390.438567] ath11k_pci 0000:05:00.0: WMI peer create vdev_id 0 peer_addr c4:04:15:3b:e0:39 +[ 390.472724] ath11k_pci 0000:05:00.0: mac vdev 0 start center_freq 2437 phymode 11ax-he20-2g +[ 390.472731] ath11k_pci 0000:05:00.0: wmi cmd send 0x5003 ret 0 +[ 390.560849] ath11k_pci 0000:05:00.0: wmi cmd send 0x5005 ret 0 +[ 390.560850] ath11k_pci 0000:05:00.0: WMI mgmt vdev up id 0x0 assoc id 1 bssid c4:04:15:3b:e0:39 + +[ 399.432896] ath11k_pci 0000:05:00.0: WMI peer delete vdev_id 0 peer_addr c4:04:15:3b:e0:39 +[ 399.432902] ath11k_pci 0000:05:00.0: wmi cmd send 0x6002 ret 0 +[ 399.441380] ath11k_pci 0000:05:00.0: wmi cmd send 0x5007 ret 0 +[ 399.441381] ath11k_pci 0000:05:00.0: WMI vdev down id 0x0 +[ 399.454681] ath11k_pci 0000:05:00.0: wmi cmd send 0x5006 ret 0 +[ 399.454682] ath11k_pci 0000:05:00.0: WMI vdev stop id 0x0 + +The opposite sequence of disconnect should be: + +vdev_down->vdev_stop->peer_delete + +This patch change the sequence of disconnect for station as above +opposite sequence for QCA6390, firmware not crash again with this patch. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211027093825.12167-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4218,6 +4218,10 @@ static int ath11k_mac_op_sta_state(struc + new_state == IEEE80211_STA_NOTEXIST)) { + ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + ++ if (ar->ab->hw_params.vdev_start_delay && ++ vif->type == NL80211_IFTYPE_STATION) ++ goto free; ++ + ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); + if (ret) + ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n", +@@ -4239,6 +4243,7 @@ static int ath11k_mac_op_sta_state(struc + } + spin_unlock_bh(&ar->ab->base_lock); + ++free: + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + +@@ -6627,6 +6632,19 @@ ath11k_mac_op_unassign_vif_chanctx(struc + arvif->is_started = false; + + if (ab->hw_params.vdev_start_delay && ++ arvif->vdev_type == WMI_VDEV_TYPE_STA) { ++ ret = ath11k_peer_delete(ar, arvif->vdev_id, arvif->bssid); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to delete peer %pM for vdev %d: %d\n", ++ arvif->bssid, arvif->vdev_id, ret); ++ else ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac removed peer %pM vdev %d after vdev stop\n", ++ arvif->bssid, arvif->vdev_id); ++ } ++ ++ if (ab->hw_params.vdev_start_delay && + arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + ath11k_wmi_vdev_down(ar, arvif->vdev_id); + diff --git a/package/kernel/mac80211/patches/ath11k/0089-ath11k-fix-FCS_ERR-flag-in-radio-tap-header.patch b/package/kernel/mac80211/patches/ath11k/0089-ath11k-fix-FCS_ERR-flag-in-radio-tap-header.patch new file mode 100644 index 000000000..6fe0ffdc9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0089-ath11k-fix-FCS_ERR-flag-in-radio-tap-header.patch @@ -0,0 +1,73 @@ +From 787264893c69ed091a46335dfd0f50dabb457718 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 25 Oct 2021 17:44:20 +0530 +Subject: [PATCH] ath11k: fix FCS_ERR flag in radio tap header + +In radio tap header, BAD FCS flag is not updated properly because +driver failed to update FCS_ERR flag in monitor mode. + +In rx_desc, FCS_ERR information is available in rx_attention +structure and presence of this field indicates corresponding frame +failed FCS check. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635164060-18423-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4826,7 +4826,7 @@ static struct sk_buff * + ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, + u32 mac_id, struct sk_buff *head_msdu, + struct sk_buff *last_msdu, +- struct ieee80211_rx_status *rxs) ++ struct ieee80211_rx_status *rxs, bool *fcs_err) + { + struct ath11k_base *ab = ar->ab; + struct sk_buff *msdu, *prev_buf; +@@ -4836,12 +4836,17 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + u8 *dest, decap_format; + struct ieee80211_hdr_3addr *wh; + struct rx_attention *rx_attention; ++ u32 err_bitmap; + + if (!head_msdu) + goto err_merge_fail; + + rx_desc = (struct hal_rx_desc *)head_msdu->data; + rx_attention = ath11k_dp_rx_get_attention(ab, rx_desc); ++ err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); ++ ++ if (err_bitmap & DP_RX_MPDU_ERR_FCS) ++ *fcs_err = true; + + if (ath11k_dp_rxdesc_get_mpdulen_err(rx_attention)) + return NULL; +@@ -4930,9 +4935,10 @@ static int ath11k_dp_rx_mon_deliver(stru + struct ath11k_pdev_dp *dp = &ar->dp; + struct sk_buff *mon_skb, *skb_next, *header; + struct ieee80211_rx_status *rxs = &dp->rx_status; ++ bool fcs_err = false; + + mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, +- tail_msdu, rxs); ++ tail_msdu, rxs, &fcs_err); + + if (!mon_skb) + goto mon_deliver_fail; +@@ -4940,6 +4946,10 @@ static int ath11k_dp_rx_mon_deliver(stru + header = mon_skb; + + rxs->flag = 0; ++ ++ if (fcs_err) ++ rxs->flag = RX_FLAG_FAILED_FCS_CRC; ++ + do { + skb_next = mon_skb->next; + if (!skb_next) diff --git a/package/kernel/mac80211/patches/ath11k/0090-ath11k-send-proper-txpower-and-maxregpower-values-to.patch b/package/kernel/mac80211/patches/ath11k/0090-ath11k-send-proper-txpower-and-maxregpower-values-to.patch new file mode 100644 index 000000000..ef39902d2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0090-ath11k-send-proper-txpower-and-maxregpower-values-to.patch @@ -0,0 +1,64 @@ +From 9212c1b9e80a869e732769a4fe7f82d392b219be Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 25 Oct 2021 17:47:09 +0530 +Subject: [PATCH] ath11k: send proper txpower and maxregpower values to + firmware + +Set proper values for max_regpower, max_power, max_antenna_gain as it +is because firmware will convert power values to 0.5dbm steps by +multiplying it with 2. + +If txpower is not set, it will lead to cca stuck resulting in latency +issues for QCN9074. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635164229-22880-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 12 ++++++------ + drivers/net/wireless/ath/ath11k/wmi.c | 2 ++ + 2 files changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -776,9 +776,9 @@ static int ath11k_mac_monitor_vdev_start + arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); + + arg.channel.min_power = 0; +- arg.channel.max_power = channel->max_power * 2; +- arg.channel.max_reg_power = channel->max_reg_power * 2; +- arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ++ arg.channel.max_power = channel->max_power; ++ arg.channel.max_reg_power = channel->max_reg_power; ++ arg.channel.max_antenna_gain = channel->max_antenna_gain; + + arg.pref_tx_streams = ar->num_tx_chains; + arg.pref_rx_streams = ar->num_rx_chains; +@@ -6133,9 +6133,9 @@ ath11k_mac_vdev_start_restart(struct ath + ath11k_phymodes[chandef->chan->band][chandef->width]; + + arg.channel.min_power = 0; +- arg.channel.max_power = chandef->chan->max_power * 2; +- arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; +- arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; ++ arg.channel.max_power = chandef->chan->max_power; ++ arg.channel.max_reg_power = chandef->chan->max_reg_power; ++ arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain; + + arg.pref_tx_streams = ar->num_tx_chains; + arg.pref_rx_streams = ar->num_rx_chains; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2388,6 +2388,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(s + tchan_info->reg_class_id); + *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX, + tchan_info->antennamax); ++ *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_MAX_TX_PWR, ++ tchan_info->maxregpower); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n", diff --git a/package/kernel/mac80211/patches/ath11k/0091-ath11k-Increment-pending_mgmt_tx-count-before-tx-sen.patch b/package/kernel/mac80211/patches/ath11k/0091-ath11k-Increment-pending_mgmt_tx-count-before-tx-sen.patch new file mode 100644 index 000000000..0788b5d46 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0091-ath11k-Increment-pending_mgmt_tx-count-before-tx-sen.patch @@ -0,0 +1,43 @@ +From c0b0d2e87d91ce283c8766b4b3c2ec9ac90ebf96 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 25 Oct 2021 18:54:42 +0530 +Subject: [PATCH] ath11k: Increment pending_mgmt_tx count before tx send invoke + +There is a race condition whereby the tx completion handler can be invoked +before the 'num_pending_mgmt_tx" count is incremented. If that occurs, we +could get warning trace indicating that 'num_pending_mgmt_tx' is 0 (because +it was not yet incremented). Ideally, this trace should be seen only if +mgmt tx has not happened but tx completion is received, and it is not +expected in this race condition. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635168282-8845-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5212,13 +5212,15 @@ static void ath11k_mgmt_over_wmi_tx_work + arvif = ath11k_vif_to_arvif(skb_cb->vif); + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && + arvif->is_started) { ++ atomic_inc(&ar->num_pending_mgmt_tx); + ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); + if (ret) { ++ if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) ++ WARN_ON_ONCE(1); ++ + ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", + arvif->vdev_id, ret); + ieee80211_free_txskb(ar->hw, skb); +- } else { +- atomic_inc(&ar->num_pending_mgmt_tx); + } + } else { + ath11k_warn(ar->ab, diff --git a/package/kernel/mac80211/patches/ath11k/0093-ath11k-Disabling-credit-flow-for-WMI-path.patch b/package/kernel/mac80211/patches/ath11k/0093-ath11k-Disabling-credit-flow-for-WMI-path.patch new file mode 100644 index 000000000..cd3dce096 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0093-ath11k-Disabling-credit-flow-for-WMI-path.patch @@ -0,0 +1,499 @@ +From f951380a6022440335f668f85296096ba13071ba Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 15 Nov 2021 11:50:52 +0200 +Subject: [PATCH] ath11k: Disabling credit flow for WMI path + +Firmware credit flow control is enabled for WMI control services, +which expects available tokens should be acquired before sending a +command to the target. Also the token gets released when firmware +receives the command. + +This credit-based flow limits driver to send WMI command only +when the token available which is causing WMI commands to timeout and +return -EAGAIN, whereas firmware has enough capability to process the +WMI command. To fix this Tx starvation issue, introduce the ability to +disable the credit flow for the WMI path. + +The driver sends WMI configuration for disabling credit flow to firmware +by two ways. + 1. By using a global flag + (HTC_MSG_SETUP_COMPLETE_EX_ID msg type flags) + 2. By using a local flag + (ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3) + +Ath11k uses both these configurations to disable credit flow for the +WMI path completely. + +Also added a hw_param member for credit flow control by which we can +enable or disable it based on per-target basis. Currently we are disabling +credit flow for IPQ8074, IPQ6018, and QCN9074 as recommended by firmware. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Pravas Kumar Panda +Signed-off-by: Pravas Kumar Panda +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635156494-20059-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ce.c | 37 +++++++++++--- + drivers/net/wireless/ath/ath11k/ce.h | 3 +- + drivers/net/wireless/ath/ath11k/core.c | 5 ++ + drivers/net/wireless/ath/ath11k/htc.c | 71 +++++++++++++++++++------- + drivers/net/wireless/ath/ath11k/htc.h | 9 ++-- + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 54 +++++++++++++++++--- + drivers/net/wireless/ath/ath11k/wmi.h | 1 + + 8 files changed, 146 insertions(+), 35 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -14,6 +14,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 16, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE1: target->host HTT + HTC control */ +@@ -40,6 +41,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE4: host->target HTT */ +@@ -73,6 +75,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE8: target autonomous hif_memcpy */ +@@ -89,6 +92,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE10: target->host HTT */ +@@ -142,6 +146,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE4: host->target HTT */ +@@ -175,6 +180,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE8: target autonomous hif_memcpy */ +@@ -220,6 +226,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE4: host->target HTT */ +@@ -489,18 +496,32 @@ err_unlock: + return skb; + } + +-static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) ++static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe) + { + struct ath11k_base *ab = pipe->ab; + struct sk_buff *skb; ++ struct sk_buff_head list; + ++ __skb_queue_head_init(&list); + while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { + if (!skb) + continue; + + dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, + DMA_TO_DEVICE); +- dev_kfree_skb_any(skb); ++ ++ if ((!pipe->send_cb) || ab->hw_params.credit_flow) { ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ ++ __skb_queue_tail(&list, skb); ++ } ++ ++ while ((skb = __skb_dequeue(&list))) { ++ ath11k_dbg(ab, ATH11K_DBG_AHB, "tx ce pipe %d len %d\n", ++ pipe->pipe_num, skb->len); ++ pipe->send_cb(ab, skb); + } + } + +@@ -636,7 +657,7 @@ static int ath11k_ce_alloc_pipe(struct a + pipe->attr_flags = attr->flags; + + if (attr->src_nentries) { +- pipe->send_cb = ath11k_ce_send_done_cb; ++ pipe->send_cb = attr->send_cb; + nentries = roundup_pow_of_two(attr->src_nentries); + desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); + ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); +@@ -667,9 +688,10 @@ static int ath11k_ce_alloc_pipe(struct a + void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) + { + struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; ++ const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; + +- if (pipe->send_cb) +- pipe->send_cb(pipe); ++ if (attr->src_nentries) ++ ath11k_ce_tx_process_cb(pipe); + + if (pipe->recv_cb) + ath11k_ce_recv_process_cb(pipe); +@@ -678,9 +700,10 @@ void ath11k_ce_per_engine_service(struct + void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) + { + struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; ++ const struct ce_attr *attr = &ab->hw_params.host_ce_config[pipe_id]; + +- if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) +- pipe->send_cb(pipe); ++ if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && attr->src_nentries) ++ ath11k_ce_tx_process_cb(pipe); + } + EXPORT_SYMBOL(ath11k_ce_per_engine_service); + +--- a/drivers/net/wireless/ath/ath11k/ce.h ++++ b/drivers/net/wireless/ath/ath11k/ce.h +@@ -101,6 +101,7 @@ struct ce_attr { + unsigned int dest_nentries; + + void (*recv_cb)(struct ath11k_base *, struct sk_buff *); ++ void (*send_cb)(struct ath11k_base *, struct sk_buff *); + }; + + #define CE_DESC_RING_ALIGN 8 +@@ -154,7 +155,7 @@ struct ath11k_ce_pipe { + unsigned int buf_sz; + unsigned int rx_buf_needed; + +- void (*send_cb)(struct ath11k_ce_pipe *); ++ void (*send_cb)(struct ath11k_base *, struct sk_buff *); + void (*recv_cb)(struct ath11k_base *, struct sk_buff *); + + struct tasklet_struct intr_tq; +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -81,6 +81,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, +@@ -133,6 +134,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, +@@ -184,6 +186,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, +@@ -235,6 +238,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, ++ .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, +@@ -286,6 +290,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, ++ .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, +--- a/drivers/net/wireless/ath/ath11k/htc.c ++++ b/drivers/net/wireless/ath/ath11k/htc.c +@@ -81,6 +81,8 @@ int ath11k_htc_send(struct ath11k_htc *h + struct ath11k_base *ab = htc->ab; + int credits = 0; + int ret; ++ bool credit_flow_enabled = (ab->hw_params.credit_flow && ++ ep->tx_credit_flow_enabled); + + if (eid >= ATH11K_HTC_EP_COUNT) { + ath11k_warn(ab, "Invalid endpoint id: %d\n", eid); +@@ -89,7 +91,7 @@ int ath11k_htc_send(struct ath11k_htc *h + + skb_push(skb, sizeof(struct ath11k_htc_hdr)); + +- if (ep->tx_credit_flow_enabled) { ++ if (credit_flow_enabled) { + credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); + spin_lock_bh(&htc->tx_lock); + if (ep->tx_credits < credits) { +@@ -126,7 +128,7 @@ int ath11k_htc_send(struct ath11k_htc *h + err_unmap: + dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); + err_credits: +- if (ep->tx_credit_flow_enabled) { ++ if (credit_flow_enabled) { + spin_lock_bh(&htc->tx_lock); + ep->tx_credits += credits; + ath11k_dbg(ab, ATH11K_DBG_HTC, +@@ -203,23 +205,25 @@ static int ath11k_htc_process_trailer(st + break; + } + +- switch (record->hdr.id) { +- case ATH11K_HTC_RECORD_CREDITS: +- len = sizeof(struct ath11k_htc_credit_report); +- if (record->hdr.len < len) { +- ath11k_warn(ab, "Credit report too long\n"); +- status = -EINVAL; ++ if (ab->hw_params.credit_flow) { ++ switch (record->hdr.id) { ++ case ATH11K_HTC_RECORD_CREDITS: ++ len = sizeof(struct ath11k_htc_credit_report); ++ if (record->hdr.len < len) { ++ ath11k_warn(ab, "Credit report too long\n"); ++ status = -EINVAL; ++ break; ++ } ++ ath11k_htc_process_credit_report(htc, ++ record->credit_report, ++ record->hdr.len, ++ src_eid); ++ break; ++ default: ++ ath11k_warn(ab, "Unhandled record: id:%d length:%d\n", ++ record->hdr.id, record->hdr.len); + break; + } +- ath11k_htc_process_credit_report(htc, +- record->credit_report, +- record->hdr.len, +- src_eid); +- break; +- default: +- ath11k_warn(ab, "Unhandled record: id:%d length:%d\n", +- record->hdr.id, record->hdr.len); +- break; + } + + if (status) +@@ -245,6 +249,29 @@ static void ath11k_htc_suspend_complete( + complete(&ab->htc_suspend); + } + ++void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ struct ath11k_htc *htc = &ab->htc; ++ struct ath11k_htc_ep *ep; ++ void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *); ++ u8 eid; ++ ++ eid = ATH11K_SKB_CB(skb)->eid; ++ if (eid >= ATH11K_HTC_EP_COUNT) ++ return; ++ ++ ep = &htc->endpoint[eid]; ++ spin_lock_bh(&htc->tx_lock); ++ ep_tx_complete = ep->ep_ops.ep_tx_complete; ++ spin_unlock_bh(&htc->tx_lock); ++ if (!ep_tx_complete) { ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ep_tx_complete(htc->ab, skb); ++} ++ + void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, + struct sk_buff *skb) + { +@@ -607,6 +634,11 @@ int ath11k_htc_connect_service(struct at + disable_credit_flow_ctrl = true; + } + ++ if (!ab->hw_params.credit_flow) { ++ flags |= ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL; ++ disable_credit_flow_ctrl = true; ++ } ++ + req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags); + req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID, + conn_req->service_id); +@@ -732,7 +764,10 @@ int ath11k_htc_start(struct ath11k_htc * + msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID, + ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID); + +- ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); ++ if (ab->hw_params.credit_flow) ++ ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); ++ else ++ msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW; + + status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb); + if (status) { +--- a/drivers/net/wireless/ath/ath11k/htc.h ++++ b/drivers/net/wireless/ath/ath11k/htc.h +@@ -83,8 +83,8 @@ enum ath11k_htc_conn_flags { + ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_HALF = 0x1, + ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS = 0x2, + ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_UNITY = 0x3, +- ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 1 << 2, +- ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3 ++ ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 0x4, ++ ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 0x8, + }; + + enum ath11k_htc_conn_svc_status { +@@ -116,6 +116,8 @@ struct ath11k_htc_conn_svc_resp { + u32 svc_meta_pad; + } __packed; + ++#define ATH11K_GLOBAL_DISABLE_CREDIT_FLOW BIT(1) ++ + struct ath11k_htc_setup_complete_extended { + u32 msg_id; + u32 flags; +@@ -305,5 +307,6 @@ int ath11k_htc_send(struct ath11k_htc *h + struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ar, int size); + void ath11k_htc_rx_completion_handler(struct ath11k_base *ar, + struct sk_buff *skb); +- ++void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, ++ struct sk_buff *skb); + #endif +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -175,6 +175,7 @@ struct ath11k_hw_params { + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; ++ bool credit_flow; + u8 max_tx_ring; + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -267,21 +267,39 @@ int ath11k_wmi_cmd_send(struct ath11k_pd + { + struct ath11k_wmi_base *wmi_sc = wmi->wmi_ab; + int ret = -EOPNOTSUPP; ++ struct ath11k_base *ab = wmi_sc->ab; + + might_sleep(); + +- wait_event_timeout(wmi_sc->tx_credits_wq, ({ +- ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); ++ if (ab->hw_params.credit_flow) { ++ wait_event_timeout(wmi_sc->tx_credits_wq, ({ ++ ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); ++ ++ if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, ++ &wmi_sc->ab->dev_flags)) ++ ret = -ESHUTDOWN; ++ ++ (ret != -EAGAIN); ++ }), WMI_SEND_TIMEOUT_HZ); ++ } else { ++ wait_event_timeout(wmi->tx_ce_desc_wq, ({ ++ ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); + +- if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags)) +- ret = -ESHUTDOWN; ++ if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, ++ &wmi_sc->ab->dev_flags)) ++ ret = -ESHUTDOWN; + +- (ret != -EAGAIN); +- }), WMI_SEND_TIMEOUT_HZ); ++ (ret != -ENOBUFS); ++ }), WMI_SEND_TIMEOUT_HZ); ++ } + + if (ret == -EAGAIN) + ath11k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id); + ++ if (ret == -ENOBUFS) ++ ath11k_warn(wmi_sc->ab, "ce desc not available for wmi command %d\n", ++ cmd_id); ++ + return ret; + } + +@@ -5817,7 +5835,30 @@ static void ath11k_wmi_op_ep_tx_credits( + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, + struct sk_buff *skb) + { ++ struct ath11k_pdev_wmi *wmi = NULL; ++ u32 i; ++ u8 wmi_ep_count; ++ u8 eid; ++ ++ eid = ATH11K_SKB_CB(skb)->eid; + dev_kfree_skb(skb); ++ ++ if (eid >= ATH11K_HTC_EP_COUNT) ++ return; ++ ++ wmi_ep_count = ab->htc.wmi_ep_count; ++ if (wmi_ep_count > ab->hw_params.max_radios) ++ return; ++ ++ for (i = 0; i < ab->htc.wmi_ep_count; i++) { ++ if (ab->wmi_ab.wmi[i].eid == eid) { ++ wmi = &ab->wmi_ab.wmi[i]; ++ break; ++ } ++ } ++ ++ if (wmi) ++ wake_up(&wmi->tx_ce_desc_wq); + } + + static bool ath11k_reg_is_world_alpha(char *alpha) +@@ -7208,6 +7249,7 @@ static int ath11k_connect_pdev_htc_servi + ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid; + ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid; + ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len; ++ init_waitqueue_head(&ab->wmi_ab.wmi[pdev_idx].tx_ce_desc_wq); + + return 0; + } +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2522,6 +2522,7 @@ struct ath11k_pdev_wmi { + enum ath11k_htc_ep_id eid; + const struct wmi_peer_flags_map *peer_flags; + u32 rx_decap_mode; ++ wait_queue_head_t tx_ce_desc_wq; + }; + + struct vdev_create_params { diff --git a/package/kernel/mac80211/patches/ath11k/0094-ath11k-use-cache-line-aligned-buffers-for-dbring.patch b/package/kernel/mac80211/patches/ath11k/0094-ath11k-use-cache-line-aligned-buffers-for-dbring.patch new file mode 100644 index 000000000..22a6c0bfe --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0094-ath11k-use-cache-line-aligned-buffers-for-dbring.patch @@ -0,0 +1,91 @@ +From bd77f6b1d7104cf6451399a7c67d08afecb9a7c7 Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Tue, 2 Nov 2021 11:11:33 +0530 +Subject: [PATCH] ath11k: use cache line aligned buffers for dbring + +The DMA buffers of dbring which is used for spectral/cfr +starts at certain offset from original kmalloc() returned buffer. +This is not cache line aligned. +And also driver tries to access the data that is immediately before +this offset address (i.e. buff->paddr) after doing dma map. +This will cause cache line sharing issues and data corruption, +if CPU happen to write back cache after HW has dma'ed the data. + +Fix this by mapping a cache line aligned buffer to dma. + +Tested on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635831693-15962-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dbring.c | 16 ++++++++++++---- + drivers/net/wireless/ath/ath11k/dbring.h | 2 +- + 2 files changed, 13 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dbring.c ++++ b/drivers/net/wireless/ath/ath11k/dbring.c +@@ -87,17 +87,23 @@ static int ath11k_dbring_fill_bufs(struc + req_entries = min(num_free, ring->bufs_max); + num_remain = req_entries; + align = ring->buf_align; +- size = sizeof(*buff) + ring->buf_sz + align - 1; ++ size = ring->buf_sz + align - 1; + + while (num_remain > 0) { +- buff = kzalloc(size, GFP_ATOMIC); ++ buff = kzalloc(sizeof(*buff), GFP_ATOMIC); + if (!buff) + break; + ++ buff->payload = kzalloc(size, GFP_ATOMIC); ++ if (!buff->payload) { ++ kfree(buff); ++ break; ++ } + ret = ath11k_dbring_bufs_replenish(ar, ring, buff); + if (ret) { + ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n", + num_remain, req_entries); ++ kfree(buff->payload); + kfree(buff); + break; + } +@@ -282,7 +288,7 @@ int ath11k_dbring_buffer_release_event(s + + srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; + num_entry = ev->fixed.num_buf_release_entry; +- size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1; ++ size = ring->buf_sz + ring->buf_align - 1; + num_buff_reaped = 0; + + spin_lock_bh(&srng->lock); +@@ -319,7 +325,8 @@ int ath11k_dbring_buffer_release_event(s + ring->handler(ar, &handler_data); + } + +- memset(buff, 0, size); ++ buff->paddr = 0; ++ memset(buff->payload, 0, size); + ath11k_dbring_bufs_replenish(ar, ring, buff); + } + +@@ -346,6 +353,7 @@ void ath11k_dbring_buf_cleanup(struct at + idr_remove(&ring->bufs_idr, buf_id); + dma_unmap_single(ar->ab->dev, buff->paddr, + ring->buf_sz, DMA_FROM_DEVICE); ++ kfree(buff->payload); + kfree(buff); + } + +--- a/drivers/net/wireless/ath/ath11k/dbring.h ++++ b/drivers/net/wireless/ath/ath11k/dbring.h +@@ -13,7 +13,7 @@ + + struct ath11k_dbring_element { + dma_addr_t paddr; +- u8 payload[0]; ++ u8 *payload; + }; + + struct ath11k_dbring_data { diff --git a/package/kernel/mac80211/patches/ath11k/0095-ath11k-Add-missing-qmi_txn_cancel.patch b/package/kernel/mac80211/patches/ath11k/0095-ath11k-Add-missing-qmi_txn_cancel.patch new file mode 100644 index 000000000..486185d2f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0095-ath11k-Add-missing-qmi_txn_cancel.patch @@ -0,0 +1,142 @@ +From 1ad6e4b00f29d017b196dda7ab96d1cfcbabd7d2 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 2 Nov 2021 18:22:38 +0530 +Subject: [PATCH] ath11k: Add missing qmi_txn_cancel() + +Currently many functions do not follow this guidance when +qmi_send_request() fails, therefore add missing +qmi_txn_cancel() in the qmi_send_request() error path. + +Also remove initialization on 'struct qmi_txn' +since qmi_tx_init() performs all necessary initialization. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635857558-21733-1-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1586,7 +1586,7 @@ static int ath11k_qmi_host_cap_send(stru + { + struct qmi_wlanfw_host_cap_req_msg_v01 req; + struct qmi_wlanfw_host_cap_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + + memset(&req, 0, sizeof(req)); +@@ -1640,6 +1640,7 @@ static int ath11k_qmi_host_cap_send(stru + QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_host_cap_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send host capability request: %d\n", ret); + goto out; + } +@@ -1705,6 +1706,7 @@ static int ath11k_qmi_fw_ind_register_se + QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_ind_register_req_msg_v01_ei, req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send indication register request: %d\n", + ret); + goto out; +@@ -1734,7 +1736,7 @@ static int ath11k_qmi_respond_fw_mem_req + { + struct qmi_wlanfw_respond_mem_req_msg_v01 *req; + struct qmi_wlanfw_respond_mem_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0, i; + bool delayed; + +@@ -1783,6 +1785,7 @@ static int ath11k_qmi_respond_fw_mem_req + QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_respond_mem_req_msg_v01_ei, req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to respond qmi memory request: %d\n", + ret); + goto out; +@@ -1911,7 +1914,7 @@ static int ath11k_qmi_request_target_cap + { + struct qmi_wlanfw_cap_req_msg_v01 req; + struct qmi_wlanfw_cap_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + int r; + +@@ -1930,6 +1933,7 @@ static int ath11k_qmi_request_target_cap + QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_cap_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send qmi cap request: %d\n", + ret); + goto out; +@@ -2000,7 +2004,7 @@ static int ath11k_qmi_load_file_target_m + { + struct qmi_wlanfw_bdf_download_req_msg_v01 *req; + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + const u8 *temp = data; + void __iomem *bdf_addr = NULL; + int ret; +@@ -2245,7 +2249,7 @@ static int ath11k_qmi_wlanfw_m3_info_sen + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + struct qmi_wlanfw_m3_info_req_msg_v01 req; + struct qmi_wlanfw_m3_info_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + + memset(&req, 0, sizeof(req)); +@@ -2277,6 +2281,7 @@ static int ath11k_qmi_wlanfw_m3_info_sen + QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN, + qmi_wlanfw_m3_info_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send m3 information request: %d\n", + ret); + goto out; +@@ -2303,7 +2308,7 @@ static int ath11k_qmi_wlanfw_mode_send(s + { + struct qmi_wlanfw_wlan_mode_req_msg_v01 req; + struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + + memset(&req, 0, sizeof(req)); +@@ -2325,6 +2330,7 @@ static int ath11k_qmi_wlanfw_mode_send(s + QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send wlan mode request (mode %d): %d\n", + mode, ret); + goto out; +@@ -2358,7 +2364,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_se + struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp; + struct ce_pipe_config *ce_cfg; + struct service_to_pipe *svc_cfg; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0, pipe_num; + + ce_cfg = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce; +@@ -2419,6 +2425,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_se + QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send wlan config request: %d\n", + ret); + goto out; diff --git a/package/kernel/mac80211/patches/ath11k/0096-ath11k-add-trace-log-support.patch b/package/kernel/mac80211/patches/ath11k/0096-ath11k-add-trace-log-support.patch new file mode 100644 index 000000000..49974b060 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0096-ath11k-add-trace-log-support.patch @@ -0,0 +1,309 @@ +From fb12305aff12e735e599c79514dde5dac40f5a59 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Tue, 9 Nov 2021 12:05:55 +0530 +Subject: [PATCH] ath11k: add trace log support + +This change is to add trace log support for, + * WMI events + * WMI commands + * ath11k_dbg messages + * ath11k_dbg_dump messages + * ath11k_log_info messages + * ath11k_log_warn messages + * ath11k_log_err messages + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00652-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636439755-30419-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debug.c | 12 +- + drivers/net/wireless/ath/ath11k/debug.h | 3 +- + drivers/net/wireless/ath/ath11k/trace.c | 1 + + drivers/net/wireless/ath/ath11k/trace.h | 172 ++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 4 + + 5 files changed, 187 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debug.c ++++ b/drivers/net/wireless/ath/ath11k/debug.c +@@ -17,7 +17,7 @@ void ath11k_info(struct ath11k_base *ab, + va_start(args, fmt); + vaf.va = &args; + dev_info(ab->dev, "%pV", &vaf); +- /* TODO: Trace the log */ ++ trace_ath11k_log_info(ab, &vaf); + va_end(args); + } + EXPORT_SYMBOL(ath11k_info); +@@ -32,7 +32,7 @@ void ath11k_err(struct ath11k_base *ab, + va_start(args, fmt); + vaf.va = &args; + dev_err(ab->dev, "%pV", &vaf); +- /* TODO: Trace the log */ ++ trace_ath11k_log_err(ab, &vaf); + va_end(args); + } + EXPORT_SYMBOL(ath11k_err); +@@ -47,7 +47,7 @@ void ath11k_warn(struct ath11k_base *ab, + va_start(args, fmt); + vaf.va = &args; + dev_warn_ratelimited(ab->dev, "%pV", &vaf); +- /* TODO: Trace the log */ ++ trace_ath11k_log_warn(ab, &vaf); + va_end(args); + } + EXPORT_SYMBOL(ath11k_warn); +@@ -68,7 +68,7 @@ void __ath11k_dbg(struct ath11k_base *ab + if (ath11k_debug_mask & mask) + dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf); + +- /* TODO: trace log */ ++ trace_ath11k_log_dbg(ab, mask, &vaf); + + va_end(args); + } +@@ -100,6 +100,10 @@ void ath11k_dbg_dump(struct ath11k_base + dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf); + } + } ++ ++ /* tracing code doesn't like null strings */ ++ trace_ath11k_log_dbg_dump(ab, msg ? msg : "", prefix ? prefix : "", ++ buf, len); + } + EXPORT_SYMBOL(ath11k_dbg_dump); + +--- a/drivers/net/wireless/ath/ath11k/debug.h ++++ b/drivers/net/wireless/ath/ath11k/debug.h +@@ -60,7 +60,8 @@ static inline void ath11k_dbg_dump(struc + + #define ath11k_dbg(ar, dbg_mask, fmt, ...) \ + do { \ +- if (ath11k_debug_mask & dbg_mask) \ ++ if ((ath11k_debug_mask & dbg_mask) || \ ++ trace_ath11k_log_dbg_enabled()) \ + __ath11k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \ + } while (0) + +--- a/drivers/net/wireless/ath/ath11k/trace.c ++++ b/drivers/net/wireless/ath/ath11k/trace.c +@@ -7,3 +7,4 @@ + + #define CREATE_TRACE_POINTS + #include "trace.h" ++EXPORT_SYMBOL(__tracepoint_ath11k_log_dbg); +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -14,12 +14,24 @@ + #if !defined(CPTCFG_ATH11K_TRACING) + #undef TRACE_EVENT + #define TRACE_EVENT(name, proto, ...) \ ++static inline void trace_ ## name(proto) {} \ ++static inline bool trace_##name##_enabled(void) \ ++{ \ ++ return false; \ ++} ++ ++#undef DECLARE_EVENT_CLASS ++#define DECLARE_EVENT_CLASS(...) ++#undef DEFINE_EVENT ++#define DEFINE_EVENT(evt_class, name, proto, ...) \ + static inline void trace_ ## name(proto) {} + #endif /* !CPTCFG_ATH11K_TRACING || __CHECKER__ */ + + #undef TRACE_SYSTEM + #define TRACE_SYSTEM ath11k + ++#define ATH11K_MSG_MAX 400 ++ + TRACE_EVENT(ath11k_htt_pktlog, + TP_PROTO(struct ath11k *ar, const void *buf, u16 buf_len, + u32 pktlog_checksum), +@@ -108,6 +120,166 @@ TRACE_EVENT(ath11k_htt_rxdesc, + ) + ); + ++DECLARE_EVENT_CLASS(ath11k_log_event, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf), ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __dynamic_array(char, msg, ATH11K_MSG_MAX) ++ ), ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ++ ATH11K_MSG_MAX, ++ vaf->fmt, ++ *vaf->va) >= ATH11K_MSG_MAX); ++ ), ++ TP_printk( ++ "%s %s %s", ++ __get_str(driver), ++ __get_str(device), ++ __get_str(msg) ++ ) ++); ++ ++DEFINE_EVENT(ath11k_log_event, ath11k_log_err, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf) ++); ++ ++DEFINE_EVENT(ath11k_log_event, ath11k_log_warn, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf) ++); ++ ++DEFINE_EVENT(ath11k_log_event, ath11k_log_info, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf) ++); ++ ++TRACE_EVENT(ath11k_wmi_cmd, ++ TP_PROTO(struct ath11k_base *ab, int id, const void *buf, size_t buf_len), ++ ++ TP_ARGS(ab, id, buf, buf_len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(unsigned int, id) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->id = id; ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++ "%s %s id %d len %zu", ++ __get_str(driver), ++ __get_str(device), ++ __entry->id, ++ __entry->buf_len ++ ) ++); ++ ++TRACE_EVENT(ath11k_wmi_event, ++ TP_PROTO(struct ath11k_base *ab, int id, const void *buf, size_t buf_len), ++ ++ TP_ARGS(ab, id, buf, buf_len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(unsigned int, id) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->id = id; ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++ "%s %s id %d len %zu", ++ __get_str(driver), ++ __get_str(device), ++ __entry->id, ++ __entry->buf_len ++ ) ++); ++ ++TRACE_EVENT(ath11k_log_dbg, ++ TP_PROTO(struct ath11k_base *ab, unsigned int level, struct va_format *vaf), ++ ++ TP_ARGS(ab, level, vaf), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(unsigned int, level) ++ __dynamic_array(char, msg, ATH11K_MSG_MAX) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->level = level; ++ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ++ ATH11K_MSG_MAX, vaf->fmt, ++ *vaf->va) >= ATH11K_MSG_MAX); ++ ), ++ ++ TP_printk( ++ "%s %s %s", ++ __get_str(driver), ++ __get_str(device), ++ __get_str(msg) ++ ) ++); ++ ++TRACE_EVENT(ath11k_log_dbg_dump, ++ TP_PROTO(struct ath11k_base *ab, const char *msg, const char *prefix, ++ const void *buf, size_t buf_len), ++ ++ TP_ARGS(ab, msg, prefix, buf, buf_len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __string(msg, msg) ++ __string(prefix, prefix) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __assign_str(msg, msg); ++ __assign_str(prefix, prefix); ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++ "%s %s %s/%s\n", ++ __get_str(driver), ++ __get_str(device), ++ __get_str(prefix), ++ __get_str(msg) ++ ) ++); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ + + /* we don't want to use include/trace/events */ +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -249,6 +249,8 @@ static int ath11k_wmi_cmd_send_nowait(st + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + cmd_hdr->cmd_id = cmd; + ++ trace_ath11k_wmi_cmd(ab, cmd_id, skb->data, skb->len); ++ + memset(skb_cb, 0, sizeof(*skb_cb)); + ret = ath11k_htc_send(&ab->htc, wmi->eid, skb); + +@@ -7104,6 +7106,8 @@ static void ath11k_wmi_tlv_op_rx(struct + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = FIELD_GET(WMI_CMD_HDR_CMD_ID, (cmd_hdr->cmd_id)); + ++ trace_ath11k_wmi_event(ab, id, skb->data, skb->len); ++ + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) + goto out; + diff --git a/package/kernel/mac80211/patches/ath11k/0099-ath11k-add-support-for-BSS-color-change.patch b/package/kernel/mac80211/patches/ath11k/0099-ath11k-add-support-for-BSS-color-change.patch new file mode 100644 index 000000000..7796b85ad --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0099-ath11k-add-support-for-BSS-color-change.patch @@ -0,0 +1,308 @@ +From 886433a984254c6d2c2074688dc8f48c40b1c070 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 25 Oct 2021 21:40:54 +0530 +Subject: [PATCH] ath11k: add support for BSS color change + +Whenever the MAC detects a color collision, or any of +its associated stations detects one, the firmware will +send out an event. Add the code to parse and handle +this event and pass the data up to mac80211. + +The firmware does not provide an offload feature such +as the one used for CSA. The color change process is +hence triggered via the beacon offload tx completion +events sent out by firmware. + +BSS color feature is enabled depending on service flag +advertised by firmware, based on which color change +functionality is invoked. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00680-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: John Crispin +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635178254-17732-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 2 + + drivers/net/wireless/ath/ath11k/mac.c | 57 +++++++++++++++++-- + drivers/net/wireless/ath/ath11k/mac.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 78 +++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/wmi.h | 15 +++++ + 5 files changed, 147 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -256,6 +256,8 @@ struct ath11k_vif { + int txpower; + bool rsnie_present; + bool wpaie_present; ++ bool bcca_zero_sent; ++ bool do_not_send_tmpl; + struct ieee80211_chanctx_conf chanctx; + }; + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1236,6 +1236,26 @@ static int ath11k_mac_setup_bcn_tmpl(str + return ret; + } + ++void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) ++{ ++ struct ieee80211_vif *vif = arvif->vif; ++ ++ if (!vif->color_change_active && !arvif->bcca_zero_sent) ++ return; ++ ++ if (vif->color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { ++ arvif->bcca_zero_sent = true; ++ ieee80211_color_change_finish(vif); ++ return; ++ } ++ ++ arvif->bcca_zero_sent = false; ++ ++ if (vif->color_change_active) ++ ieee80211_beacon_update_cntdwn(vif); ++ ath11k_mac_setup_bcn_tmpl(arvif); ++} ++ + static void ath11k_control_beaconing(struct ath11k_vif *arvif, + struct ieee80211_bss_conf *info) + { +@@ -2899,10 +2919,17 @@ static void ath11k_mac_op_bss_info_chang + "Set staggered beacon mode for VDEV: %d\n", + arvif->vdev_id); + +- ret = ath11k_mac_setup_bcn_tmpl(arvif); +- if (ret) +- ath11k_warn(ar->ab, "failed to update bcn template: %d\n", +- ret); ++ if (!arvif->do_not_send_tmpl || !arvif->bcca_zero_sent) { ++ ret = ath11k_mac_setup_bcn_tmpl(arvif); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to update bcn template: %d\n", ++ ret); ++ } ++ ++ if (arvif->bcca_zero_sent) ++ arvif->do_not_send_tmpl = true; ++ else ++ arvif->do_not_send_tmpl = false; + } + + if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { +@@ -3113,6 +3140,25 @@ static void ath11k_mac_op_bss_info_chang + if (ret) + ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", + arvif->vdev_id, ret); ++ ++ param_id = WMI_VDEV_PARAM_BSS_COLOR; ++ if (info->he_bss_color.enabled) ++ param_value = info->he_bss_color.color << ++ IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET; ++ else ++ param_value = IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ param_id, ++ param_value); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to set bss color param on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "bss color param 0x%x set on vdev %i\n", ++ param_value, arvif->vdev_id); + } else if (vif->type == NL80211_IFTYPE_STATION) { + ret = ath11k_wmi_send_bss_color_change_enable_cmd(ar, + arvif->vdev_id, +@@ -7882,6 +7928,9 @@ static int __ath11k_mac_register(struct + + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); ++ if (test_bit(WMI_TLV_SERVICE_BSS_COLOR_OFFLOAD, ar->ab->wmi_ab.svc_map)) ++ wiphy_ext_feature_set(ar->hw->wiphy, ++ NL80211_EXT_FEATURE_BSS_COLOR); + + ar->hw->wiphy->cipher_suites = cipher_suites; + ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -155,4 +155,5 @@ enum ath11k_supported_bw ath11k_mac_mac8 + enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher); + void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); + void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id); ++void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif); + #endif +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -128,6 +128,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, + [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { + .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, ++ [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { ++ .min_len = sizeof(struct wmi_obss_color_collision_event) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -1633,6 +1635,15 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a + void *ptr; + int ret, len; + size_t aligned_len = roundup(bcn->len, 4); ++ struct ieee80211_vif *vif; ++ struct ath11k_vif *arvif = ath11k_mac_get_arvif(ar, vdev_id); ++ ++ if (!arvif) { ++ ath11k_warn(ar->ab, "failed to find arvif with vdev id %d\n", vdev_id); ++ return -EINVAL; ++ } ++ ++ vif = arvif->vif; + + len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len; + +@@ -1645,8 +1656,12 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->tim_ie_offset = offs->tim_offset; +- cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; +- cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; ++ ++ if (vif->csa_active) { ++ cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; ++ cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; ++ } ++ + cmd->buf_len = bcn->len; + + ptr = skb->data + sizeof(*cmd); +@@ -3452,6 +3467,53 @@ int ath11k_wmi_fils_discovery(struct ath + } + + static void ++ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *skb) ++{ ++ const void **tb; ++ const struct wmi_obss_color_collision_event *ev; ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_OBSS_COLOR_COLLISION_EVT]; ++ if (!ev) { ++ ath11k_warn(ab, "failed to fetch obss color collision ev"); ++ goto exit; ++ } ++ ++ arvif = ath11k_mac_get_arvif_by_vdev_id(ab, ev->vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "failed to find arvif with vedv id %d in obss_color_collision_event\n", ++ ev->vdev_id); ++ goto exit; ++ } ++ ++ switch (ev->evt_type) { ++ case WMI_BSS_COLOR_COLLISION_DETECTION: ++ ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap); ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", ++ ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); ++ break; ++ case WMI_BSS_COLOR_COLLISION_DISABLE: ++ case WMI_BSS_COLOR_FREE_SLOT_TIMER_EXPIRY: ++ case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE: ++ break; ++ default: ++ ath11k_warn(ab, "received unknown obss color collision detetction event\n"); ++ } ++ ++exit: ++ kfree(tb); ++} ++ ++static void + ath11k_fill_band_to_mac_param(struct ath11k_base *soc, + struct wmi_host_pdev_band_to_mac *band_to_mac) + { +@@ -6158,6 +6220,7 @@ static void ath11k_vdev_start_resp_event + + static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *skb) + { ++ struct ath11k_vif *arvif; + u32 vdev_id, tx_status; + + if (ath11k_pull_bcn_tx_status_ev(ab, skb->data, skb->len, +@@ -6165,6 +6228,14 @@ static void ath11k_bcn_tx_status_event(s + ath11k_warn(ab, "failed to extract bcn tx status"); + return; + } ++ ++ arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "invalid vdev id %d in bcn_tx_status", ++ vdev_id); ++ return; ++ } ++ ath11k_mac_bcn_tx_event(arvif); + } + + static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb) +@@ -7192,6 +7263,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID: + ath11k_probe_resp_tx_status_event(ab, skb); + break; ++ case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: ++ ath11k_wmi_obss_color_collision_event(ab, skb); ++ break; + /* add Unsupported events here */ + case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: + case WMI_PEER_OPER_MODE_CHANGE_EVENTID: +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -774,6 +774,8 @@ enum wmi_tlv_event_id { + WMI_MDNS_STATS_EVENTID = WMI_TLV_CMD(WMI_GRP_MDNS_OFL), + WMI_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_CMD(WMI_GRP_SAP_OFL), + WMI_SAP_OFL_DEL_STA_EVENTID, ++ WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID = ++ WMI_EVT_GRP_START_ID(WMI_GRP_OBSS_OFL), + WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_OCB), + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, + WMI_DCC_GET_STATS_RESP_EVENTID, +@@ -4916,6 +4918,13 @@ struct wmi_pdev_obss_pd_bitmap_cmd { + #define ATH11K_BSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS 10000 + #define ATH11K_BSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS 5000 + ++enum wmi_bss_color_collision { ++ WMI_BSS_COLOR_COLLISION_DISABLE = 0, ++ WMI_BSS_COLOR_COLLISION_DETECTION, ++ WMI_BSS_COLOR_FREE_SLOT_TIMER_EXPIRY, ++ WMI_BSS_COLOR_FREE_SLOT_AVAILABLE, ++}; ++ + struct wmi_obss_color_collision_cfg_params_cmd { + u32 tlv_header; + u32 vdev_id; +@@ -4933,6 +4942,12 @@ struct wmi_bss_color_change_enable_param + u32 enable; + } __packed; + ++struct wmi_obss_color_collision_event { ++ u32 vdev_id; ++ u32 evt_type; ++ u64 obss_color_bitmap; ++} __packed; ++ + #define ATH11K_IPV4_TH_SEED_SIZE 5 + #define ATH11K_IPV6_TH_SEED_SIZE 11 + diff --git a/package/kernel/mac80211/patches/ath11k/0102-ath11k-add-hw_param-for-wakeup_mhi.patch b/package/kernel/mac80211/patches/ath11k/0102-ath11k-add-hw_param-for-wakeup_mhi.patch new file mode 100644 index 000000000..fe000c3ab --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0102-ath11k-add-hw_param-for-wakeup_mhi.patch @@ -0,0 +1,137 @@ +From 081e2d6476e30399433b509684d5da4d1844e430 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Wed, 17 Nov 2021 09:39:41 +0200 +Subject: [PATCH] ath11k: add hw_param for wakeup_mhi + +Wakeup mhi is needed before pci_read/write only for QCA6390 and WCN6855. Since +wakeup & release mhi is enabled for all hardwares, below mhi assert is seen in +QCN9074 when doing 'rmmod ath11k_pci': + + Kernel panic - not syncing: dev_wake != 0 + CPU: 2 PID: 13535 Comm: procd Not tainted 4.4.60 #1 + Hardware name: Generic DT based system + [<80316dac>] (unwind_backtrace) from [<80313700>] (show_stack+0x10/0x14) + [<80313700>] (show_stack) from [<805135dc>] (dump_stack+0x7c/0x9c) + [<805135dc>] (dump_stack) from [<8032136c>] (panic+0x84/0x1f8) + [<8032136c>] (panic) from [<80549b24>] (mhi_pm_disable_transition+0x3b8/0x5b8) + [<80549b24>] (mhi_pm_disable_transition) from [<80549ddc>] (mhi_power_down+0xb8/0x100) + [<80549ddc>] (mhi_power_down) from [<7f5242b0>] (ath11k_mhi_op_status_cb+0x284/0x3ac [ath11k_pci]) + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [<7f5242b0>] (ath11k_mhi_op_status_cb [ath11k_pci]) from [<7f524878>] (ath11k_mhi_stop+0x10/0x20 [ath11k_pci]) + [<7f524878>] (ath11k_mhi_stop [ath11k_pci]) from [<7f525b94>] (ath11k_pci_power_down+0x54/0x90 [ath11k_pci]) + [<7f525b94>] (ath11k_pci_power_down [ath11k_pci]) from [<8056b2a8>] (pci_device_shutdown+0x30/0x44) + [<8056b2a8>] (pci_device_shutdown) from [<805cfa0c>] (device_shutdown+0x124/0x174) + [<805cfa0c>] (device_shutdown) from [<8033aaa4>] (kernel_restart+0xc/0x50) + [<8033aaa4>] (kernel_restart) from [<8033ada8>] (SyS_reboot+0x178/0x1ec) + [<8033ada8>] (SyS_reboot) from [<80301b80>] (ret_fast_syscall+0x0/0x34) + +Hence, disable wakeup/release mhi using hw_param for other hardwares. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01060-QCAHKSWPL_SILICONZ-1 + +Fixes: a05bd8513335 ("ath11k: read and write registers below unwindowed address") +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636702019-26142-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/pci.c | 12 ++++++++---- + 3 files changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -86,6 +86,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, ++ .wakeup_mhi = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -139,6 +140,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, ++ .wakeup_mhi = false, + }, + { + .name = "qca6390 hw2.0", +@@ -191,6 +193,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, ++ .wakeup_mhi = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -243,6 +246,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, + .alloc_cacheable_memory = true, ++ .wakeup_mhi = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -295,6 +299,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, ++ .wakeup_mhi = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -180,6 +180,7 @@ struct ath11k_hw_params { + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; + bool alloc_cacheable_memory; ++ bool wakeup_mhi; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -182,7 +182,8 @@ void ath11k_pci_write32(struct ath11k_ba + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. + */ +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +@@ -206,7 +207,8 @@ void ath11k_pci_write32(struct ath11k_ba + } + } + +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + } +@@ -219,7 +221,8 @@ u32 ath11k_pci_read32(struct ath11k_base + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. + */ +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +@@ -243,7 +246,8 @@ u32 ath11k_pci_read32(struct ath11k_base + } + } + +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + diff --git a/package/kernel/mac80211/patches/ath11k/0103-ath11k-get-msi_data-again-after-request_irq-is-calle.patch b/package/kernel/mac80211/patches/ath11k/0103-ath11k-get-msi_data-again-after-request_irq-is-calle.patch new file mode 100644 index 000000000..483ba4973 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0103-ath11k-get-msi_data-again-after-request_irq-is-calle.patch @@ -0,0 +1,76 @@ +From 87b4072d7ef818e368b0f4162a1af2fb4727f51c Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: get msi_data again after request_irq is called + +The reservation mode of interrupts in kernel assigns a dummy vector +when the interrupt is allocated and assigns a real vector when the +request_irq is called. The reservation mode helps to ease vector +pressure when devices with a large amount of queues/interrupts +are initialized, but only a minimal subset of those queues/interrupts +is actually used. + +So on reservation mode, the msi_data may change after request_irq +is called, so ath11k reads msi_data again after request_irq is called, +and then the correct msi_data is programmed into QCA6390 hardware +components. Without this change, spurious interrupt occurs in case of +one MSI vector. When VT-d in BIOS is enabled and ath11k can get 32 MSI +vectors, ath11k always get the same msi_data before and after request_irq, +that's why this change is only required when one MSI vector is to be +supported. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026041636.5008-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 30 +++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -939,6 +939,25 @@ static void ath11k_pci_free_msi(struct a + pci_free_irq_vectors(ab_pci->pdev); + } + ++static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) ++{ ++ struct msi_desc *msi_desc; ++ ++ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); ++ if (!msi_desc) { ++ ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); ++ pci_free_irq_vectors(ab_pci->pdev); ++ return -EINVAL; ++ } ++ ++ ab_pci->msi_ep_base_data = msi_desc->msg.data; ++ ++ ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", ++ ab_pci->msi_ep_base_data); ++ ++ return 0; ++} ++ + static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) + { + struct ath11k_base *ab = ab_pci->ab; +@@ -1348,6 +1367,17 @@ static int ath11k_pci_probe(struct pci_d + goto err_ce_free; + } + ++ /* kernel may allocate a dummy vector before request_irq and ++ * then allocate a real vector when request_irq is called. ++ * So get msi_data here again to avoid spurious interrupt ++ * as msi_data will configured to srngs. ++ */ ++ ret = ath11k_pci_config_msi_data(ab_pci); ++ if (ret) { ++ ath11k_err(ab, "failed to config msi_data: %d\n", ret); ++ goto err_free_irq; ++ } ++ + ret = ath11k_core_init(ab); + if (ret) { + ath11k_err(ab, "failed to init core: %d\n", ret); diff --git a/package/kernel/mac80211/patches/ath11k/0104-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handl.patch b/package/kernel/mac80211/patches/ath11k/0104-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handl.patch new file mode 100644 index 000000000..cd6872a74 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0104-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handl.patch @@ -0,0 +1,92 @@ +From 01279bcd01d965b6526d575e036841778d8e3c4e Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: add CE and ext IRQ flag to indicate irq_handler + +This change adds two flags to indicate whether IRQ handler for CE +and DP can be called. This is because in one MSI vector case, +interrupt is not disabled in hif_stop and hif_irq_disable. Otherwise, +MHI interrupt is disabled too. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041646.5060-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 2 ++ + drivers/net/wireless/ath/ath11k/pci.c | 16 ++++++++++++++++ + 2 files changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -200,6 +200,8 @@ enum ath11k_dev_flags { + ATH11K_FLAG_REGISTERED, + ATH11K_FLAG_QMI_FAIL, + ATH11K_FLAG_HTC_SUSPEND_COMPLETE, ++ ATH11K_FLAG_CE_IRQ_ENABLED, ++ ATH11K_FLAG_EXT_IRQ_ENABLED, + }; + + enum ath11k_monitor_flags { +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -578,6 +578,8 @@ static void ath11k_pci_ce_irqs_disable(s + { + int i; + ++ clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); ++ + for (i = 0; i < ab->hw_params.ce_count; i++) { + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) + continue; +@@ -611,6 +613,10 @@ static void ath11k_pci_ce_tasklet(struct + static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) + { + struct ath11k_ce_pipe *ce_pipe = arg; ++ struct ath11k_base *ab = ce_pipe->ab; ++ ++ if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) ++ return IRQ_HANDLED; + + /* last interrupt received for this CE */ + ce_pipe->timestamp = jiffies; +@@ -633,6 +639,8 @@ static void __ath11k_pci_ext_irq_disable + { + int i; + ++ clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); ++ + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; + +@@ -658,6 +666,8 @@ static void ath11k_pci_ext_irq_enable(st + { + int i; + ++ set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); ++ + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + +@@ -712,6 +722,10 @@ static int ath11k_pci_ext_grp_napi_poll( + static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) + { + struct ath11k_ext_irq_grp *irq_grp = arg; ++ struct ath11k_base *ab = irq_grp->ab; ++ ++ if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) ++ return IRQ_HANDLED; + + ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); + +@@ -858,6 +872,8 @@ static void ath11k_pci_ce_irqs_enable(st + { + int i; + ++ set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); ++ + for (i = 0; i < ab->hw_params.ce_count; i++) { + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) + continue; diff --git a/package/kernel/mac80211/patches/ath11k/0105-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch b/package/kernel/mac80211/patches/ath11k/0105-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch new file mode 100644 index 000000000..e08db10ec --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0105-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch @@ -0,0 +1,50 @@ +From 4ab4693f327ad015c4637ae42dc53c8471aed9c8 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for DP IRQ + +Like ATH11K_PCI_IRQ_CE0_OFFSET, define ATH11K_PCI_IRQ_DP_OFFSET for +DP to save the IRQ instead of base_vector from MSI config. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041655.5112-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -16,7 +16,8 @@ + #define ATH11K_PCI_BAR_NUM 0 + #define ATH11K_PCI_DMA_MASK 32 + +-#define ATH11K_PCI_IRQ_CE0_OFFSET 3 ++#define ATH11K_PCI_IRQ_CE0_OFFSET 3 ++#define ATH11K_PCI_IRQ_DP_OFFSET 14 + + #define WINDOW_ENABLE_BIT 0x40000000 + #define WINDOW_REG_ADDRESS 0x310c +@@ -742,9 +743,8 @@ static irqreturn_t ath11k_pci_ext_interr + static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) + { + int i, j, ret, num_vectors = 0; +- u32 user_base_data = 0, base_vector = 0, base_idx; ++ u32 user_base_data = 0, base_vector = 0; + +- base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; + ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", + &num_vectors, + &user_base_data, +@@ -774,7 +774,7 @@ static int ath11k_pci_ext_irq_config(str + } + + irq_grp->num_irq = num_irq; +- irq_grp->irqs[0] = base_idx + i; ++ irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; + + for (j = 0; j < irq_grp->num_irq; j++) { + int irq_idx = irq_grp->irqs[j]; diff --git a/package/kernel/mac80211/patches/ath11k/0106-ath11k-refactor-multiple-MSI-vector-implementation.patch b/package/kernel/mac80211/patches/ath11k/0106-ath11k-refactor-multiple-MSI-vector-implementation.patch new file mode 100644 index 000000000..2716195f5 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0106-ath11k-refactor-multiple-MSI-vector-implementation.patch @@ -0,0 +1,173 @@ +From c41a6700b276ddf6ef93dcb43baca51ea0c4c7c1 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: refactor multiple MSI vector implementation + +This is to prepare for one MSI vector support. IRQ enable and disable +of CE and DP are done only in case of multiple MSI vectors. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041705.5167-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 48 ++++++++++++++++++++++----- + drivers/net/wireless/ath/ath11k/pci.h | 3 ++ + 2 files changed, 43 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -486,11 +486,11 @@ int ath11k_pci_get_user_msi_assignment(s + for (idx = 0; idx < msi_config->total_users; idx++) { + if (strcmp(user_name, msi_config->users[idx].name) == 0) { + *num_vectors = msi_config->users[idx].num_vectors; +- *user_base_data = msi_config->users[idx].base_vector +- + ab_pci->msi_ep_base_data; +- *base_vector = msi_config->users[idx].base_vector; ++ *base_vector = msi_config->users[idx].base_vector; ++ *user_base_data = *base_vector + ab_pci->msi_ep_base_data; + +- ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", ++ ath11k_dbg(ab, ATH11K_DBG_PCI, ++ "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + user_name, *num_vectors, *user_base_data, + *base_vector); + +@@ -561,16 +561,30 @@ static void ath11k_pci_free_irq(struct a + + static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 irq_idx; + ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + enable_irq(ab->irq_num[irq_idx]); + } + + static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 irq_idx; + ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + disable_irq_nosync(ab->irq_num[irq_idx]); + } +@@ -630,8 +644,15 @@ static irqreturn_t ath11k_pci_ce_interru + + static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); + int i; + ++ /* In case of one MSI vector, we handle irq enable/disable ++ * in a uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + for (i = 0; i < irq_grp->num_irq; i++) + disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } +@@ -657,8 +678,15 @@ static void __ath11k_pci_ext_irq_disable + + static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); + int i; + ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + for (i = 0; i < irq_grp->num_irq; i++) + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } +@@ -742,6 +770,7 @@ static irqreturn_t ath11k_pci_ext_interr + + static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + int i, j, ret, num_vectors = 0; + u32 user_base_data = 0, base_vector = 0; + +@@ -788,16 +817,15 @@ static int ath11k_pci_ext_irq_config(str + + irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); + ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, +- IRQF_SHARED, ++ ab_pci->irq_flags, + "DP_EXT_IRQ", irq_grp); + if (ret) { + ath11k_err(ab, "failed request irq %d: %d\n", + vector, ret); + return ret; + } +- +- disable_irq_nosync(ab->irq_num[irq_idx]); + } ++ ath11k_pci_ext_grp_disable(irq_grp); + } + + return 0; +@@ -805,6 +833,7 @@ static int ath11k_pci_ext_irq_config(str + + static int ath11k_pci_config_irq(struct ath11k_base *ab) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + struct ath11k_ce_pipe *ce_pipe; + u32 msi_data_start; + u32 msi_data_count, msi_data_idx; +@@ -832,7 +861,7 @@ static int ath11k_pci_config_irq(struct + tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); + + ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, +- IRQF_SHARED, irq_name[irq_idx], ++ ab_pci->irq_flags, irq_name[irq_idx], + ce_pipe); + if (ret) { + ath11k_err(ab, "failed to request irq %d: %d\n", +@@ -926,6 +955,9 @@ static int ath11k_pci_alloc_msi(struct a + return -EINVAL; + else + return num_vectors; ++ } else { ++ set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); ++ ab_pci->irq_flags = IRQF_SHARED; + } + ath11k_pci_msi_disable(ab_pci); + +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -68,6 +68,7 @@ enum ath11k_pci_flags { + ATH11K_PCI_FLAG_INIT_DONE, + ATH11K_PCI_FLAG_IS_MSI_64, + ATH11K_PCI_ASPM_RESTORE, ++ ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, + }; + + struct ath11k_pci { +@@ -87,6 +88,8 @@ struct ath11k_pci { + /* enum ath11k_pci_flags */ + unsigned long flags; + u16 link_ctl; ++ ++ unsigned long irq_flags; + }; + + static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) diff --git a/package/kernel/mac80211/patches/ath11k/0107-ath11k-add-support-one-MSI-vector.patch b/package/kernel/mac80211/patches/ath11k/0107-ath11k-add-support-one-MSI-vector.patch new file mode 100644 index 000000000..cb76177c7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0107-ath11k-add-support-one-MSI-vector.patch @@ -0,0 +1,195 @@ +From ac6e73483f7b4b5bde23b14fc3aaafc8341ae0c7 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: add support one MSI vector + +On some platforms it's not possible to allocate 32 MSI vectors for various +reasons, be it kernel configuration, VT-d disabled, buggy BIOS etc. So +ath11k was not able to use QCA6390 PCI devices on those platforms. Add +support for one MSI vector to solve that. + +In case of one MSI vector, interrupt migration needs to be disabled. This +is because when interrupt migration happens, the msi_data may change. +However, msi_data is already programmed to rings during initial phase and +ath11k has no way to know that msi_data is changed during run time and +reprogram again. + +In case of one MSI vector, MHI subsystem should not use IRQF_NO_SUSPEND +as QCA6390 doesn't set this flag too. Ath11k doesn't need to leave +IRQ enabled in suspend state. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041714.5219-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 14 ++++++-- + drivers/net/wireless/ath/ath11k/pci.c | 52 ++++++++++++++++++++------- + 2 files changed, 51 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -248,6 +248,7 @@ static int ath11k_mhi_get_msi(struct ath + u32 user_base_data, base_vector; + int ret, num_vectors, i; + int *irq; ++ unsigned int msi_data; + + ret = ath11k_pci_get_user_msi_assignment(ab_pci, + "MHI", &num_vectors, +@@ -262,9 +263,15 @@ static int ath11k_mhi_get_msi(struct ath + if (!irq) + return -ENOMEM; + +- for (i = 0; i < num_vectors; i++) ++ for (i = 0; i < num_vectors; i++) { ++ msi_data = base_vector; ++ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ msi_data += i; ++ + irq[i] = ath11k_pci_get_msi_irq(ab->dev, +- base_vector + i); ++ msi_data); ++ } + + ab_pci->mhi_ctrl->irq = irq; + ab_pci->mhi_ctrl->nr_irqs = num_vectors; +@@ -341,6 +348,9 @@ int ath11k_mhi_register(struct ath11k_pc + return ret; + } + ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; ++ + mhi_ctrl->iova_start = 0; + mhi_ctrl->iova_stop = 0xffffffff; + mhi_ctrl->sbl_size = SZ_512K; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -77,6 +77,17 @@ static const struct ath11k_msi_config at + }, + }; + ++static const struct ath11k_msi_config msi_config_one_msi = { ++ .total_vectors = 1, ++ .total_users = 4, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, ++ { .name = "CE", .num_vectors = 1, .base_vector = 0 }, ++ { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, ++ { .name = "DP", .num_vectors = 1, .base_vector = 0 }, ++ }, ++}; ++ + static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { + "bhi", + "mhi-er0", +@@ -619,16 +630,18 @@ static void ath11k_pci_sync_ce_irqs(stru + static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) + { + struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); ++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); + +- ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); ++ enable_irq(ce_pipe->ab->irq_num[irq_idx]); + } + + static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) + { + struct ath11k_ce_pipe *ce_pipe = arg; + struct ath11k_base *ab = ce_pipe->ab; ++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; +@@ -636,7 +649,8 @@ static irqreturn_t ath11k_pci_ce_interru + /* last interrupt received for this CE */ + ce_pipe->timestamp = jiffies; + +- ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); ++ disable_irq_nosync(ab->irq_num[irq_idx]); ++ + tasklet_schedule(&ce_pipe->intr_tq); + + return IRQ_HANDLED; +@@ -735,11 +749,13 @@ static int ath11k_pci_ext_grp_napi_poll( + napi); + struct ath11k_base *ab = irq_grp->ab; + int work_done; ++ int i; + + work_done = ath11k_dp_service_srng(ab, irq_grp, budget); + if (work_done < budget) { + napi_complete_done(napi, work_done); +- ath11k_pci_ext_grp_enable(irq_grp); ++ for (i = 0; i < irq_grp->num_irq; i++) ++ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } + + if (work_done > budget) +@@ -752,6 +768,7 @@ static irqreturn_t ath11k_pci_ext_interr + { + struct ath11k_ext_irq_grp *irq_grp = arg; + struct ath11k_base *ab = irq_grp->ab; ++ int i; + + if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; +@@ -761,7 +778,8 @@ static irqreturn_t ath11k_pci_ext_interr + /* last interrupt received for this group */ + irq_grp->timestamp = jiffies; + +- ath11k_pci_ext_grp_disable(irq_grp); ++ for (i = 0; i < irq_grp->num_irq; i++) ++ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + + napi_schedule(&irq_grp->napi); + +@@ -947,18 +965,25 @@ static int ath11k_pci_alloc_msi(struct a + msi_config->total_vectors, + msi_config->total_vectors, + PCI_IRQ_MSI); +- if (num_vectors != msi_config->total_vectors) { +- ath11k_err(ab, "failed to get %d MSI vectors, only %d available", +- msi_config->total_vectors, num_vectors); +- +- if (num_vectors >= 0) +- return -EINVAL; +- else +- return num_vectors; +- } else { ++ if (num_vectors == msi_config->total_vectors) { + set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->irq_flags = IRQF_SHARED; ++ } else { ++ num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, ++ 1, ++ 1, ++ PCI_IRQ_MSI); ++ if (num_vectors < 0) { ++ ret = -EINVAL; ++ goto reset_msi_config; ++ } ++ clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); ++ ab_pci->msi_config = &msi_config_one_msi; ++ ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; ++ ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); + } ++ ath11k_info(ab, "MSI vectors: %d\n", num_vectors); ++ + ath11k_pci_msi_disable(ab_pci); + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); +@@ -979,6 +1004,7 @@ static int ath11k_pci_alloc_msi(struct a + free_msi_vector: + pci_free_irq_vectors(ab_pci->pdev); + ++reset_msi_config: + return ret; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0108-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vec.patch b/package/kernel/mac80211/patches/ath11k/0108-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vec.patch new file mode 100644 index 000000000..18eec3d3c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0108-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vec.patch @@ -0,0 +1,41 @@ +From 915a081ff307d61d6551d6c16b542e03775353c4 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: do not restore ASPM in case of single MSI vector + +Current code enables ASPM by default, it allows MHI to enter M2 state. +In case of one MSI vector, system hang is observed if ath11k does MHI +register reading in this state. The issue was reported on Dell XPS 13 +9310 but is seen also on XPS 15 and XPS 17 laptops. + +The workaround here is to prevent MHI from entering M2 state, this can +be done by disabling ASPM if only one MSI vector is used. When using 32 +vectors ASPM is enabled as before. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041722.5271-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -1229,7 +1229,13 @@ static int ath11k_pci_start(struct ath11 + + set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); + +- ath11k_pci_aspm_restore(ab_pci); ++ /* TODO: for now don't restore ASPM in case of single MSI ++ * vector as MHI register reading in M2 causes system hang. ++ */ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ ath11k_pci_aspm_restore(ab_pci); ++ else ++ ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); + + ath11k_pci_ce_irqs_enable(ab); + ath11k_ce_rx_post_buf(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0109-ath11k-Set-IRQ-affinity-to-CPU0-in-case-of-one-MSI-v.patch b/package/kernel/mac80211/patches/ath11k/0109-ath11k-Set-IRQ-affinity-to-CPU0-in-case-of-one-MSI-v.patch new file mode 100644 index 000000000..e86edad03 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0109-ath11k-Set-IRQ-affinity-to-CPU0-in-case-of-one-MSI-v.patch @@ -0,0 +1,89 @@ +From e94b07493da31705c3fdd0b2854f0cffe1dacb3c Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH] ath11k: Set IRQ affinity to CPU0 in case of one MSI vector + +With VT-d disabled on Intel platform, ath11k gets only one MSI +vector. In that case, ath11k does not free IRQ when doing suspend, +hence the kernel has to migrate it to CPU0 (if it was affine to +other CPUs) and allocates a new MSI vector. However, ath11k has +no chance to reconfig it to HW srngs during this phase, thus +ath11k fails to resume. + +This issue can be fixed by setting IRQ affinity to CPU0 before +request_irq is called. With such affinity, migration will not +happen and thus the vector keeps unchanged during suspend/resume. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026041732.5323-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -849,6 +849,15 @@ static int ath11k_pci_ext_irq_config(str + return 0; + } + ++static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m) ++{ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return 0; ++ ++ return irq_set_affinity_hint(ab_pci->pdev->irq, m); ++} ++ + static int ath11k_pci_config_irq(struct ath11k_base *ab) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +@@ -865,6 +874,12 @@ static int ath11k_pci_config_irq(struct + if (ret) + return ret; + ++ ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); ++ if (ret) { ++ ath11k_err(ab, "failed to set irq affinity %d\n", ret); ++ return ret; ++ } ++ + /* Configure CE irqs */ + for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +@@ -884,7 +899,7 @@ static int ath11k_pci_config_irq(struct + if (ret) { + ath11k_err(ab, "failed to request irq %d: %d\n", + irq_idx, ret); +- return ret; ++ goto err_irq_affinity_cleanup; + } + + ab->irq_num[irq_idx] = irq; +@@ -895,9 +910,13 @@ static int ath11k_pci_config_irq(struct + + ret = ath11k_pci_ext_irq_config(ab); + if (ret) +- return ret; ++ goto err_irq_affinity_cleanup; + + return 0; ++ ++err_irq_affinity_cleanup: ++ ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); ++ return ret; + } + + static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) +@@ -1494,6 +1513,8 @@ static void ath11k_pci_remove(struct pci + struct ath11k_base *ab = pci_get_drvdata(pdev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + ++ ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); ++ + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { + ath11k_pci_power_down(ab); + ath11k_debugfs_soc_destroy(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0110-ath11k-change-to-treat-alpha-code-na-as-world-wide-r.patch b/package/kernel/mac80211/patches/ath11k/0110-ath11k-change-to-treat-alpha-code-na-as-world-wide-r.patch new file mode 100644 index 000000000..a8de4524d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0110-ath11k-change-to-treat-alpha-code-na-as-world-wide-r.patch @@ -0,0 +1,35 @@ +From f8108250e331b8f0273c53afb9e2db5068e59b2e Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:57 +0200 +Subject: [PATCH] ath11k: change to treat alpha code na as world wide regdomain + +Some firmware versions for WCN6855 report the default regdomain with +alpha code "na" by default when load as a world wide regdomain, ath11k +should treat it as a world wide alpha code. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118094848.7776-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -5927,7 +5927,13 @@ static void ath11k_wmi_htc_tx_complete(s + + static bool ath11k_reg_is_world_alpha(char *alpha) + { +- return alpha[0] == '0' && alpha[1] == '0'; ++ if (alpha[0] == '0' && alpha[1] == '0') ++ return true; ++ ++ if (alpha[0] == 'n' && alpha[1] == 'a') ++ return true; ++ ++ return false; + } + + static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb) diff --git a/package/kernel/mac80211/patches/ath11k/0111-ath11k-calculate-the-correct-NSS-of-peer-for-HE-capa.patch b/package/kernel/mac80211/patches/ath11k/0111-ath11k-calculate-the-correct-NSS-of-peer-for-HE-capa.patch new file mode 100644 index 000000000..f0d3f46a6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0111-ath11k-calculate-the-correct-NSS-of-peer-for-HE-capa.patch @@ -0,0 +1,80 @@ +From 3db26ecf7114370e451e296e33a0af3303d32819 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:57 +0200 +Subject: [PATCH] ath11k: calculate the correct NSS of peer for HE capabilities + +When connected to 6G mode AP, it does not have VHT/HT capabilities, +so the NSS is not set, then it is 1 by default. + +This patch is to calculate the NSS with supported HE-MCS and NSS set +of HE capabilities. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01280-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118095453.8030-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 37 ++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1921,7 +1921,6 @@ static void ath11k_peer_assoc_h_he(struc + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct cfg80211_chan_def def; + const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; +- u8 ampdu_factor; + enum nl80211_band band; + u16 *he_mcs_mask; + u8 max_nss, he_mcs; +@@ -1929,6 +1928,9 @@ static void ath11k_peer_assoc_h_he(struc + int i, he_nss, nss_idx; + bool user_rate_valid = true; + u32 rx_nss, tx_nss, nss_160; ++ u8 ampdu_factor, rx_mcs_80, rx_mcs_160; ++ u16 mcs_160_map, mcs_80_map; ++ bool support_160; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1943,6 +1945,39 @@ static void ath11k_peer_assoc_h_he(struc + return; + + arg->he_flag = true; ++ support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G); ++ ++ /* Supported HE-MCS and NSS Set of peer he_cap is intersection with self he_cp */ ++ mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); ++ mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); ++ ++ if (support_160) { ++ for (i = 7; i >= 0; i--) { ++ u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; ++ ++ if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { ++ rx_mcs_160 = i + 1; ++ break; ++ } ++ } ++ } ++ ++ for (i = 7; i >= 0; i--) { ++ u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; ++ ++ if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { ++ rx_mcs_80 = i + 1; ++ break; ++ } ++ } ++ ++ if (support_160) ++ max_nss = min(rx_mcs_80, rx_mcs_160); ++ else ++ max_nss = rx_mcs_80; ++ ++ arg->peer_nss = min(sta->rx_nss, max_nss); + + memcpy_and_pad(&arg->peer_he_cap_macinfo, + sizeof(arg->peer_he_cap_macinfo), diff --git a/package/kernel/mac80211/patches/ath11k/0112-ath11k-fix-read-fail-for-htt_stats-and-htt_peer_stat.patch b/package/kernel/mac80211/patches/ath11k/0112-ath11k-fix-read-fail-for-htt_stats-and-htt_peer_stat.patch new file mode 100644 index 000000000..f5385af6c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0112-ath11k-fix-read-fail-for-htt_stats-and-htt_peer_stat.patch @@ -0,0 +1,206 @@ +From 1370634054d4e1e4794057b06ac651b6366ce97d Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH] ath11k: fix read fail for htt_stats and htt_peer_stats for + single pdev + +The pdev id is set to 0 for single pdev configured hardware, the real +pdev id is not 0 in firmware, for example, its pdev id is 1 for 5G/6G +phy and 2 for 2G band phy. For HTT_H2T_MSG_TYPE_EXT_STATS_CFG message, +firmware parse the pdev_mask to its pdev id, ath11k set it to 0 for +single pdev, it is not correct, need set it with the real pdev id of +firmware. + +Save the real pdev id report by firmware and set it correctly. + +Below commands run success with this patch: +cat /sys/kernel/debug/ieee80211/phy0/ath11k/htt_stats +cat /sys/kernel/debug/ieee80211/phy0/netdev\:wls1/stations/00\:03\:7f\:75\:59\:85/htt_peer_stats + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118095700.8149-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 5 ++ + drivers/net/wireless/ath/ath11k/dp_tx.c | 9 +++- + drivers/net/wireless/ath/ath11k/mac.c | 61 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/mac.h | 4 ++ + drivers/net/wireless/ath/ath11k/wmi.c | 6 +++ + drivers/net/wireless/ath/ath11k/wmi.h | 4 +- + 6 files changed, 86 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -714,6 +714,11 @@ struct ath11k_base { + /* Protects data like peers */ + spinlock_t base_lock; + struct ath11k_pdev pdevs[MAX_RADIOS]; ++ struct { ++ enum WMI_HOST_WLAN_BAND supported_bands; ++ u32 pdev_id; ++ } target_pdev_ids[MAX_RADIOS]; ++ u8 target_pdev_count; + struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS]; + struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS]; + unsigned long long free_vdev_map; +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -9,6 +9,7 @@ + #include "debugfs_sta.h" + #include "hw.h" + #include "peer.h" ++#include "mac.h" + + static enum hal_tcl_encap_type + ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb) +@@ -985,6 +986,7 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struc + struct ath11k_dp *dp = &ab->dp; + struct sk_buff *skb; + struct htt_ext_stats_cfg_cmd *cmd; ++ u32 pdev_id; + int len = sizeof(*cmd); + int ret; + +@@ -998,7 +1000,12 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struc + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG; + +- cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id; ++ if (ab->hw_params.single_pdev_only) ++ pdev_id = ath11k_mac_get_target_pdev_id(ar); ++ else ++ pdev_id = ar->pdev->pdev_id; ++ ++ cmd->hdr.pdev_mask = 1 << pdev_id; + + cmd->hdr.stats_type = type; + cmd->cfg_param0 = cfg_params->cfg0; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -554,6 +554,67 @@ struct ath11k *ath11k_mac_get_ar_by_pdev + return NULL; + } + ++struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ struct ath11k_vif *arvif; ++ int i; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif->is_up) ++ return arvif; ++ } ++ } ++ ++ return NULL; ++} ++ ++static bool ath11k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BAND band2) ++{ ++ return (((band1 == NL80211_BAND_2GHZ) && (band2 & WMI_HOST_WLAN_2G_CAP)) || ++ (((band1 == NL80211_BAND_5GHZ) || (band1 == NL80211_BAND_6GHZ)) && ++ (band2 & WMI_HOST_WLAN_5G_CAP))); ++} ++ ++u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif) ++{ ++ struct ath11k *ar = arvif->ar; ++ struct ath11k_base *ab = ar->ab; ++ struct ieee80211_vif *vif = arvif->vif; ++ struct cfg80211_chan_def def; ++ enum nl80211_band band; ++ u8 pdev_id = ab->target_pdev_ids[0].pdev_id; ++ int i; ++ ++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) ++ return pdev_id; ++ ++ band = def.chan->band; ++ ++ for (i = 0; i < ab->target_pdev_count; i++) { ++ if (ath11k_mac_band_match(band, ab->target_pdev_ids[i].supported_bands)) ++ return ab->target_pdev_ids[i].pdev_id; ++ } ++ ++ return pdev_id; ++} ++ ++u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ ++ arvif = ath11k_mac_get_vif_up(ar->ab); ++ ++ if (arvif) ++ return ath11k_mac_get_target_pdev_id_from_vif(arvif); ++ else ++ return ar->ab->target_pdev_ids[0].pdev_id; ++} ++ + static void ath11k_pdev_caps_update(struct ath11k *ar) + { + struct ath11k_base *ab = ar->ab; +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -144,6 +144,10 @@ void ath11k_mac_scan_finish(struct ath11 + struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id); + struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab, + u32 vdev_id); ++u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar); ++u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif); ++struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab); ++ + struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id); + struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id); + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -337,6 +337,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + struct ath11k_pdev *pdev) + { + struct wmi_mac_phy_capabilities *mac_phy_caps; ++ struct ath11k_base *ab = wmi_handle->wmi_ab->ab; + struct ath11k_band_cap *cap_band; + struct ath11k_pdev_cap *pdev_cap = &pdev->cap; + u32 phy_map; +@@ -368,6 +369,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + pdev->pdev_id = mac_phy_caps->pdev_id; + pdev_cap->supported_bands |= mac_phy_caps->supported_bands; + pdev_cap->ampdu_density = mac_phy_caps->ampdu_density; ++ ab->target_pdev_ids[ab->target_pdev_count].supported_bands = ++ mac_phy_caps->supported_bands; ++ ab->target_pdev_ids[ab->target_pdev_count].pdev_id = mac_phy_caps->pdev_id; ++ ab->target_pdev_count++; + + /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from + * band to band for a single radio, need to see how this should be +@@ -4230,6 +4235,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_re + svc_rdy_ext->param.num_phy = svc_rdy_ext->soc_hal_reg_caps->num_phy; + + soc->num_radios = 0; ++ soc->target_pdev_count = 0; + phy_id_map = svc_rdy_ext->pref_hw_mode_caps.phy_id_map; + + while (phy_id_map && soc->num_radios < MAX_RADIOS) { +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -113,10 +113,10 @@ enum wmi_host_hw_mode_priority { + WMI_HOST_HW_MODE_MAX_PRI + }; + +-enum { ++enum WMI_HOST_WLAN_BAND { + WMI_HOST_WLAN_2G_CAP = 0x1, + WMI_HOST_WLAN_5G_CAP = 0x2, +- WMI_HOST_WLAN_2G_5G_CAP = 0x3, ++ WMI_HOST_WLAN_2G_5G_CAP = WMI_HOST_WLAN_2G_CAP | WMI_HOST_WLAN_5G_CAP, + }; + + /* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. diff --git a/package/kernel/mac80211/patches/ath11k/0113-ath11k-skip-sending-vdev-down-for-channel-switch.patch b/package/kernel/mac80211/patches/ath11k/0113-ath11k-skip-sending-vdev-down-for-channel-switch.patch new file mode 100644 index 000000000..d0ae98c49 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0113-ath11k-skip-sending-vdev-down-for-channel-switch.patch @@ -0,0 +1,68 @@ +From a4146249a33381f41f6d15eaa1797d7ba1820a31 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH] ath11k: skip sending vdev down for channel switch + +The ath11k driver currently sends vdev down to the firmware before +updating the channel context, which is followed by a vdev restart +command. + +Sending vdev down is not required before sending a vdev restart, +because the firmware internally does vdev down when ath11k sends +a vdev restart command. + +Firmware will happen crash while channel switch without this change. + +Hence skip the vdev down command sending when updating the channel +context and then fix the firmware crash issue. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118095901.8271-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 32 +-------------------------- + 1 file changed, 1 insertion(+), 31 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6467,37 +6467,7 @@ ath11k_mac_update_vif_chan(struct ath11k + + lockdep_assert_held(&ar->conf_mutex); + +- for (i = 0; i < n_vifs; i++) { +- arvif = (void *)vifs[i].vif->drv_priv; +- +- if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) +- monitor_vif = true; +- +- ath11k_dbg(ab, ATH11K_DBG_MAC, +- "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", +- arvif->vdev_id, +- vifs[i].old_ctx->def.chan->center_freq, +- vifs[i].new_ctx->def.chan->center_freq, +- vifs[i].old_ctx->def.width, +- vifs[i].new_ctx->def.width); +- +- if (WARN_ON(!arvif->is_started)) +- continue; +- +- if (WARN_ON(!arvif->is_up)) +- continue; +- +- ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id); +- if (ret) { +- ath11k_warn(ab, "failed to down vdev %d: %d\n", +- arvif->vdev_id, ret); +- continue; +- } +- +- ar->num_started_vdevs--; +- } +- +- /* All relevant vdevs are downed and associated channel resources ++ /* Associated channel resources of all relevant vdevs + * should be available for the channel switch now. + */ + diff --git a/package/kernel/mac80211/patches/ath11k/0114-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch b/package/kernel/mac80211/patches/ath11k/0114-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch new file mode 100644 index 000000000..9f93f4401 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0114-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch @@ -0,0 +1,157 @@ +From 46e46db313a2bf3c48cac4eb8bdb613b762f301b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH] ath11k: add read variant from SMBIOS for download board data + +This is to read variant from SMBIOS such as read from DT, the variant +string will be used to one part of string which used to search board +data from board-2.bin. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118100033.8384-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 79 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 13 +++++ + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++ + 3 files changed, 96 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#include ++#include ++ + #include "core.h" + #include "dp_tx.h" + #include "dp_rx.h" +@@ -384,6 +387,82 @@ int ath11k_core_resume(struct ath11k_bas + } + EXPORT_SYMBOL(ath11k_core_resume); + ++static void ath11k_core_check_bdfext(const struct dmi_header *hdr, void *data) ++{ ++ struct ath11k_base *ab = data; ++ const char *bdf_ext; ++ const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC; ++ u8 bdf_enabled; ++ int i; ++ size_t len; ++ ++ if (ab->qmi.target.bdf_ext[0] != '\0') ++ return; ++ ++ if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE) ++ return; ++ ++ if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "wrong smbios bdf ext type length (%d).\n", ++ hdr->length); ++ return; ++ } ++ ++ bdf_enabled = *((u8 *)hdr + ATH11K_SMBIOS_BDF_EXT_OFFSET); ++ if (!bdf_enabled) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n"); ++ return; ++ } ++ ++ /* Only one string exists (per spec) */ ++ bdf_ext = (char *)hdr + hdr->length; ++ ++ if (memcmp(bdf_ext, magic, strlen(magic)) != 0) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant magic does not match.\n"); ++ return; ++ } ++ ++ len = strlen(bdf_ext); ++ for (i = 0; i < len; i++) { ++ if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant name contains non ascii chars.\n"); ++ return; ++ } ++ } ++ ++ /* Copy extension name without magic prefix */ ++ if (strscpy(ab->qmi.target.bdf_ext, bdf_ext + strlen(magic), ++ sizeof(ab->qmi.target.bdf_ext)) < 0) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", ++ bdf_ext); ++ return; ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "found and validated bdf variant smbios_type 0x%x bdf %s\n", ++ ATH11K_SMBIOS_BDF_EXT_TYPE, bdf_ext); ++} ++ ++int ath11k_core_check_smbios(struct ath11k_base *ab) ++{ ++ int ret; ++ ++ ab->qmi.target.bdf_ext[0] = '\0'; ++ ++ ret = dmi_walk(ath11k_core_check_bdfext, ab); ++ if (ret) ++ return ret; ++ ++ if (ab->qmi.target.bdf_ext[0] == '\0') ++ return -ENODATA; ++ ++ return 0; ++} ++ + int ath11k_core_check_dt(struct ath11k_base *ab) + { + size_t max_len = sizeof(ab->qmi.target.bdf_ext); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -938,6 +938,18 @@ struct ath11k_fw_stats_bcn { + u32 tx_bcn_outage_cnt; + }; + ++/* SMBIOS type containing Board Data File Name Extension */ ++#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8 ++ ++/* SMBIOS type structure length (excluding strings-set) */ ++#define ATH11K_SMBIOS_BDF_EXT_LENGTH 0x9 ++ ++/* Offset pointing to Board Data File Name Extension */ ++#define ATH11K_SMBIOS_BDF_EXT_OFFSET 0x8 ++ ++/* The magic used by QCA spec */ ++#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_" ++ + extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[]; +@@ -959,6 +971,7 @@ int ath11k_core_fetch_bdf(struct ath11k_ + struct ath11k_board_data *bd); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); ++int ath11k_core_check_smbios(struct ath11k_base *ab); + + void ath11k_core_halt(struct ath11k *ar); + int ath11k_core_resume(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1991,6 +1991,10 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.fw_build_timestamp, + ab->qmi.target.fw_build_id); + ++ r = ath11k_core_check_smbios(ab); ++ if (r) ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "SMBIOS bdf variant name not set.\n"); ++ + r = ath11k_core_check_dt(ab); + if (r) + ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0115-ath11k-Fix-mon-status-ring-rx-tlv-processing.patch b/package/kernel/mac80211/patches/ath11k/0115-ath11k-Fix-mon-status-ring-rx-tlv-processing.patch new file mode 100644 index 000000000..b3e908d55 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0115-ath11k-Fix-mon-status-ring-rx-tlv-processing.patch @@ -0,0 +1,65 @@ +From 09f16f7390f302937409738d6cb6ce99b265f455 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH] ath11k: Fix mon status ring rx tlv processing + +In HE monitor capture, HAL_TLV_STATUS_PPDU_DONE is received +on processing multiple skb. Do not clear the ppdu_info +till the HAL_TLV_STATUS_PPDU_DONE is received. + +This fixes below warning and packet drops in monitor mode. + "Rate marked as an HE rate but data is invalid: MCS: 6, NSS: 0" + WARNING: at + PC is at ieee80211_rx_napi+0x624/0x840 [mac80211] + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01693-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1637249433-10316-1-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -3061,10 +3061,10 @@ int ath11k_dp_rx_process_mon_status(stru + if (!num_buffs_reaped) + goto exit; + +- while ((skb = __skb_dequeue(&skb_list))) { +- memset(&ppdu_info, 0, sizeof(ppdu_info)); +- ppdu_info.peer_id = HAL_INVALID_PEERID; ++ memset(&ppdu_info, 0, sizeof(ppdu_info)); ++ ppdu_info.peer_id = HAL_INVALID_PEERID; + ++ while ((skb = __skb_dequeue(&skb_list))) { + if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { + log_type = ATH11K_PKTLOG_TYPE_LITE_RX; + rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; +@@ -3092,10 +3092,7 @@ int ath11k_dp_rx_process_mon_status(stru + ath11k_dbg(ab, ATH11K_DBG_DATA, + "failed to find the peer with peer_id %d\n", + ppdu_info.peer_id); +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); +- dev_kfree_skb_any(skb); +- continue; ++ goto next_skb; + } + + arsta = (struct ath11k_sta *)peer->sta->drv_priv; +@@ -3104,10 +3101,13 @@ int ath11k_dp_rx_process_mon_status(stru + if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + ++next_skb: + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + + dev_kfree_skb_any(skb); ++ memset(&ppdu_info, 0, sizeof(ppdu_info)); ++ ppdu_info.peer_id = HAL_INVALID_PEERID; + } + exit: + return num_buffs_reaped; diff --git a/package/kernel/mac80211/patches/ath11k/0116-Revert-ath11k-add-read-variant-from-SMBIOS-for-downl.patch b/package/kernel/mac80211/patches/ath11k/0116-Revert-ath11k-add-read-variant-from-SMBIOS-for-downl.patch new file mode 100644 index 000000000..f4241394d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0116-Revert-ath11k-add-read-variant-from-SMBIOS-for-downl.patch @@ -0,0 +1,168 @@ +From 72f4124347724e3b8aa434f6bc4a2cd69f7bb336 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Wed, 24 Nov 2021 11:43:16 +0200 +Subject: [PATCH] Revert "ath11k: add read variant from SMBIOS for download + board data" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 46e46db313a2bf3c48cac4eb8bdb613b762f301b. Mark reported +that it breaks QCA6390 hw2.0 on Dell XPS 13 9310: + +[    5.537034] ath11k_pci 0000:72:00.0: chip_id 0x0 chip_family 0xb board_id 0xff soc_id 0xffffffff +[    5.537038] ath11k_pci 0000:72:00.0: fw_version 0x101c06cc fw_build_timestamp 2020-06-24 19:50 fw_build_id +[    5.537236] ath11k_pci 0000:72:00.0: failed to fetch board data for bus=pci,qmi-chip-id=0,qmi-board-id=255,variant=DE_1901 from ath11k/QCA6390/hw2.0/board-2.bin +[    5.537255] ath11k_pci 0000:72:00.0: failed to fetch board-2.bin or board.bin from QCA6390/hw2.0 +[    5.537257] ath11k_pci 0000:72:00.0: qmi failed to fetch board file: -2 +[    5.537258] ath11k_pci 0000:72:00.0: failed to load board data file: -2 + +So we need to back to the drawing board and implement it so that backwards +compatiblity is not broken. + +Reported-by: Mark Herbert +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211124094316.9096-1-kvalo@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 79 -------------------------- + drivers/net/wireless/ath/ath11k/core.h | 13 ----- + drivers/net/wireless/ath/ath11k/qmi.c | 4 -- + 3 files changed, 96 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -8,9 +8,6 @@ + #include + #include + #include +-#include +-#include +- + #include "core.h" + #include "dp_tx.h" + #include "dp_rx.h" +@@ -387,82 +384,6 @@ int ath11k_core_resume(struct ath11k_bas + } + EXPORT_SYMBOL(ath11k_core_resume); + +-static void ath11k_core_check_bdfext(const struct dmi_header *hdr, void *data) +-{ +- struct ath11k_base *ab = data; +- const char *bdf_ext; +- const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC; +- u8 bdf_enabled; +- int i; +- size_t len; +- +- if (ab->qmi.target.bdf_ext[0] != '\0') +- return; +- +- if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE) +- return; +- +- if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "wrong smbios bdf ext type length (%d).\n", +- hdr->length); +- return; +- } +- +- bdf_enabled = *((u8 *)hdr + ATH11K_SMBIOS_BDF_EXT_OFFSET); +- if (!bdf_enabled) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n"); +- return; +- } +- +- /* Only one string exists (per spec) */ +- bdf_ext = (char *)hdr + hdr->length; +- +- if (memcmp(bdf_ext, magic, strlen(magic)) != 0) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "bdf variant magic does not match.\n"); +- return; +- } +- +- len = strlen(bdf_ext); +- for (i = 0; i < len; i++) { +- if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "bdf variant name contains non ascii chars.\n"); +- return; +- } +- } +- +- /* Copy extension name without magic prefix */ +- if (strscpy(ab->qmi.target.bdf_ext, bdf_ext + strlen(magic), +- sizeof(ab->qmi.target.bdf_ext)) < 0) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", +- bdf_ext); +- return; +- } +- +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "found and validated bdf variant smbios_type 0x%x bdf %s\n", +- ATH11K_SMBIOS_BDF_EXT_TYPE, bdf_ext); +-} +- +-int ath11k_core_check_smbios(struct ath11k_base *ab) +-{ +- int ret; +- +- ab->qmi.target.bdf_ext[0] = '\0'; +- +- ret = dmi_walk(ath11k_core_check_bdfext, ab); +- if (ret) +- return ret; +- +- if (ab->qmi.target.bdf_ext[0] == '\0') +- return -ENODATA; +- +- return 0; +-} +- + int ath11k_core_check_dt(struct ath11k_base *ab) + { + size_t max_len = sizeof(ab->qmi.target.bdf_ext); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -938,18 +938,6 @@ struct ath11k_fw_stats_bcn { + u32 tx_bcn_outage_cnt; + }; + +-/* SMBIOS type containing Board Data File Name Extension */ +-#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8 +- +-/* SMBIOS type structure length (excluding strings-set) */ +-#define ATH11K_SMBIOS_BDF_EXT_LENGTH 0x9 +- +-/* Offset pointing to Board Data File Name Extension */ +-#define ATH11K_SMBIOS_BDF_EXT_OFFSET 0x8 +- +-/* The magic used by QCA spec */ +-#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_" +- + extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[]; +@@ -971,7 +959,6 @@ int ath11k_core_fetch_bdf(struct ath11k_ + struct ath11k_board_data *bd); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); +-int ath11k_core_check_smbios(struct ath11k_base *ab); + + void ath11k_core_halt(struct ath11k *ar); + int ath11k_core_resume(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1991,10 +1991,6 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.fw_build_timestamp, + ab->qmi.target.fw_build_id); + +- r = ath11k_core_check_smbios(ab); +- if (r) +- ath11k_dbg(ab, ATH11K_DBG_QMI, "SMBIOS bdf variant name not set.\n"); +- + r = ath11k_core_check_dt(ab); + if (r) + ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0117-ath11k-Fix-spelling-mistake-detetction-detection.patch b/package/kernel/mac80211/patches/ath11k/0117-ath11k-Fix-spelling-mistake-detetction-detection.patch new file mode 100644 index 000000000..751c2b1c9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0117-ath11k-Fix-spelling-mistake-detetction-detection.patch @@ -0,0 +1,25 @@ +From c27506cc7733261bafd7a97e7990407eef433d32 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Tue, 23 Nov 2021 09:04:31 +0000 +Subject: [PATCH] ath11k: Fix spelling mistake "detetction" -> "detection" + +There is a spelling mistake in an ath11k_warn message. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211123090431.165103-1-colin.i.king@gmail.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -3511,7 +3511,7 @@ ath11k_wmi_obss_color_collision_event(st + case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE: + break; + default: +- ath11k_warn(ab, "received unknown obss color collision detetction event\n"); ++ ath11k_warn(ab, "received unknown obss color collision detection event\n"); + } + + exit: diff --git a/package/kernel/mac80211/patches/ath11k/0121-ath11k-add-support-for-WCN6855-hw2.1.patch b/package/kernel/mac80211/patches/ath11k/0121-ath11k-add-support-for-WCN6855-hw2.1.patch new file mode 100644 index 000000000..79d8b9140 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0121-ath11k-add-support-for-WCN6855-hw2.1.patch @@ -0,0 +1,152 @@ +From d1147a316b53df9cb0152e415ec41dcb6ea62c1c Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 29 Nov 2021 10:56:12 +0800 +Subject: [PATCH] ath11k: add support for WCN6855 hw2.1 + +Ath11k fails to probe WCN6855 hw2.1 chip: + +[ 6.983821] ath11k_pci 0000:06:00.0: enabling device (0000 -> 0002) +[ 6.983841] ath11k_pci 0000:06:00.0: Unsupported WCN6855 SOC hardware version: 18 17 + +This is caused by the wrong bit mask setting of hardware major version: +for QCA6390/QCN6855, it should be BIT8-11, not BIT8-16, so change the +definition to GENMASK(11, 8). + +Also, add a separate entry for WCN6855 hw2.1 in ath11k_hw_params. + +Please note that currently WCN6855 hw2.1 shares the same firmwares +as hw2.0, so users of this chip need to create a symlink as below: + + ln -s hw2.0 hw2.1 + +Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Fixes: 18ac1665e785 ("ath11k: pci: check TCSR_SOC_HW_VERSION") +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211129025613.21594-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 53 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mhi.c | 1 + + drivers/net/wireless/ath/ath11k/pci.c | 16 +++++++- + 4 files changed, 69 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -301,6 +301,59 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + }, ++ { ++ .name = "wcn6855 hw2.1", ++ .hw_rev = ATH11K_HW_WCN6855_HW21, ++ .fw = { ++ .dir = "WCN6855/hw2.1", ++ .board_size = 256 * 1024, ++ .cal_offset = 128 * 1024, ++ }, ++ .max_radios = 3, ++ .bdf_addr = 0x4B0C0000, ++ .hw_ops = &wcn6855_ops, ++ .ring_mask = &ath11k_hw_ring_mask_qca6390, ++ .internal_sleep_clock = true, ++ .regs = &wcn6855_regs, ++ .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390, ++ .host_ce_config = ath11k_host_ce_config_qca6390, ++ .ce_count = 9, ++ .target_ce_config = ath11k_target_ce_config_wlan_qca6390, ++ .target_ce_count = 9, ++ .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, ++ .svc_to_ce_map_len = 14, ++ .single_pdev_only = true, ++ .rxdma1_enable = false, ++ .num_rxmda_per_pdev = 2, ++ .rx_mac_buf_ring = true, ++ .vdev_start_delay = true, ++ .htt_peer_map_v2 = false, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 0, ++ .max_fft_bins = 0, ++ }, ++ ++ .interface_modes = BIT(NL80211_IFTYPE_STATION) | ++ BIT(NL80211_IFTYPE_AP), ++ .supports_monitor = false, ++ .supports_shadow_regs = true, ++ .idle_ps = true, ++ .supports_sta_ps = true, ++ .cold_boot_calib = false, ++ .supports_suspend = true, ++ .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), ++ .fix_l1ss = false, ++ .credit_flow = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, ++ .hal_params = &ath11k_hw_hal_params_qca6390, ++ .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = false, ++ .wakeup_mhi = true, ++ }, + }; + + int ath11k_core_suspend(struct ath11k_base *ab) +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -117,6 +117,7 @@ enum ath11k_hw_rev { + ATH11K_HW_IPQ6018_HW10, + ATH11K_HW_QCN9074_HW10, + ATH11K_HW_WCN6855_HW20, ++ ATH11K_HW_WCN6855_HW21, + }; + + enum ath11k_firmware_mode { +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -368,6 +368,7 @@ int ath11k_mhi_register(struct ath11k_pc + break; + case ATH11K_HW_QCA6390_HW20: + case ATH11K_HW_WCN6855_HW20: ++ case ATH11K_HW_WCN6855_HW21: + ath11k_mhi_config = &ath11k_mhi_config_qca6390; + break; + default: +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -26,7 +26,7 @@ + #define WINDOW_RANGE_MASK GENMASK(18, 0) + + #define TCSR_SOC_HW_VERSION 0x0224 +-#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) ++#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) + #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) + + /* BAR0 + 4k is always accessible, and no +@@ -1415,9 +1415,21 @@ static int ath11k_pci_probe(struct pci_d + &soc_hw_version_minor); + switch (soc_hw_version_major) { + case 2: +- ab->hw_rev = ATH11K_HW_WCN6855_HW20; ++ switch (soc_hw_version_minor) { ++ case 0x00: ++ case 0x01: ++ ab->hw_rev = ATH11K_HW_WCN6855_HW20; ++ break; ++ case 0x10: ++ case 0x11: ++ ab->hw_rev = ATH11K_HW_WCN6855_HW21; ++ break; ++ default: ++ goto unsupported_wcn6855_soc; ++ } + break; + default: ++unsupported_wcn6855_soc: + dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", + soc_hw_version_major, soc_hw_version_minor); + ret = -EOPNOTSUPP; diff --git a/package/kernel/mac80211/patches/ath11k/0122-ath11k-Fix-QMI-file-type-enum-value.patch b/package/kernel/mac80211/patches/ath11k/0122-ath11k-Fix-QMI-file-type-enum-value.patch new file mode 100644 index 000000000..3d1b5bfd0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0122-ath11k-Fix-QMI-file-type-enum-value.patch @@ -0,0 +1,32 @@ +From 18ae1ab04525507ae5528245a6df004cacd0d39a Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Mon, 29 Nov 2021 16:15:54 +0530 +Subject: [PATCH] ath11k: Fix QMI file type enum value + +bdf_type for caldata in QMI_WLANFW_BDF_DOWNLOAD_REQ_V01 is wrongly +sent as 1. But, expected bdf_type value for caldata and EEPROM is 2 and 3 +respectively. It leads to firmware crash. Fix ath11k_qmi_file_type enum +values. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Fixes: 336e7b53c82f ("ath11k: clean up BDF download functions") +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638182754-18408-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -41,7 +41,7 @@ struct ath11k_base; + + enum ath11k_qmi_file_type { + ATH11K_QMI_FILE_TYPE_BDF_GOLDEN, +- ATH11K_QMI_FILE_TYPE_CALDATA, ++ ATH11K_QMI_FILE_TYPE_CALDATA = 2, + ATH11K_QMI_FILE_TYPE_EEPROM, + ATH11K_QMI_MAX_FILE_TYPE, + }; diff --git a/package/kernel/mac80211/patches/ath11k/0123-ath11k-change-to-use-dynamic-memory-for-channel-list.patch b/package/kernel/mac80211/patches/ath11k/0123-ath11k-change-to-use-dynamic-memory-for-channel-list.patch new file mode 100644 index 000000000..fa508e8a7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0123-ath11k-change-to-use-dynamic-memory-for-channel-list.patch @@ -0,0 +1,66 @@ +From cea7f78d85f3f6ba05f43754600426b0e84abbbd Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 29 Nov 2021 06:09:39 -0500 +Subject: [PATCH] ath11k: change to use dynamic memory for channel list of scan + +Currently there are about 60 channels for 6 GHz, then the size of +chan_list in struct scan_req_params which is 40 is not enough to +fill all the channel list of 6 GHz. + +Use dynamic memory to save the channel list of scan. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211129110939.15711-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 10 ++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 3 +-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3504,6 +3504,14 @@ static int ath11k_mac_op_hw_scan(struct + + if (req->n_channels) { + arg.num_chan = req->n_channels; ++ arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), ++ GFP_KERNEL); ++ ++ if (!arg.chan_list) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ + for (i = 0; i < arg.num_chan; i++) + arg.chan_list[i] = req->channels[i]->center_freq; + } +@@ -3522,6 +3530,8 @@ static int ath11k_mac_op_hw_scan(struct + ATH11K_MAC_SCAN_TIMEOUT_MSECS)); + + exit: ++ kfree(arg.chan_list); ++ + if (req->ie_len) + kfree(arg.extraie.ptr); + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3082,7 +3082,6 @@ enum scan_dwelltime_adaptive_mode { + + #define WLAN_SCAN_MAX_NUM_SSID 10 + #define WLAN_SCAN_MAX_NUM_BSSID 10 +-#define WLAN_SCAN_MAX_NUM_CHANNELS 40 + + #define WLAN_SSID_MAX_LEN 32 + +@@ -3303,7 +3302,7 @@ struct scan_req_params { + u32 num_bssid; + u32 num_ssids; + u32 n_probes; +- u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS]; ++ u32 *chan_list; + u32 notify_scan_events; + struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID]; + struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID]; diff --git a/package/kernel/mac80211/patches/ath11k/0125-ath11k-add-configure-country-code-for-QCA6390-and-WC.patch b/package/kernel/mac80211/patches/ath11k/0125-ath11k-add-configure-country-code-for-QCA6390-and-WC.patch new file mode 100644 index 000000000..3d8a60ca5 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0125-ath11k-add-configure-country-code-for-QCA6390-and-WC.patch @@ -0,0 +1,92 @@ +From 0b05ddad8e4bd56bda42b9dc491c1b127720f063 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 7 Dec 2021 17:23:36 +0200 +Subject: [PATCH] ath11k: add configure country code for QCA6390 and WCN6855 + +Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which +is used for QCA6390 and WCN6855. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211201071745.17746-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 36 +++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 12 +++++++++ + 2 files changed, 48 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2798,6 +2798,42 @@ out: + return ret; + } + ++int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, ++ struct wmi_set_current_country_params *param) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_set_current_country_cmd *cmd; ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_set_current_country_cmd *)skb->data; ++ cmd->tlv_header = ++ FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->pdev_id = ar->pdev->pdev_id; ++ memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "set current country pdev id %d alpha2 %c%c\n", ++ ar->pdev->pdev_id, ++ param->alpha2[0], ++ param->alpha2[1]); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ + int + ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, + struct thermal_mitigation_params *param) +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3769,6 +3769,16 @@ struct stats_request_params { + u32 pdev_id; + }; + ++struct wmi_set_current_country_params { ++ u8 alpha2[3]; ++}; ++ ++struct wmi_set_current_country_cmd { ++ u32 tlv_header; ++ u32 pdev_id; ++ u32 new_alpha2; ++} __packed; ++ + enum set_init_cc_type { + WMI_COUNTRY_INFO_TYPE_ALPHA, + WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE, +@@ -5432,6 +5442,8 @@ int ath11k_wmi_delba_send(struct ath11k + u32 tid, u32 initiator, u32 reason); + int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, + u32 vdev_id, u32 bcn_ctrl_op); ++int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, ++ struct wmi_set_current_country_params *param); + int + ath11k_wmi_send_init_country_cmd(struct ath11k *ar, + struct wmi_init_country_params init_cc_param); diff --git a/package/kernel/mac80211/patches/ath11k/0126-ath11k-add-11d-scan-offload-support.patch b/package/kernel/mac80211/patches/ath11k/0126-ath11k-add-11d-scan-offload-support.patch new file mode 100644 index 000000000..72b82111d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0126-ath11k-add-11d-scan-offload-support.patch @@ -0,0 +1,600 @@ +From 9dcf6808b253a72b2c90eed179863bf5fab7d68c Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 7 Dec 2021 17:23:36 +0200 +Subject: [PATCH] ath11k: add 11d scan offload support + +Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID, +WMI_11D_SCAN_STOP_CMDID. + +After vdev create for STATION, send WMI_11D_SCAN_START_CMDID to firmware +and wait firmware complete it, the scan from mac80211 also need to wait +the 11d scan finished, and send WMI_11D_SCAN_STOP_CMDID to firmware +before vdev delete for STATION. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211201071745.17746-4-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 31 +++++ + drivers/net/wireless/ath/ath11k/core.h | 9 ++ + drivers/net/wireless/ath/ath11k/mac.c | 163 ++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/mac.h | 7 ++ + drivers/net/wireless/ath/ath11k/reg.c | 15 +++ + drivers/net/wireless/ath/ath11k/wmi.c | 109 +++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 27 ++++ + 7 files changed, 360 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1096,6 +1096,7 @@ void ath11k_core_halt(struct ath11k *ar) + ath11k_mac_peer_cleanup_all(ar); + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); ++ cancel_work_sync(&ab->update_11d_work); + + rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); + synchronize_rcu(); +@@ -1103,6 +1104,34 @@ void ath11k_core_halt(struct ath11k *ar) + idr_init(&ar->txmgmt_idr); + } + ++static void ath11k_update_11d(struct work_struct *work) ++{ ++ struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ struct wmi_set_current_country_params set_current_param = {}; ++ int ret, i; ++ ++ spin_lock_bh(&ab->base_lock); ++ memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); ++ spin_unlock_bh(&ab->base_lock); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", ++ set_current_param.alpha2[0], ++ set_current_param.alpha2[1]); ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ ++ ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "pdev id %d failed set current country code: %d\n", ++ i, ret); ++ } ++} ++ + static void ath11k_core_restart(struct work_struct *work) + { + struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); +@@ -1272,12 +1301,14 @@ struct ath11k_base *ath11k_core_alloc(st + + mutex_init(&ab->core_lock); + spin_lock_init(&ab->base_lock); ++ mutex_init(&ab->vdev_id_11d_lock); + + INIT_LIST_HEAD(&ab->peers); + init_waitqueue_head(&ab->peer_mapping_wq); + init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); + init_waitqueue_head(&ab->qmi.cold_boot_waitq); + INIT_WORK(&ab->restart_work, ath11k_core_restart); ++ INIT_WORK(&ab->update_11d_work, ath11k_update_11d); + timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); + init_completion(&ab->htc_suspend); + init_completion(&ab->wow.wakeup_completed); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -589,6 +589,11 @@ struct ath11k { + #endif + bool dfs_block_radar_events; + struct ath11k_thermal thermal; ++ u32 vdev_id_11d_scan; ++ struct completion finish_11d_scan; ++ struct completion finish_11d_ch_list; ++ bool pending_11d; ++ bool regdom_set_by_user; + }; + + struct ath11k_band_cap { +@@ -762,6 +767,8 @@ struct ath11k_base { + struct completion driver_recovery; + struct workqueue_struct *workqueue; + struct work_struct restart_work; ++ struct work_struct update_11d_work; ++ u8 new_alpha2[3]; + struct { + /* protected by data_lock */ + u32 fw_crash_counter; +@@ -771,6 +778,8 @@ struct ath11k_base { + struct ath11k_dbring_cap *db_caps; + u32 num_db_cap; + ++ /* To synchronize 11d scan vdev id */ ++ struct mutex vdev_id_11d_lock; + struct timer_list mon_reap_timer; + + struct completion htc_suspend; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2681,6 +2681,8 @@ static void ath11k_bss_assoc(struct ieee + if (ret) + ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", + arvif->vdev_id, ret); ++ ++ ath11k_mac_11d_scan_stop_all(ar->ab); + } + + static void ath11k_bss_disassoc(struct ieee80211_hw *hw, +@@ -3410,6 +3412,7 @@ static int ath11k_start_scan(struct ath1 + struct scan_req_params *arg) + { + int ret; ++ unsigned long timeout = 1 * HZ; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -3420,7 +3423,14 @@ static int ath11k_start_scan(struct ath1 + if (ret) + return ret; + +- ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); ++ if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) { ++ timeout = 5 * HZ; ++ ++ if (ar->supports_6ghz) ++ timeout += 5 * HZ; ++ } ++ ++ ret = wait_for_completion_timeout(&ar->scan.started, timeout); + if (ret == 0) { + ret = ath11k_scan_stop(ar); + if (ret) +@@ -3477,6 +3487,26 @@ static int ath11k_mac_op_hw_scan(struct + if (ret) + goto exit; + ++ /* Currently the pending_11d=true only happened 1 time while ++ * wlan interface up in ath11k_mac_11d_scan_start(), it is called by ++ * ath11k_mac_op_add_interface(), after wlan interface up, ++ * pending_11d=false always. ++ * If remove below wait, it always happened scan fail and lead connect ++ * fail while wlan interface up, because it has a 11d scan which is running ++ * in firmware, and lead this scan failed. ++ */ ++ if (ar->pending_11d) { ++ long time_left; ++ unsigned long timeout = 5 * HZ; ++ ++ if (ar->supports_6ghz) ++ timeout += 5 * HZ; ++ ++ time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout); ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac wait 11d channel list time left %ld\n", time_left); ++ } ++ + memset(&arg, 0, sizeof(arg)); + ath11k_wmi_start_scan_init(ar, &arg); + arg.vdev_id = arvif->vdev_id; +@@ -5638,6 +5668,7 @@ static void ath11k_mac_op_stop(struct ie + + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); ++ cancel_work_sync(&ar->ab->update_11d_work); + + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { +@@ -5791,6 +5822,122 @@ static void ath11k_mac_op_update_vif_off + } + } + ++static bool ath11k_mac_vif_ap_active_any(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ struct ath11k_vif *arvif; ++ int i; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP) ++ return true; ++ } ++ } ++ return false; ++} ++ ++void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait) ++{ ++ struct wmi_11d_scan_start_params param; ++ int ret; ++ ++ mutex_lock(&ar->ab->vdev_id_11d_lock); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n", ++ ar->vdev_id_11d_scan); ++ ++ if (ar->regdom_set_by_user) ++ goto fin; ++ ++ if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) ++ goto fin; ++ ++ if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) ++ goto fin; ++ ++ if (ath11k_mac_vif_ap_active_any(ar->ab)) ++ goto fin; ++ ++ param.vdev_id = vdev_id; ++ param.start_interval_msec = 0; ++ param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); ++ ++ if (wait) ++ reinit_completion(&ar->finish_11d_scan); ++ ++ ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n", ++ vdev_id, ret); ++ } else { ++ ar->vdev_id_11d_scan = vdev_id; ++ if (wait) { ++ ar->pending_11d = true; ++ ret = wait_for_completion_timeout(&ar->finish_11d_scan, ++ 5 * HZ); ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac 11d scan left time %d\n", ret); ++ ++ if (!ret) ++ ar->pending_11d = false; ++ } ++ } ++ ++fin: ++ mutex_unlock(&ar->ab->vdev_id_11d_lock); ++} ++ ++void ath11k_mac_11d_scan_stop(struct ath11k *ar) ++{ ++ int ret; ++ u32 vdev_id; ++ ++ if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) ++ return; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n"); ++ ++ mutex_lock(&ar->ab->vdev_id_11d_lock); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n", ++ ar->vdev_id_11d_scan); ++ ++ if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) { ++ vdev_id = ar->vdev_id_11d_scan; ++ ++ ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to stopt 11d scan vdev %d ret: %d\n", ++ vdev_id, ret); ++ else ++ ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; ++ } ++ mutex_unlock(&ar->ab->vdev_id_11d_lock); ++} ++ ++void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ int i; ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n"); ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ ++ ath11k_mac_11d_scan_stop(ar); ++ } ++} ++ + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) + { +@@ -5924,6 +6071,8 @@ static int ath11k_mac_op_add_interface(s + arvif->vdev_id, ret); + goto err_peer_del; + } ++ ++ ath11k_mac_11d_scan_stop_all(ar->ab); + break; + case WMI_VDEV_TYPE_STA: + param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; +@@ -5963,6 +6112,9 @@ static int ath11k_mac_op_add_interface(s + arvif->vdev_id, ret); + goto err_peer_del; + } ++ ++ ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true); ++ + break; + case WMI_VDEV_TYPE_MONITOR: + set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); +@@ -6064,6 +6216,9 @@ static void ath11k_mac_op_remove_interfa + ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", + arvif->vdev_id); + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_STA) ++ ath11k_mac_11d_scan_stop(ar); ++ + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); + if (ret) +@@ -6782,6 +6937,9 @@ ath11k_mac_op_unassign_vif_chanctx(struc + ret); + } + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_STA) ++ ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false); ++ + mutex_unlock(&ar->conf_mutex); + } + +@@ -8183,6 +8341,9 @@ int ath11k_mac_allocate(struct ath11k_ba + + ar->monitor_vdev_id = -1; + clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; ++ init_completion(&ar->finish_11d_scan); ++ init_completion(&ar->finish_11d_ch_list); + } + + return 0; +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -127,6 +127,13 @@ struct ath11k_generic_iter { + + extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default; + ++#define ATH11K_SCAN_11D_INTERVAL 600000 ++#define ATH11K_11D_INVALID_VDEV_ID 0xFFFF ++ ++void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait); ++void ath11k_mac_11d_scan_stop(struct ath11k *ar); ++void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab); ++ + void ath11k_mac_destroy(struct ath11k_base *ab); + void ath11k_mac_unregister(struct ath11k_base *ab); + int ath11k_mac_register(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -86,6 +86,9 @@ ath11k_reg_notifier(struct wiphy *wiphy, + if (ret) + ath11k_warn(ar->ab, + "INIT Country code set to fw failed : %d\n", ret); ++ ++ ath11k_mac_11d_scan_stop(ar); ++ ar->regdom_set_by_user = true; + } + + int ath11k_reg_update_chan_list(struct ath11k *ar) +@@ -179,6 +182,11 @@ int ath11k_reg_update_chan_list(struct a + ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); + kfree(params); + ++ if (ar->pending_11d) { ++ complete(&ar->finish_11d_ch_list); ++ ar->pending_11d = false; ++ } ++ + return ret; + } + +@@ -244,8 +252,15 @@ int ath11k_regd_update(struct ath11k *ar + goto err; + } + ++ if (ar->pending_11d) ++ complete(&ar->finish_11d_scan); ++ + rtnl_lock(); + wiphy_lock(ar->hw->wiphy); ++ ++ if (ar->pending_11d) ++ reinit_completion(&ar->finish_11d_ch_list); ++ + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); + wiphy_unlock(ar->hw->wiphy); + rtnl_unlock(); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -130,6 +130,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, + [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { + .min_len = sizeof(struct wmi_obss_color_collision_event) }, ++ [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { ++ .min_len = sizeof(struct wmi_11d_new_cc_ev) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -2898,6 +2900,75 @@ ath11k_wmi_send_thermal_mitigation_param + return ret; + } + ++int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, ++ struct wmi_11d_scan_start_params *param) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_11d_scan_start_cmd *cmd; ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_11d_scan_start_cmd *)skb->data; ++ cmd->tlv_header = ++ FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_START_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = param->vdev_id; ++ cmd->scan_period_msec = param->scan_period_msec; ++ cmd->start_interval_msec = param->start_interval_msec; ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "send 11d scan start vdev id %d period %d ms internal %d ms\n", ++ cmd->vdev_id, ++ cmd->scan_period_msec, ++ cmd->start_interval_msec); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ ++int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_11d_scan_stop_cmd *cmd; ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_11d_scan_stop_cmd *)skb->data; ++ cmd->tlv_header = ++ FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_STOP_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "send 11d scan stop vdev id %d\n", ++ cmd->vdev_id); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ + int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) + { + struct ath11k_pdev_wmi *wmi = ar->wmi; +@@ -5938,6 +6009,41 @@ static void ath11k_wmi_op_ep_tx_credits( + wake_up(&ab->wmi_ab.tx_credits_wq); + } + ++static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb) ++{ ++ const struct wmi_11d_new_cc_ev *ev; ++ const void **tb; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return ret; ++ } ++ ++ ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; ++ if (!ev) { ++ kfree(tb); ++ ath11k_warn(ab, "failed to fetch 11d new cc ev"); ++ return -EPROTO; ++ } ++ ++ spin_lock_bh(&ab->base_lock); ++ memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); ++ spin_unlock_bh(&ab->base_lock); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n", ++ ab->new_alpha2[0], ++ ab->new_alpha2[1]); ++ ++ kfree(tb); ++ ++ queue_work(ab->workqueue, &ab->update_11d_work); ++ ++ return 0; ++} ++ + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, + struct sk_buff *skb) + { +@@ -7333,6 +7439,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_WOW_WAKEUP_HOST_EVENTID: + ath11k_wmi_event_wow_wakeup_host(ab, skb); + break; ++ case WMI_11D_NEW_COUNTRY_EVENTID: ++ ath11k_reg_11d_new_cc_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3812,6 +3812,28 @@ struct wmi_init_country_cmd { + } cc_info; + } __packed; + ++struct wmi_11d_scan_start_params { ++ u32 vdev_id; ++ u32 scan_period_msec; ++ u32 start_interval_msec; ++}; ++ ++struct wmi_11d_scan_start_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 scan_period_msec; ++ u32 start_interval_msec; ++} __packed; ++ ++struct wmi_11d_scan_stop_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++} __packed; ++ ++struct wmi_11d_new_cc_ev { ++ u32 new_alpha2; ++} __packed; ++ + #define THERMAL_LEVELS 1 + struct tt_level_config { + u32 tmplwm; +@@ -5447,6 +5469,11 @@ int ath11k_wmi_send_set_current_country_ + int + ath11k_wmi_send_init_country_cmd(struct ath11k *ar, + struct wmi_init_country_params init_cc_param); ++ ++int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, ++ struct wmi_11d_scan_start_params *param); ++int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id); ++ + int + ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, + struct thermal_mitigation_params *param); diff --git a/package/kernel/mac80211/patches/ath11k/0127-ath11k-add-wait-operation-for-tx-management-packets-.patch b/package/kernel/mac80211/patches/ath11k/0127-ath11k-add-wait-operation-for-tx-management-packets-.patch new file mode 100644 index 000000000..dffa7acba --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0127-ath11k-add-wait-operation-for-tx-management-packets-.patch @@ -0,0 +1,230 @@ +From dddaa64d0af37275314a656bd8f8e941799e2d61 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Thu, 2 Dec 2021 01:37:05 -0500 +Subject: [PATCH] ath11k: add wait operation for tx management packets for + flush from mac80211 + +In ath11k, tx of management packet is doing in a work queue. Sometimes +the workqueue does not finish tx immediately, then it lead after the next +step of vdev delete finished, it start to send the management packet to +firmware and lead firmware crash. + +ieee80211_set_disassoc() have logic of ieee80211_flush_queues() after +it send_deauth_disassoc() to ath11k, its purpose is make sure the +deauth was actually sent, so it need to change ath11k to match the +purpose of mac80211. + +To address these issue wait for tx mgmt as well as tx data packets. + +dmesg log of connect/disconnect to AP: +[ 307.522226] wls1: authenticate with 62:66:e4:e9:6a:a9 +[ 307.586565] wls1: send auth to 62:66:e4:e9:6a:a9 (try 1/3) +[ 307.586581] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 +[ 307.586922] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 +[ 307.590179] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 +[ 307.590181] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 +[ 307.598699] wls1: authenticated +[ 307.599483] wls1: associate with 62:66:e4:e9:6a:a9 (try 1/3) +[ 307.599506] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 +[ 307.599519] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 +[ 307.603059] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 +[ 307.603063] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 +[ 307.637105] wls1: associated +[ 317.365239] wls1: deauthenticating from 62:66:e4:e9:6a:a9 by local choice (Reason: 3=DEAUTH_LEAVING) +[ 317.368104] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 +[ 317.372622] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 +[ 317.378320] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 +[ 317.378330] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 +[ 317.378359] ath11k_pci 0000:05:00.0: mac mgmt tx flush mgmt pending 0 +[ 317.421066] ath11k_pci 0000:05:00.0: mac mgmt tx flush mgmt pending 0 +[ 317.421427] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211202063705.14321-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 1 + + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 51 +++++++++++++++++++++----- + drivers/net/wireless/ath/ath11k/wmi.c | 12 +++++- + 4 files changed, 55 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1165,6 +1165,7 @@ static void ath11k_core_restart(struct w + idr_for_each(&ar->txmgmt_idr, + ath11k_mac_tx_mgmt_pending_free, ar); + idr_destroy(&ar->txmgmt_idr); ++ wake_up(&ar->txmgmt_empty_waitq); + } + + wake_up(&ab->wmi_ab.tx_credits_wq); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -551,6 +551,7 @@ struct ath11k { + /* protects txmgmt_idr data */ + spinlock_t txmgmt_idr_lock; + atomic_t num_pending_mgmt_tx; ++ wait_queue_head_t txmgmt_empty_waitq; + + /* cycle count is reported twice for each visited channel during scan. + * access protected by data_lock +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5268,6 +5268,21 @@ static int __ath11k_set_antenna(struct a + return 0; + } + ++static void ath11k_mgmt_over_wmi_tx_drop(struct ath11k *ar, struct sk_buff *skb) ++{ ++ int num_mgmt; ++ ++ ieee80211_free_txskb(ar->hw, skb); ++ ++ num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); ++ ++ if (num_mgmt < 0) ++ WARN_ON_ONCE(1); ++ ++ if (!num_mgmt) ++ wake_up(&ar->txmgmt_empty_waitq); ++} ++ + static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id) + { + struct sk_buff *msdu; +@@ -5286,7 +5301,7 @@ static void ath11k_mac_tx_mgmt_free(stru + info = IEEE80211_SKB_CB(msdu); + memset(&info->status, 0, sizeof(info->status)); + +- ieee80211_free_txskb(ar->hw, msdu); ++ ath11k_mgmt_over_wmi_tx_drop(ar, msdu); + } + + int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) +@@ -5326,6 +5341,10 @@ static int ath11k_mac_mgmt_tx_wmi(struct + buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, + ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); + spin_unlock_bh(&ar->txmgmt_idr_lock); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac tx mgmt frame, buf id %d\n", buf_id); ++ + if (buf_id < 0) + return -ENOSPC; + +@@ -5372,7 +5391,7 @@ static void ath11k_mgmt_over_wmi_tx_purg + struct sk_buff *skb; + + while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); + } + + static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) +@@ -5387,29 +5406,29 @@ static void ath11k_mgmt_over_wmi_tx_work + skb_cb = ATH11K_SKB_CB(skb); + if (!skb_cb->vif) { + ath11k_warn(ar->ab, "no vif found for mgmt frame\n"); +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); + continue; + } + + arvif = ath11k_vif_to_arvif(skb_cb->vif); + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && + arvif->is_started) { +- atomic_inc(&ar->num_pending_mgmt_tx); + ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); + if (ret) { +- if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) +- WARN_ON_ONCE(1); +- + ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", + arvif->vdev_id, ret); +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); ++ } else { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac tx mgmt frame, vdev_id %d\n", ++ arvif->vdev_id); + } + } else { + ath11k_warn(ar->ab, + "dropping mgmt frame for vdev %d, is_started %d\n", + arvif->vdev_id, + arvif->is_started); +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); + } + } + } +@@ -5440,6 +5459,7 @@ static int ath11k_mac_mgmt_tx(struct ath + } + + skb_queue_tail(q, skb); ++ atomic_inc(&ar->num_pending_mgmt_tx); + ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); + + return 0; +@@ -7026,6 +7046,17 @@ static void ath11k_mac_op_flush(struct i + ATH11K_FLUSH_TIMEOUT); + if (time_left == 0) + ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); ++ ++ time_left = wait_event_timeout(ar->txmgmt_empty_waitq, ++ (atomic_read(&ar->num_pending_mgmt_tx) == 0), ++ ATH11K_FLUSH_TIMEOUT); ++ if (time_left == 0) ++ ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", ++ time_left); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac mgmt tx flush mgmt pending %d\n", ++ atomic_read(&ar->num_pending_mgmt_tx)); + } + + static int +@@ -8264,6 +8295,8 @@ int ath11k_mac_register(struct ath11k_ba + ret = __ath11k_mac_register(ar); + if (ret) + goto err_cleanup; ++ ++ init_waitqueue_head(&ar->txmgmt_empty_waitq); + } + + return 0; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -4980,6 +4980,7 @@ static int wmi_process_mgmt_tx_comp(stru + struct sk_buff *msdu; + struct ieee80211_tx_info *info; + struct ath11k_skb_cb *skb_cb; ++ int num_mgmt; + + spin_lock_bh(&ar->txmgmt_idr_lock); + msdu = idr_find(&ar->txmgmt_idr, desc_id); +@@ -5003,10 +5004,19 @@ static int wmi_process_mgmt_tx_comp(stru + + ieee80211_tx_status_irqsafe(ar->hw, msdu); + ++ num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); ++ + /* WARN when we received this event without doing any mgmt tx */ +- if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) ++ if (num_mgmt < 0) + WARN_ON_ONCE(1); + ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi mgmt tx comp pending %d desc id %d\n", ++ num_mgmt, desc_id); ++ ++ if (!num_mgmt) ++ wake_up(&ar->txmgmt_empty_waitq); ++ + return 0; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0129-ath11k-enable-IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS-.patch b/package/kernel/mac80211/patches/ath11k/0129-ath11k-enable-IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS-.patch new file mode 100644 index 000000000..bb1336216 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0129-ath11k-enable-IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS-.patch @@ -0,0 +1,42 @@ +From 9f6da09a5f6ab94bca58395af56b883b3a79663a Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 8 Dec 2021 10:43:59 +0200 +Subject: [PATCH] ath11k: enable IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for + WCN6855 + +Currently mac80211 will send 3 scan request for each scan of WCN6855, +they are 2.4 GHz/5 GHz/6 GHz band scan. Firmware of WCN6855 will +cache the RNR IE(Reduced Neighbor Report element) which exist in the +beacon of 2.4 GHz/5 GHz of the AP which is co-located with 6 GHz, +and then use the cache to scan in 6 GHz band scan if the 6 GHz scan +is in the same scan with the 2.4 GHz/5 GHz band, this will helpful to +search more AP of 6 GHz. Also it will decrease the time cost of scan +because firmware will use dual-band scan for the 2.4 GHz/5 GHz, it +means the 2.4 GHz and 5 GHz scans are doing simultaneously. + +Set the flag IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN6855 since +it supports 2.4 GHz/5 GHz/6 GHz and it is single pdev which means +all the 2.4 GHz/5 GHz/6 GHz exist in the same wiphy/ieee80211_hw. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Tested-by: Sven Eckelmann +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211129101309.2931-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -8122,6 +8122,9 @@ static int __ath11k_mac_register(struct + + ar->hw->wiphy->interface_modes = ab->hw_params.interface_modes; + ++ if (ab->hw_params.single_pdev_only && ar->supports_6ghz) ++ ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS); ++ + ieee80211_hw_set(ar->hw, SIGNAL_DBM); + ieee80211_hw_set(ar->hw, SUPPORTS_PS); + ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); diff --git a/package/kernel/mac80211/patches/ath11k/0130-ath11k-Add-htt-cmd-to-enable-full-monitor-mode.patch b/package/kernel/mac80211/patches/ath11k/0130-ath11k-Add-htt-cmd-to-enable-full-monitor-mode.patch new file mode 100644 index 000000000..ccf8b9c1f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0130-ath11k-Add-htt-cmd-to-enable-full-monitor-mode.patch @@ -0,0 +1,189 @@ +From 5c1f74d24d92ce62264508df4c8acabb3127cd83 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: Add htt cmd to enable full monitor mode + +A new hw_param full_monitor_mode is added to enable full +monitor support for QCN9074. +HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE cmd is sent to FW +to enable the full monitor mode. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638881695-22155-2-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++ + drivers/net/wireless/ath/ath11k/dp.h | 28 +++++++++++++++ + drivers/net/wireless/ath/ath11k/dp_tx.c | 48 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/dp_tx.h | 2 ++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 5 files changed, 84 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -74,6 +74,7 @@ static const struct ath11k_hw_params ath + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), + .supports_monitor = true, ++ .full_monitor_mode = false, + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +@@ -128,6 +129,7 @@ static const struct ath11k_hw_params ath + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), + .supports_monitor = true, ++ .full_monitor_mode = false, + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +@@ -181,6 +183,7 @@ static const struct ath11k_hw_params ath + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, ++ .full_monitor_mode = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, +@@ -234,6 +237,7 @@ static const struct ath11k_hw_params ath + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), + .supports_monitor = true, ++ .full_monitor_mode = true, + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +@@ -287,6 +291,7 @@ static const struct ath11k_hw_params ath + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, ++ .full_monitor_mode = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -292,6 +292,7 @@ enum htt_h2t_msg_type { + HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc, + HTT_H2T_MSG_TYPE_EXT_STATS_CFG = 0x10, + HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11, ++ HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE = 0x17, + }; + + #define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0) +@@ -957,6 +958,33 @@ struct htt_rx_ring_tlv_filter { + u32 pkt_filter_flags3; /* DATA */ + }; + ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE GENMASK(7, 0) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID GENMASK(15, 8) ++ ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE BIT(0) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END BIT(1) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END BIT(2) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING GENMASK(10, 3) ++ ++/** ++ * Enumeration for full monitor mode destination ring select ++ * 0 - REO destination ring select ++ * 1 - FW destination ring select ++ * 2 - SW destination ring select ++ * 3 - Release destination ring select ++ */ ++enum htt_rx_full_mon_release_ring { ++ HTT_RX_MON_RING_REO, ++ HTT_RX_MON_RING_FW, ++ HTT_RX_MON_RING_SW, ++ HTT_RX_MON_RING_RELEASE, ++}; ++ ++struct htt_rx_full_monitor_mode_cfg_cmd { ++ u32 info0; ++ u32 cfg; ++} __packed; ++ + /* HTT message target->host */ + + enum htt_t2h_msg_type { +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -1033,6 +1033,15 @@ int ath11k_dp_tx_htt_monitor_mode_ring_c + struct htt_rx_ring_tlv_filter tlv_filter = {0}; + int ret = 0, ring_id = 0, i; + ++ if (ab->hw_params.full_monitor_mode) { ++ ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab, ++ dp->mac_id, !reset); ++ if (ret < 0) { ++ ath11k_err(ab, "failed to setup full monitor %d\n", ret); ++ return ret; ++ } ++ } ++ + ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; + + if (!reset) { +@@ -1098,3 +1107,42 @@ int ath11k_dp_tx_htt_monitor_mode_ring_c + + return ret; + } ++ ++int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, ++ bool config) ++{ ++ struct htt_rx_full_monitor_mode_cfg_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len = sizeof(*cmd); ++ ++ skb = ath11k_htc_alloc_skb(ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ skb_put(skb, len); ++ cmd = (struct htt_rx_full_monitor_mode_cfg_cmd *)skb->data; ++ memset(cmd, 0, sizeof(*cmd)); ++ cmd->info0 = FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE, ++ HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE); ++ ++ cmd->info0 |= FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID, mac_id); ++ ++ cmd->cfg = HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE | ++ FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING, ++ HTT_RX_MON_RING_SW); ++ if (config) { ++ cmd->cfg |= HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END | ++ HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END; ++ } ++ ++ ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb); ++ if (ret) ++ goto err_free; ++ ++ return 0; ++ ++err_free: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} +--- a/drivers/net/wireless/ath/ath11k/dp_tx.h ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.h +@@ -37,4 +37,6 @@ int ath11k_dp_tx_htt_rx_filter_setup(str + int rx_buf_size, + struct htt_rx_ring_tlv_filter *tlv_filter); + ++int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, ++ bool config); + #endif +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -168,6 +168,7 @@ struct ath11k_hw_params { + + u16 interface_modes; + bool supports_monitor; ++ bool full_monitor_mode; + bool supports_shadow_regs; + bool idle_ps; + bool supports_sta_ps; diff --git a/package/kernel/mac80211/patches/ath11k/0131-ath11k-add-software-monitor-ring-descriptor-for-full.patch b/package/kernel/mac80211/patches/ath11k/0131-ath11k-add-software-monitor-ring-descriptor-for-full.patch new file mode 100644 index 000000000..6db287bf2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0131-ath11k-add-software-monitor-ring-descriptor-for-full.patch @@ -0,0 +1,131 @@ +From 88ee00d130f744854cdd91ad76a888d9e66996d1 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: add software monitor ring descriptor for full monitor + +In full monitor mode, monitor destination ring is read in +software monitor ring descriptor format instead of +reo_entrance_ring format. Add new sw_mon_ring descriptor. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638881695-22155-3-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/hal_desc.h | 19 ++++++++++ + drivers/net/wireless/ath/ath11k/hal_rx.c | 44 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/hal_rx.h | 17 +++++++++ + 3 files changed, 80 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath11k/hal_desc.h +@@ -858,6 +858,25 @@ struct hal_reo_entrance_ring { + * this ring has looped around the ring. + */ + ++#define HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON GENMASK(1, 0) ++#define HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE GENMASK(6, 2) ++#define HAL_SW_MON_RING_INFO0_MPDU_FRAG_NUMBER GENMASK(10, 7) ++#define HAL_SW_MON_RING_INFO0_FRAMELESS_BAR BIT(11) ++#define HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT GENMASK(15, 12) ++#define HAL_SW_MON_RING_INFO0_END_OF_PPDU BIT(16) ++ ++#define HAL_SW_MON_RING_INFO1_PHY_PPDU_ID GENMASK(15, 0) ++#define HAL_SW_MON_RING_INFO1_RING_ID GENMASK(27, 20) ++#define HAL_SW_MON_RING_INFO1_LOOPING_COUNT GENMASK(31, 28) ++ ++struct hal_sw_monitor_ring { ++ struct ath11k_buffer_addr buf_addr_info; ++ struct rx_mpdu_desc rx_mpdu_info; ++ struct ath11k_buffer_addr status_buf_addr_info; ++ u32 info0; ++ u32 info1; ++} __packed; ++ + #define HAL_REO_CMD_HDR_INFO0_CMD_NUMBER GENMASK(15, 0) + #define HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED BIT(16) + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -1186,3 +1186,47 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get + + *pp_buf_addr = (void *)buf_addr_info; + } ++ ++void ++ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc, ++ struct hal_sw_mon_ring_entries *sw_mon_entries) ++{ ++ struct hal_sw_monitor_ring *sw_mon_ring = rx_desc; ++ struct ath11k_buffer_addr *buf_addr_info; ++ struct ath11k_buffer_addr *status_buf_addr_info; ++ struct rx_mpdu_desc *rx_mpdu_desc_info_details; ++ ++ rx_mpdu_desc_info_details = &sw_mon_ring->rx_mpdu_info; ++ ++ sw_mon_entries->msdu_cnt = FIELD_GET(RX_MPDU_DESC_INFO0_MSDU_COUNT, ++ rx_mpdu_desc_info_details->info0); ++ ++ buf_addr_info = &sw_mon_ring->buf_addr_info; ++ status_buf_addr_info = &sw_mon_ring->status_buf_addr_info; ++ ++ sw_mon_entries->mon_dst_paddr = (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, ++ buf_addr_info->info1)) << 32) | ++ FIELD_GET(BUFFER_ADDR_INFO0_ADDR, ++ buf_addr_info->info0); ++ ++ sw_mon_entries->mon_status_paddr = ++ (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, ++ status_buf_addr_info->info1)) << 32) | ++ FIELD_GET(BUFFER_ADDR_INFO0_ADDR, ++ status_buf_addr_info->info0); ++ ++ sw_mon_entries->mon_dst_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, ++ buf_addr_info->info1); ++ ++ sw_mon_entries->mon_status_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, ++ status_buf_addr_info->info1); ++ ++ sw_mon_entries->status_buf_count = FIELD_GET(HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT, ++ sw_mon_ring->info0); ++ ++ sw_mon_entries->dst_buf_addr_info = buf_addr_info; ++ sw_mon_entries->status_buf_addr_info = status_buf_addr_info; ++ ++ sw_mon_entries->ppdu_id = ++ FIELD_GET(HAL_SW_MON_RING_INFO1_PHY_PPDU_ID, sw_mon_ring->info1); ++} +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -77,6 +77,20 @@ enum hal_rx_mon_status { + HAL_RX_MON_STATUS_BUF_DONE, + }; + ++struct hal_sw_mon_ring_entries { ++ dma_addr_t mon_dst_paddr; ++ dma_addr_t mon_status_paddr; ++ u32 mon_dst_sw_cookie; ++ u32 mon_status_sw_cookie; ++ void *dst_buf_addr_info; ++ void *status_buf_addr_info; ++ u16 ppdu_id; ++ u8 status_buf_count; ++ u8 msdu_cnt; ++ bool end_of_ppdu; ++ bool drop_ppdu; ++}; ++ + struct hal_rx_mon_ppdu_info { + u32 ppdu_id; + u32 ppdu_ts; +@@ -331,6 +345,9 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get + dma_addr_t *paddr, u32 *sw_cookie, + void **pp_buf_addr_info, u8 *rbm, + u32 *msdu_cnt); ++void ++ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc, ++ struct hal_sw_mon_ring_entries *sw_mon_ent); + enum hal_rx_mon_status + ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab, + struct hal_rx_mon_ppdu_info *ppdu_info, diff --git a/package/kernel/mac80211/patches/ath11k/0132-ath11k-Process-full-monitor-mode-rx-support.patch b/package/kernel/mac80211/patches/ath11k/0132-ath11k-Process-full-monitor-mode-rx-support.patch new file mode 100644 index 000000000..884a79564 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0132-ath11k-Process-full-monitor-mode-rx-support.patch @@ -0,0 +1,568 @@ +From 7e2ea2e947046834a450295dfd328adb70a9f864 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: Process full monitor mode rx support + +In full monitor mode, monitor destination ring is read before monitor +status ring. mon_dst_ring has ppdu id, reap till the end of PPDU. Add +all the MPDUs to list. Start processing the status ring, if PPDU id in +status ring is lagging behind, reap the status ring, once the PPDU ID +matches, deliver the MSDU to upper layer. If status PPDU id leading, +reap the mon_dst_ring. + +The advantage with full monitor mode is hardware has status buffers +available for all the MPDUs in mon_dst_ring, which makes it possible +to deliver more frames to be seen on sniffer. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638881695-22155-4-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.c | 1 + + drivers/net/wireless/ath/ath11k/dp.h | 26 +- + drivers/net/wireless/ath/ath11k/dp_rx.c | 409 +++++++++++++++++++++++- + 3 files changed, 433 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -1051,6 +1051,7 @@ int ath11k_dp_alloc(struct ath11k_base * + + INIT_LIST_HEAD(&dp->reo_cmd_list); + INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list); ++ INIT_LIST_HEAD(&dp->dp_full_mon_mpdu_list); + spin_lock_init(&dp->reo_cmd_lock); + + dp->reo_cmd_cache_flush_count = 0; +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -89,6 +89,19 @@ struct dp_tx_ring { + int tx_status_tail; + }; + ++enum dp_mon_status_buf_state { ++ /* PPDU id matches in dst ring and status ring */ ++ DP_MON_STATUS_MATCH, ++ /* status ring dma is not done */ ++ DP_MON_STATUS_NO_DMA, ++ /* status ring is lagging, reap status ring */ ++ DP_MON_STATUS_LAG, ++ /* status ring is leading, reap dst ring and drop */ ++ DP_MON_STATUS_LEAD, ++ /* replinish monitor status ring */ ++ DP_MON_STATUS_REPLINISH, ++}; ++ + struct ath11k_pdev_mon_stats { + u32 status_ppdu_state; + u32 status_ppdu_start; +@@ -104,6 +117,12 @@ struct ath11k_pdev_mon_stats { + u32 dup_mon_buf_cnt; + }; + ++struct dp_full_mon_mpdu { ++ struct list_head list; ++ struct sk_buff *head; ++ struct sk_buff *tail; ++}; ++ + struct dp_link_desc_bank { + void *vaddr_unaligned; + void *vaddr; +@@ -135,7 +154,11 @@ struct ath11k_mon_data { + u32 mon_last_buf_cookie; + u64 mon_last_linkdesc_paddr; + u16 chan_noise_floor; +- ++ bool hold_mon_dst_ring; ++ enum dp_mon_status_buf_state buf_state; ++ dma_addr_t mon_status_paddr; ++ struct dp_full_mon_mpdu *mon_mpdu; ++ struct hal_sw_mon_ring_entries sw_mon_entries; + struct ath11k_pdev_mon_stats rx_mon_stats; + /* lock for monitor data */ + spinlock_t mon_lock; +@@ -245,6 +268,7 @@ struct ath11k_dp { + struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX]; + struct list_head reo_cmd_list; + struct list_head reo_cmd_cache_flush_list; ++ struct list_head dp_full_mon_mpdu_list; + u32 reo_cmd_cache_flush_count; + /** + * protects access to below fields, +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2942,6 +2942,43 @@ fail_desc_get: + return req_entries - num_remain; + } + ++#define ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP 32535 ++ ++static void ++ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon, ++ struct hal_tlv_hdr *tlv) ++{ ++ struct hal_rx_ppdu_start *ppdu_start; ++ u16 ppdu_id_diff, ppdu_id, tlv_len; ++ u8 *ptr; ++ ++ /* PPDU id is part of second tlv, move ptr to second tlv */ ++ tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl); ++ ptr = (u8 *)tlv; ++ ptr += sizeof(*tlv) + tlv_len; ++ tlv = (struct hal_tlv_hdr *)ptr; ++ ++ if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_PPDU_START) ++ return; ++ ++ ptr += sizeof(*tlv); ++ ppdu_start = (struct hal_rx_ppdu_start *)ptr; ++ ppdu_id = FIELD_GET(HAL_RX_PPDU_START_INFO0_PPDU_ID, ++ __le32_to_cpu(ppdu_start->info0)); ++ ++ if (pmon->sw_mon_entries.ppdu_id < ppdu_id) { ++ pmon->buf_state = DP_MON_STATUS_LEAD; ++ ppdu_id_diff = ppdu_id - pmon->sw_mon_entries.ppdu_id; ++ if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) ++ pmon->buf_state = DP_MON_STATUS_LAG; ++ } else if (pmon->sw_mon_entries.ppdu_id > ppdu_id) { ++ pmon->buf_state = DP_MON_STATUS_LAG; ++ ppdu_id_diff = pmon->sw_mon_entries.ppdu_id - ppdu_id; ++ if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) ++ pmon->buf_state = DP_MON_STATUS_LEAD; ++ } ++} ++ + static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, + int *budget, struct sk_buff_head *skb_list) + { +@@ -2949,6 +2986,7 @@ static int ath11k_dp_rx_reap_mon_status_ + const struct ath11k_hw_hal_params *hal_params; + struct ath11k_pdev_dp *dp; + struct dp_rxdma_ring *rx_ring; ++ struct ath11k_mon_data *pmon; + struct hal_srng *srng; + void *rx_mon_status_desc; + struct sk_buff *skb; +@@ -2962,6 +3000,7 @@ static int ath11k_dp_rx_reap_mon_status_ + + ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; + dp = &ar->dp; ++ pmon = &dp->mon_data; + srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); + rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; + +@@ -2974,8 +3013,10 @@ static int ath11k_dp_rx_reap_mon_status_ + *budget -= 1; + rx_mon_status_desc = + ath11k_hal_srng_src_peek(ab, srng); +- if (!rx_mon_status_desc) ++ if (!rx_mon_status_desc) { ++ pmon->buf_state = DP_MON_STATUS_REPLINISH; + break; ++ } + + ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr, + &cookie, &rbm); +@@ -2988,6 +3029,7 @@ static int ath11k_dp_rx_reap_mon_status_ + ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n", + buf_id); + spin_unlock_bh(&rx_ring->idr_lock); ++ pmon->buf_state = DP_MON_STATUS_REPLINISH; + goto move_next; + } + +@@ -3007,10 +3049,18 @@ static int ath11k_dp_rx_reap_mon_status_ + FIELD_GET(HAL_TLV_HDR_TAG, + tlv->tl)); + dev_kfree_skb_any(skb); ++ pmon->buf_state = DP_MON_STATUS_NO_DMA; + goto move_next; + } + ++ if (ab->hw_params.full_monitor_mode) { ++ ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv); ++ if (paddr == pmon->mon_status_paddr) ++ pmon->buf_state = DP_MON_STATUS_MATCH; ++ } + __skb_queue_tail(skb_list, skb); ++ } else { ++ pmon->buf_state = DP_MON_STATUS_REPLINISH; + } + move_next: + skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, +@@ -5098,6 +5148,357 @@ static void ath11k_dp_rx_mon_status_proc + } + } + ++static u32 ++ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, ++ void *ring_entry, struct sk_buff **head_msdu, ++ struct sk_buff **tail_msdu, ++ struct hal_sw_mon_ring_entries *sw_mon_entries) ++{ ++ struct ath11k_pdev_dp *dp = &ar->dp; ++ struct ath11k_mon_data *pmon = &dp->mon_data; ++ struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring; ++ struct sk_buff *msdu = NULL, *last = NULL; ++ struct hal_sw_monitor_ring *sw_desc = ring_entry; ++ struct hal_rx_msdu_list msdu_list; ++ struct hal_rx_desc *rx_desc; ++ struct ath11k_skb_rxcb *rxcb; ++ void *rx_msdu_link_desc; ++ void *p_buf_addr_info, *p_last_buf_addr_info; ++ int buf_id, i = 0; ++ u32 rx_buf_size, rx_pkt_offset, l2_hdr_offset; ++ u32 rx_bufs_used = 0, msdu_cnt = 0; ++ u32 total_len = 0, frag_len = 0, sw_cookie; ++ u16 num_msdus = 0; ++ u8 rxdma_err, rbm; ++ bool is_frag, is_first_msdu; ++ bool drop_mpdu = false; ++ ++ ath11k_hal_rx_sw_mon_ring_buf_paddr_get(ring_entry, sw_mon_entries); ++ ++ sw_cookie = sw_mon_entries->mon_dst_sw_cookie; ++ sw_mon_entries->end_of_ppdu = false; ++ sw_mon_entries->drop_ppdu = false; ++ p_last_buf_addr_info = sw_mon_entries->dst_buf_addr_info; ++ msdu_cnt = sw_mon_entries->msdu_cnt; ++ ++ sw_mon_entries->end_of_ppdu = ++ FIELD_GET(HAL_SW_MON_RING_INFO0_END_OF_PPDU, sw_desc->info0); ++ if (sw_mon_entries->end_of_ppdu) ++ return rx_bufs_used; ++ ++ if (FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON, ++ sw_desc->info0) == ++ HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { ++ rxdma_err = ++ FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE, ++ sw_desc->info0); ++ if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR || ++ rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR || ++ rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) { ++ pmon->rx_mon_stats.dest_mpdu_drop++; ++ drop_mpdu = true; ++ } ++ } ++ ++ is_frag = false; ++ is_first_msdu = true; ++ ++ do { ++ rx_msdu_link_desc = ++ (u8 *)pmon->link_desc_banks[sw_cookie].vaddr + ++ (sw_mon_entries->mon_dst_paddr - ++ pmon->link_desc_banks[sw_cookie].paddr); ++ ++ ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list, ++ &num_msdus); ++ ++ for (i = 0; i < num_msdus; i++) { ++ buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, ++ msdu_list.sw_cookie[i]); ++ ++ spin_lock_bh(&rx_ring->idr_lock); ++ msdu = idr_find(&rx_ring->bufs_idr, buf_id); ++ if (!msdu) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "full mon msdu_pop: invalid buf_id %d\n", ++ buf_id); ++ spin_unlock_bh(&rx_ring->idr_lock); ++ break; ++ } ++ idr_remove(&rx_ring->bufs_idr, buf_id); ++ spin_unlock_bh(&rx_ring->idr_lock); ++ ++ rxcb = ATH11K_SKB_RXCB(msdu); ++ if (!rxcb->unmapped) { ++ dma_unmap_single(ar->ab->dev, rxcb->paddr, ++ msdu->len + ++ skb_tailroom(msdu), ++ DMA_FROM_DEVICE); ++ rxcb->unmapped = 1; ++ } ++ if (drop_mpdu) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "full mon: i %d drop msdu %p *ppdu_id %x\n", ++ i, msdu, sw_mon_entries->ppdu_id); ++ dev_kfree_skb_any(msdu); ++ msdu_cnt--; ++ goto next_msdu; ++ } ++ ++ rx_desc = (struct hal_rx_desc *)msdu->data; ++ ++ rx_pkt_offset = sizeof(struct hal_rx_desc); ++ l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc); ++ ++ if (is_first_msdu) { ++ if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) { ++ drop_mpdu = true; ++ dev_kfree_skb_any(msdu); ++ msdu = NULL; ++ goto next_msdu; ++ } ++ is_first_msdu = false; ++ } ++ ++ ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i], ++ &is_frag, &total_len, ++ &frag_len, &msdu_cnt); ++ ++ rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len; ++ ++ ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size); ++ ++ if (!(*head_msdu)) ++ *head_msdu = msdu; ++ else if (last) ++ last->next = msdu; ++ ++ last = msdu; ++next_msdu: ++ rx_bufs_used++; ++ } ++ ++ ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, ++ &sw_mon_entries->mon_dst_paddr, ++ &sw_mon_entries->mon_dst_sw_cookie, ++ &rbm, ++ &p_buf_addr_info); ++ ++ if (ath11k_dp_rx_monitor_link_desc_return(ar, ++ p_last_buf_addr_info, ++ dp->mac_id)) ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "full mon: dp_rx_monitor_link_desc_return failed\n"); ++ ++ p_last_buf_addr_info = p_buf_addr_info; ++ ++ } while (sw_mon_entries->mon_dst_paddr && msdu_cnt); ++ ++ if (last) ++ last->next = NULL; ++ ++ *tail_msdu = msdu; ++ ++ return rx_bufs_used; ++} ++ ++static int ath11k_dp_rx_full_mon_prepare_mpdu(struct ath11k_dp *dp, ++ struct dp_full_mon_mpdu *mon_mpdu, ++ struct sk_buff *head, ++ struct sk_buff *tail) ++{ ++ mon_mpdu = kzalloc(sizeof(*mon_mpdu), GFP_ATOMIC); ++ if (!mon_mpdu) ++ return -ENOMEM; ++ ++ list_add_tail(&mon_mpdu->list, &dp->dp_full_mon_mpdu_list); ++ mon_mpdu->head = head; ++ mon_mpdu->tail = tail; ++ ++ return 0; ++} ++ ++static void ath11k_dp_rx_full_mon_drop_ppdu(struct ath11k_dp *dp, ++ struct dp_full_mon_mpdu *mon_mpdu) ++{ ++ struct dp_full_mon_mpdu *tmp; ++ struct sk_buff *tmp_msdu, *skb_next; ++ ++ if (list_empty(&dp->dp_full_mon_mpdu_list)) ++ return; ++ ++ list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { ++ list_del(&mon_mpdu->list); ++ ++ tmp_msdu = mon_mpdu->head; ++ while (tmp_msdu) { ++ skb_next = tmp_msdu->next; ++ dev_kfree_skb_any(tmp_msdu); ++ tmp_msdu = skb_next; ++ } ++ ++ kfree(mon_mpdu); ++ } ++} ++ ++static int ath11k_dp_rx_full_mon_deliver_ppdu(struct ath11k *ar, ++ int mac_id, ++ struct ath11k_mon_data *pmon, ++ struct napi_struct *napi) ++{ ++ struct ath11k_pdev_mon_stats *rx_mon_stats; ++ struct dp_full_mon_mpdu *tmp; ++ struct dp_full_mon_mpdu *mon_mpdu = pmon->mon_mpdu; ++ struct sk_buff *head_msdu, *tail_msdu; ++ struct ath11k_base *ab = ar->ab; ++ struct ath11k_dp *dp = &ab->dp; ++ int ret; ++ ++ rx_mon_stats = &pmon->rx_mon_stats; ++ ++ list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { ++ list_del(&mon_mpdu->list); ++ head_msdu = mon_mpdu->head; ++ tail_msdu = mon_mpdu->tail; ++ if (head_msdu && tail_msdu) { ++ ret = ath11k_dp_rx_mon_deliver(ar, mac_id, head_msdu, ++ tail_msdu, napi); ++ rx_mon_stats->dest_mpdu_done++; ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, "full mon: deliver ppdu\n"); ++ } ++ kfree(mon_mpdu); ++ } ++ ++ return ret; ++} ++ ++static int ++ath11k_dp_rx_process_full_mon_status_ring(struct ath11k_base *ab, int mac_id, ++ struct napi_struct *napi, int budget) ++{ ++ struct ath11k *ar = ab->pdevs[mac_id].ar; ++ struct ath11k_pdev_dp *dp = &ar->dp; ++ struct ath11k_mon_data *pmon = &dp->mon_data; ++ struct hal_sw_mon_ring_entries *sw_mon_entries; ++ int quota = 0, work = 0, count; ++ ++ sw_mon_entries = &pmon->sw_mon_entries; ++ ++ while (pmon->hold_mon_dst_ring) { ++ quota = ath11k_dp_rx_process_mon_status(ab, mac_id, ++ napi, 1); ++ if (pmon->buf_state == DP_MON_STATUS_MATCH) { ++ count = sw_mon_entries->status_buf_count; ++ if (count > 1) { ++ quota += ath11k_dp_rx_process_mon_status(ab, mac_id, ++ napi, count); ++ } ++ ++ ath11k_dp_rx_full_mon_deliver_ppdu(ar, dp->mac_id, ++ pmon, napi); ++ pmon->hold_mon_dst_ring = false; ++ } else if (!pmon->mon_status_paddr || ++ pmon->buf_state == DP_MON_STATUS_LEAD) { ++ sw_mon_entries->drop_ppdu = true; ++ pmon->hold_mon_dst_ring = false; ++ } ++ ++ if (!quota) ++ break; ++ ++ work += quota; ++ } ++ ++ if (sw_mon_entries->drop_ppdu) ++ ath11k_dp_rx_full_mon_drop_ppdu(&ab->dp, pmon->mon_mpdu); ++ ++ return work; ++} ++ ++static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id, ++ struct napi_struct *napi, int budget) ++{ ++ struct ath11k *ar = ab->pdevs[mac_id].ar; ++ struct ath11k_pdev_dp *dp = &ar->dp; ++ struct ath11k_mon_data *pmon = &dp->mon_data; ++ struct hal_sw_mon_ring_entries *sw_mon_entries; ++ struct ath11k_pdev_mon_stats *rx_mon_stats; ++ struct sk_buff *head_msdu, *tail_msdu; ++ void *mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id]; ++ void *ring_entry; ++ u32 rx_bufs_used = 0, mpdu_rx_bufs_used; ++ int quota = 0, ret; ++ bool break_dst_ring = false; ++ ++ spin_lock_bh(&pmon->mon_lock); ++ ++ sw_mon_entries = &pmon->sw_mon_entries; ++ rx_mon_stats = &pmon->rx_mon_stats; ++ ++ if (pmon->hold_mon_dst_ring) { ++ spin_unlock_bh(&pmon->mon_lock); ++ goto reap_status_ring; ++ } ++ ++ ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng); ++ while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) { ++ head_msdu = NULL; ++ tail_msdu = NULL; ++ ++ mpdu_rx_bufs_used = ath11k_dp_rx_full_mon_mpdu_pop(ar, ring_entry, ++ &head_msdu, ++ &tail_msdu, ++ sw_mon_entries); ++ rx_bufs_used += mpdu_rx_bufs_used; ++ ++ if (!sw_mon_entries->end_of_ppdu) { ++ if (head_msdu) { ++ ret = ath11k_dp_rx_full_mon_prepare_mpdu(&ab->dp, ++ pmon->mon_mpdu, ++ head_msdu, ++ tail_msdu); ++ if (ret) ++ break_dst_ring = true; ++ } ++ ++ goto next_entry; ++ } else { ++ if (!sw_mon_entries->ppdu_id && ++ !sw_mon_entries->mon_status_paddr) { ++ break_dst_ring = true; ++ goto next_entry; ++ } ++ } ++ ++ rx_mon_stats->dest_ppdu_done++; ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_START; ++ pmon->buf_state = DP_MON_STATUS_LAG; ++ pmon->mon_status_paddr = sw_mon_entries->mon_status_paddr; ++ pmon->hold_mon_dst_ring = true; ++next_entry: ++ ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab, ++ mon_dst_srng); ++ if (break_dst_ring) ++ break; ++ } ++ ++ ath11k_hal_srng_access_end(ar->ab, mon_dst_srng); ++ spin_unlock_bh(&pmon->mon_lock); ++ ++ if (rx_bufs_used) { ++ ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, ++ &dp->rxdma_mon_buf_ring, ++ rx_bufs_used, ++ HAL_RX_BUF_RBM_SW3_BM); ++ } ++ ++reap_status_ring: ++ quota = ath11k_dp_rx_process_full_mon_status_ring(ab, mac_id, ++ napi, budget); ++ ++ return quota; ++} ++ + static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, + struct napi_struct *napi, int budget) + { +@@ -5120,10 +5521,14 @@ int ath11k_dp_rx_process_mon_rings(struc + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); + int ret = 0; + +- if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && ++ ab->hw_params.full_monitor_mode) ++ ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget); ++ else if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) + ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); + else + ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); ++ + return ret; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0133-ath11k-add-spectral-CFR-buffer-validation-support.patch b/package/kernel/mac80211/patches/ath11k/0133-ath11k-add-spectral-CFR-buffer-validation-support.patch new file mode 100644 index 000000000..ac37a3a0b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0133-ath11k-add-spectral-CFR-buffer-validation-support.patch @@ -0,0 +1,118 @@ +From d3d358efc553de4f9d803c889a2e91523ea90f19 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: add spectral/CFR buffer validation support + +Currently there is no validation on the spectral/CFR report +over the db ring buffers from the hardware. Improper/incomplete +DMA by the target can result in invalid data received by host. +Due to this we may populate incorrect data to user space. + +This buffer validation support fix this issues by filling some +magic value in the buffer during buffer replenish and check for +the magic value in the buffer received by the target. If host +detect magic value in the received buffer it will drop the buffer. + +Tested-on: IPQ8074 WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1637312901-10279-2-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dbring.c | 30 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/dbring.h | 2 ++ + drivers/net/wireless/ath/ath11k/spectral.c | 14 ++++++++++ + 3 files changed, 46 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/dbring.c ++++ b/drivers/net/wireless/ath/ath11k/dbring.c +@@ -6,6 +6,35 @@ + #include "core.h" + #include "debug.h" + ++#define ATH11K_DB_MAGIC_VALUE 0xdeadbeaf ++ ++int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size) ++{ ++ u32 *temp; ++ int idx; ++ ++ size = size >> 2; ++ ++ for (idx = 0, temp = buffer; idx < size; idx++, temp++) { ++ if (*temp == ATH11K_DB_MAGIC_VALUE) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void ath11k_dbring_fill_magic_value(struct ath11k *ar, ++ void *buffer, u32 size) ++{ ++ u32 *temp; ++ int idx; ++ ++ size = size >> 2; ++ ++ for (idx = 0, temp = buffer; idx < size; idx++, temp++) ++ *temp++ = ATH11K_DB_MAGIC_VALUE; ++} ++ + static int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff) +@@ -26,6 +55,7 @@ static int ath11k_dbring_bufs_replenish( + + ptr_unaligned = buff->payload; + ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align); ++ ath11k_dbring_fill_magic_value(ar, ptr_aligned, ring->buf_sz); + paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz, + DMA_FROM_DEVICE); + +--- a/drivers/net/wireless/ath/ath11k/dbring.h ++++ b/drivers/net/wireless/ath/ath11k/dbring.h +@@ -76,4 +76,6 @@ int ath11k_dbring_get_cap(struct ath11k_ + struct ath11k_dbring_cap *db_cap); + void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); + void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); ++int ath11k_dbring_validate_buffer(struct ath11k *ar, void *data, u32 size); ++ + #endif /* ATH11K_DBRING_H */ +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -585,6 +585,7 @@ int ath11k_spectral_process_fft(struct a + u16 length, freq; + u8 chan_width_mhz, bin_sz; + int ret; ++ u32 check_length; + + lockdep_assert_held(&ar->spectral.lock); + +@@ -618,6 +619,13 @@ int ath11k_spectral_process_fft(struct a + return -EINVAL; + } + ++ check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz); ++ ret = ath11k_dbring_validate_buffer(ar, data, check_length); ++ if (ret) { ++ ath11k_warn(ar->ab, "found magic value in fft data, dropping\n"); ++ return ret; ++ } ++ + ret = ath11k_spectral_pull_search(ar, data, &search); + if (ret) { + ath11k_warn(ab, "failed to pull search report %d\n", ret); +@@ -751,6 +759,12 @@ static int ath11k_spectral_process_data( + goto err; + } + ++ ret = ath11k_dbring_validate_buffer(ar, data, tlv_len); ++ if (ret) { ++ ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n"); ++ goto err; ++ } ++ + summary = (struct spectral_summary_fft_report *)tlv; + ath11k_spectral_pull_summary(ar, ¶m->meta, + summary, &summ_rpt); diff --git a/package/kernel/mac80211/patches/ath11k/0136-ath11k-support-MAC-address-randomization-in-scan.patch b/package/kernel/mac80211/patches/ath11k/0136-ath11k-support-MAC-address-randomization-in-scan.patch new file mode 100644 index 000000000..90b984b0f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0136-ath11k-support-MAC-address-randomization-in-scan.patch @@ -0,0 +1,137 @@ +From 9cbd7fc9be82a99af690adcebd6f2cdae4c7c193 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Thu, 9 Dec 2021 10:17:49 +0200 +Subject: [PATCH] ath11k: support MAC address randomization in scan + +The driver reports NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR capability +to upper layer based on the service bit firmware reported. Driver +sets the spoofed flag in scan_ctrl_flag to firmware if upper layer +has enabled this feature in scan request. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638948007-9609-1-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 19 +++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 30 +++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 10 ++++++++- + 3 files changed, 58 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3546,6 +3546,12 @@ static int ath11k_mac_op_hw_scan(struct + arg.chan_list[i] = req->channels[i]->center_freq; + } + ++ if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { ++ arg.scan_f_add_spoofed_mac_in_probe = 1; ++ ether_addr_copy(arg.mac_addr.addr, req->mac_addr); ++ ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); ++ } ++ + ret = ath11k_start_scan(ar, &arg); + if (ret) { + ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret); +@@ -5590,6 +5596,14 @@ static int ath11k_mac_op_start(struct ie + goto err; + } + ++ if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) { ++ ret = ath11k_wmi_scan_prob_req_oui(ar, ar->mac_addr); ++ if (ret) { ++ ath11k_err(ab, "failed to set prob req oui: %i\n", ret); ++ goto err; ++ } ++ } ++ + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE, + 0, pdev->pdev_id); + if (ret) { +@@ -8186,6 +8200,11 @@ static int __ath11k_mac_register(struct + + ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + ++ if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) { ++ ar->hw->wiphy->features |= ++ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; ++ } ++ + ar->hw->queues = ATH11K_HW_MAX_QUEUES; + ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; + ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2181,6 +2181,8 @@ int ath11k_wmi_send_scan_start_cmd(struc + cmd->num_ssids = params->num_ssids; + cmd->ie_len = params->extraie.len; + cmd->n_probes = params->n_probes; ++ ether_addr_copy(cmd->mac_addr.addr, params->mac_addr.addr); ++ ether_addr_copy(cmd->mac_mask.addr, params->mac_mask.addr); + + ptr += sizeof(*cmd); + +@@ -7710,3 +7712,31 @@ int ath11k_wmi_wow_enable(struct ath11k + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); + } ++ ++int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, ++ const u8 mac_addr[ETH_ALEN]) ++{ ++ struct sk_buff *skb; ++ struct wmi_scan_prob_req_oui_cmd *cmd; ++ u32 prob_req_oui; ++ int len; ++ ++ prob_req_oui = (((u32)mac_addr[0]) << 16) | ++ (((u32)mac_addr[1]) << 8) | mac_addr[2]; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_scan_prob_req_oui_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_SCAN_PROB_REQ_OUI_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ cmd->prob_req_oui = prob_req_oui; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi scan prob req oui %d\n", ++ prob_req_oui); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID); ++} +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3313,6 +3313,8 @@ struct scan_req_params { + u32 num_hint_bssid; + struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID]; + struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID]; ++ struct wmi_mac_addr mac_addr; ++ struct wmi_mac_addr mac_mask; + }; + + struct wmi_ssid_arg { +@@ -3676,6 +3678,11 @@ struct wmi_scan_chan_list_cmd { + u32 pdev_id; + } __packed; + ++struct wmi_scan_prob_req_oui_cmd { ++ u32 tlv_header; ++ u32 prob_req_oui; ++} __packed; ++ + #define WMI_MGMT_SEND_DOWNLD_LEN 64 + + #define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0) +@@ -5530,5 +5537,6 @@ int ath11k_wmi_set_hw_mode(struct ath11k + enum wmi_host_hw_mode_config_type mode); + int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar); + int ath11k_wmi_wow_enable(struct ath11k *ar); +- ++int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, ++ const u8 mac_addr[ETH_ALEN]); + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0137-ath11k-set-DTIM-policy-to-stick-mode-for-station-int.patch b/package/kernel/mac80211/patches/ath11k/0137-ath11k-set-DTIM-policy-to-stick-mode-for-station-int.patch new file mode 100644 index 000000000..a74d67801 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0137-ath11k-set-DTIM-policy-to-stick-mode-for-station-int.patch @@ -0,0 +1,51 @@ +From 55e18e5a76ab5de2286d4bac703a78066278f475 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Thu, 9 Dec 2021 10:17:49 +0200 +Subject: [PATCH] ath11k: set DTIM policy to stick mode for station interface + +Set DTIM policy to DTIM stick mode, so station follows AP DTIM +interval rather than listen interval which is set in peer assoc cmd. +DTIM stick mode is more preferred per firmware team request. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638948694-15582-1-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 7 +++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 7 +++++++ + 2 files changed, 14 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2682,6 +2682,13 @@ static void ath11k_bss_assoc(struct ieee + ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", + arvif->vdev_id, ret); + ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ WMI_VDEV_PARAM_DTIM_POLICY, ++ WMI_DTIM_POLICY_STICK); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to set vdev %d dtim policy: %d\n", ++ arvif->vdev_id, ret); ++ + ath11k_mac_11d_scan_stop_all(ar->ab); + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2169,6 +2169,13 @@ enum wmi_nss_ratio { + WMI_NSS_RATIO_2_NSS = 0x3, + }; + ++enum wmi_dtim_policy { ++ WMI_DTIM_POLICY_IGNORE = 1, ++ WMI_DTIM_POLICY_NORMAL = 2, ++ WMI_DTIM_POLICY_STICK = 3, ++ WMI_DTIM_POLICY_AUTO = 4, ++}; ++ + struct wmi_host_pdev_band_to_mac { + u32 pdev_id; + u32 start_freq; diff --git a/package/kernel/mac80211/patches/ath11k/0141-ath11k-add-ab-to-TARGET_NUM_VDEVS-co.patch b/package/kernel/mac80211/patches/ath11k/0141-ath11k-add-ab-to-TARGET_NUM_VDEVS-co.patch new file mode 100644 index 000000000..750ec81e3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0141-ath11k-add-ab-to-TARGET_NUM_VDEVS-co.patch @@ -0,0 +1,130 @@ +From 523aafd0f071c5f9e951a861c30531c1eeb01ad4 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Mon, 13 Dec 2021 11:53:08 +0200 +Subject: [PATCH] ath11k: add ab to TARGET_NUM_VDEVS & co + +The next patch changes TARGET_NUM_VDEVS to be dynamic and need access to ab. +Add ab separately to keep the next patch simple. + +Compile tested only. + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211209104351.9811-2-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/core.c | 2 +- + drivers/net/wireless/ath/ath11k/hw.c | 14 +++++++------- + drivers/net/wireless/ath/ath11k/hw.h | 18 +++++++++--------- + drivers/net/wireless/ath/ath11k/mac.c | 10 +++++----- + 4 files changed, 22 insertions(+), 22 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1067,7 +1067,7 @@ static int ath11k_core_reconfigure_on_cr + ath11k_dp_free(ab); + ath11k_hal_srng_deinit(ab); + +- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; ++ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; + + ret = ath11k_hal_srng_init(ab); + if (ret) +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -150,18 +150,18 @@ static void ath11k_hw_ipq8074_reo_setup( + static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, + struct target_resource_config *config) + { +- config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; ++ config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab); + + if (ab->num_radios == 2) { +- config->num_peers = TARGET_NUM_PEERS(DBS); +- config->num_tids = TARGET_NUM_TIDS(DBS); ++ config->num_peers = TARGET_NUM_PEERS(ab, DBS); ++ config->num_tids = TARGET_NUM_TIDS(ab, DBS); + } else if (ab->num_radios == 3) { +- config->num_peers = TARGET_NUM_PEERS(DBS_SBS); +- config->num_tids = TARGET_NUM_TIDS(DBS_SBS); ++ config->num_peers = TARGET_NUM_PEERS(ab, DBS_SBS); ++ config->num_tids = TARGET_NUM_TIDS(ab, DBS_SBS); + } else { + /* Control should not reach here */ +- config->num_peers = TARGET_NUM_PEERS(SINGLE); +- config->num_tids = TARGET_NUM_TIDS(SINGLE); ++ config->num_peers = TARGET_NUM_PEERS(ab, SINGLE); ++ config->num_tids = TARGET_NUM_TIDS(ab, SINGLE); + } + config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; + config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -12,26 +12,26 @@ + /* Target configuration defines */ + + /* Num VDEVS per radio */ +-#define TARGET_NUM_VDEVS (16 + 1) ++#define TARGET_NUM_VDEVS(ab) (16 + 1) + +-#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS) ++#define TARGET_NUM_PEERS_PDEV(ab) (512 + TARGET_NUM_VDEVS(ab)) + + /* Num of peers for Single Radio mode */ +-#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV) ++#define TARGET_NUM_PEERS_SINGLE(ab) (TARGET_NUM_PEERS_PDEV(ab)) + + /* Num of peers for DBS */ +-#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV) ++#define TARGET_NUM_PEERS_DBS(ab) (2 * TARGET_NUM_PEERS_PDEV(ab)) + + /* Num of peers for DBS_SBS */ +-#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV) ++#define TARGET_NUM_PEERS_DBS_SBS(ab) (3 * TARGET_NUM_PEERS_PDEV(ab)) + + /* Max num of stations (per radio) */ +-#define TARGET_NUM_STATIONS 512 ++#define TARGET_NUM_STATIONS(ab) 512 + +-#define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x ++#define TARGET_NUM_PEERS(ab, x) TARGET_NUM_PEERS_##x(ab) + #define TARGET_NUM_PEER_KEYS 2 +-#define TARGET_NUM_TIDS(x) (2 * TARGET_NUM_PEERS(x) + \ +- 4 * TARGET_NUM_VDEVS + 8) ++#define TARGET_NUM_TIDS(ab, x) (2 * TARGET_NUM_PEERS(ab, x) + \ ++ 4 * TARGET_NUM_VDEVS(ab) + 8) + + #define TARGET_AST_SKID_LIMIT 16 + #define TARGET_NUM_OFFLD_PEERS 4 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6004,9 +6004,9 @@ static int ath11k_mac_op_add_interface(s + goto err; + } + +- if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { ++ if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) { + ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n", +- ar->num_created_vdevs, TARGET_NUM_VDEVS); ++ ar->num_created_vdevs, TARGET_NUM_VDEVS(ab)); + ret = -EBUSY; + goto err; + } +@@ -8202,8 +8202,8 @@ static int __ath11k_mac_register(struct + ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_AP_SCAN; + +- ar->max_num_stations = TARGET_NUM_STATIONS; +- ar->max_num_peers = TARGET_NUM_PEERS_PDEV; ++ ar->max_num_stations = TARGET_NUM_STATIONS(ab); ++ ar->max_num_peers = TARGET_NUM_PEERS_PDEV(ab); + + ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + +@@ -8306,7 +8306,7 @@ int ath11k_mac_register(struct ath11k_ba + + /* Initialize channel counters frequency value in hertz */ + ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; +- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; ++ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; diff --git a/package/kernel/mac80211/patches/ath11k/0142-ath11k-Change-qcn9074-fw-to-operate-in-mode-2.patch b/package/kernel/mac80211/patches/ath11k/0142-ath11k-Change-qcn9074-fw-to-operate-in-mode-2.patch new file mode 100644 index 000000000..7d9f0cd76 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0142-ath11k-Change-qcn9074-fw-to-operate-in-mode-2.patch @@ -0,0 +1,139 @@ +From beefee71336bfb406c3e37a0de8a12881424e78c Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Mon, 13 Dec 2021 11:53:08 +0200 +Subject: [PATCH] ath11k: Change qcn9074 fw to operate in mode-2 + +In mode-2 QCN9074 firmware uses 15MB of host memory and firmware +request 1MB size segements in QMI, whereas in mode-0 firmware +uses 45MB of host memory and each segment is of 2MB size. +In mode-2 firmware operates with reduced number of vdevs and peers. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211209104351.9811-3-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/core.c | 18 ++++++++++++++++++ + drivers/net/wireless/ath/ath11k/hw.h | 9 ++++++--- + drivers/net/wireless/ath/ath11k/qmi.c | 2 +- + drivers/net/wireless/ath/ath11k/qmi.h | 1 - + 4 files changed, 25 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -79,6 +79,9 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = true, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, +@@ -134,6 +137,9 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = true, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, +@@ -188,6 +194,9 @@ static const struct ath11k_hw_params ath + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, +@@ -242,6 +251,9 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = false, ++ .fw_mem_mode = 2, ++ .num_vdevs = 8, ++ .num_peers = 128, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, +@@ -296,6 +308,9 @@ static const struct ath11k_hw_params ath + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, +@@ -349,6 +364,9 @@ static const struct ath11k_hw_params ath + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -12,9 +12,9 @@ + /* Target configuration defines */ + + /* Num VDEVS per radio */ +-#define TARGET_NUM_VDEVS(ab) (16 + 1) ++#define TARGET_NUM_VDEVS(ab) (ab->hw_params.num_vdevs) + +-#define TARGET_NUM_PEERS_PDEV(ab) (512 + TARGET_NUM_VDEVS(ab)) ++#define TARGET_NUM_PEERS_PDEV(ab) (ab->hw_params.num_peers + TARGET_NUM_VDEVS(ab)) + + /* Num of peers for Single Radio mode */ + #define TARGET_NUM_PEERS_SINGLE(ab) (TARGET_NUM_PEERS_PDEV(ab)) +@@ -26,7 +26,7 @@ + #define TARGET_NUM_PEERS_DBS_SBS(ab) (3 * TARGET_NUM_PEERS_PDEV(ab)) + + /* Max num of stations (per radio) */ +-#define TARGET_NUM_STATIONS(ab) 512 ++#define TARGET_NUM_STATIONS(ab) (ab->hw_params.num_peers) + + #define TARGET_NUM_PEERS(ab, x) TARGET_NUM_PEERS_##x(ab) + #define TARGET_NUM_PEER_KEYS 2 +@@ -173,6 +173,9 @@ struct ath11k_hw_params { + bool idle_ps; + bool supports_sta_ps; + bool cold_boot_calib; ++ int fw_mem_mode; ++ u32 num_vdevs; ++ u32 num_peers; + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2830,7 +2830,7 @@ int ath11k_qmi_init_service(struct ath11 + memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk)); + ab->qmi.ab = ab; + +- ab->qmi.target_mem_mode = ATH11K_QMI_TARGET_MEM_MODE_DEFAULT; ++ ab->qmi.target_mem_mode = ab->hw_params.fw_mem_mode; + ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX, + &ath11k_qmi_ops, ath11k_qmi_msg_handlers); + if (ret < 0) { +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -34,7 +34,6 @@ + + #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 + #define ATH11K_FIRMWARE_MODE_OFF 4 +-#define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0 + #define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ) + + struct ath11k_base; diff --git a/package/kernel/mac80211/patches/ath11k/0143-ath11k-Use-reserved-host-DDR-addresses-from-DT-for-P.patch b/package/kernel/mac80211/patches/ath11k/0143-ath11k-Use-reserved-host-DDR-addresses-from-DT-for-P.patch new file mode 100644 index 000000000..4842e5261 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0143-ath11k-Use-reserved-host-DDR-addresses-from-DT-for-P.patch @@ -0,0 +1,254 @@ +From 6ac04bdc5edb418787ab2040b1f922c23464c750 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 14 Dec 2021 17:39:43 +0200 +Subject: [PATCH] ath11k: Use reserved host DDR addresses from DT for PCI + devices + +Host DDR memory (contiguous 45 MB in mode-0 or 15 MB in mode-2) +is reserved through DT entries for firmware usage. Send the base +address from DT entries. +If DT entry is available, PCI device will work with +fixed_mem_region else host allocates multiple segments. + +IPQ8074 on HK10 board supports multiple PCI devices. +IPQ8074 + QCN9074 is tested with this patch. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638789319-2950-2-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mhi.c | 34 ++++++++++++- + drivers/net/wireless/ath/ath11k/pci.c | 11 ++++- + drivers/net/wireless/ath/ath11k/qmi.c | 67 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/qmi.h | 1 + + 5 files changed, 101 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -203,6 +203,7 @@ enum ath11k_dev_flags { + ATH11K_FLAG_HTC_SUSPEND_COMPLETE, + ATH11K_FLAG_CE_IRQ_ENABLED, + ATH11K_FLAG_EXT_IRQ_ENABLED, ++ ATH11K_FLAG_FIXED_MEM_RGN, + }; + + enum ath11k_monitor_flags { +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -3,6 +3,9 @@ + + #include + #include ++#include ++#include ++#include + + #include "core.h" + #include "debug.h" +@@ -318,6 +321,26 @@ static void ath11k_mhi_op_write_reg(stru + writel(val, addr); + } + ++static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl) ++{ ++ struct device_node *np; ++ struct resource res; ++ int ret; ++ ++ np = of_find_node_by_type(NULL, "memory"); ++ if (!np) ++ return -ENOENT; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ if (ret) ++ return ret; ++ ++ mhi_ctrl->iova_start = res.start + 0x1000000; ++ mhi_ctrl->iova_stop = res.end; ++ ++ return 0; ++} ++ + int ath11k_mhi_register(struct ath11k_pci *ab_pci) + { + struct ath11k_base *ab = ab_pci->ab; +@@ -351,8 +374,15 @@ int ath11k_mhi_register(struct ath11k_pc + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + +- mhi_ctrl->iova_start = 0; +- mhi_ctrl->iova_stop = 0xffffffff; ++ if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { ++ ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl); ++ if (ret < 0) ++ return ret; ++ } else { ++ mhi_ctrl->iova_start = 0; ++ mhi_ctrl->iova_stop = 0xFFFFFFFF; ++ } ++ + mhi_ctrl->sbl_size = SZ_512K; + mhi_ctrl->seg_len = SZ_512K; + mhi_ctrl->fbc_download = true; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #include "pci.h" + #include "core.h" +@@ -1353,7 +1354,7 @@ static int ath11k_pci_probe(struct pci_d + { + struct ath11k_base *ab; + struct ath11k_pci *ab_pci; +- u32 soc_hw_version_major, soc_hw_version_minor; ++ u32 soc_hw_version_major, soc_hw_version_minor, addr; + int ret; + + ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, +@@ -1373,6 +1374,14 @@ static int ath11k_pci_probe(struct pci_d + pci_set_drvdata(pdev, ab); + spin_lock_init(&ab_pci->window_lock); + ++ /* Set fixed_mem_region to true for platforms support reserved memory ++ * from DT. If memory is reserved from DT for FW, ath11k driver need not ++ * allocate memory. ++ */ ++ ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); ++ if (!ret) ++ set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); ++ + ret = ath11k_pci_claim(ab_pci, pdev); + if (ret) { + ath11k_err(ab, "failed to claim device: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -9,6 +9,8 @@ + #include "core.h" + #include "debug.h" + #include ++#include ++#include + #include + + #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 +@@ -1751,7 +1753,9 @@ static int ath11k_qmi_respond_fw_mem_req + * failure to FW and FW will then request mulitple blocks of small + * chunk size memory. + */ +- if (!ab->bus_params.fixed_mem_region && ab->qmi.target_mem_delayed) { ++ if (!(ab->bus_params.fixed_mem_region || ++ test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && ++ ab->qmi.target_mem_delayed) { + delayed = true; + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n", + ab->qmi.mem_seg_count); +@@ -1818,10 +1822,12 @@ static void ath11k_qmi_free_target_mem_c + { + int i; + +- if (ab->bus_params.fixed_mem_region) +- return; +- + for (i = 0; i < ab->qmi.mem_seg_count; i++) { ++ if ((ab->bus_params.fixed_mem_region || ++ test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && ++ ab->qmi.target_mem[i].iaddr) ++ iounmap(ab->qmi.target_mem[i].iaddr); ++ + if (!ab->qmi.target_mem[i].vaddr) + continue; + +@@ -1869,10 +1875,44 @@ static int ath11k_qmi_alloc_target_mem_c + + static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) + { +- int i, idx; ++ struct device *dev = ab->dev; ++ struct device_node *hremote_node = NULL; ++ struct resource res; ++ u32 host_ddr_sz; ++ int i, idx, ret; + + for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { + switch (ab->qmi.target_mem[i].type) { ++ case HOST_DDR_REGION_TYPE: ++ hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0); ++ if (!hremote_node) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "qmi fail to get hremote_node\n"); ++ return ret; ++ } ++ ++ ret = of_address_to_resource(hremote_node, 0, &res); ++ if (ret) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "qmi fail to get reg from hremote\n"); ++ return ret; ++ } ++ ++ if (res.end - res.start + 1 < ab->qmi.target_mem[i].size) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "qmi fail to assign memory of sz\n"); ++ return -EINVAL; ++ } ++ ++ ab->qmi.target_mem[idx].paddr = res.start; ++ ab->qmi.target_mem[idx].iaddr = ++ ioremap(ab->qmi.target_mem[idx].paddr, ++ ab->qmi.target_mem[i].size); ++ ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ++ host_ddr_sz = ab->qmi.target_mem[i].size; ++ ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; ++ idx++; ++ break; + case BDF_MEM_REGION_TYPE: + ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; + ab->qmi.target_mem[idx].vaddr = NULL; +@@ -1887,10 +1927,16 @@ static int ath11k_qmi_assign_target_mem_ + } + + if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) { +- ab->qmi.target_mem[idx].paddr = +- ATH11K_QMI_CALDB_ADDRESS; +- ab->qmi.target_mem[idx].vaddr = +- (void *)ATH11K_QMI_CALDB_ADDRESS; ++ if (hremote_node) { ++ ab->qmi.target_mem[idx].paddr = ++ res.start + host_ddr_sz; ++ ab->qmi.target_mem[idx].iaddr = ++ ioremap(ab->qmi.target_mem[idx].paddr, ++ ab->qmi.target_mem[i].size); ++ } else { ++ ab->qmi.target_mem[idx].paddr = ++ ATH11K_QMI_CALDB_ADDRESS; ++ } + } else { + ab->qmi.target_mem[idx].paddr = 0; + ab->qmi.target_mem[idx].vaddr = NULL; +@@ -2621,7 +2667,8 @@ static void ath11k_qmi_msg_mem_request_c + msg->mem_seg[i].type, msg->mem_seg[i].size); + } + +- if (ab->bus_params.fixed_mem_region) { ++ if (ab->bus_params.fixed_mem_region || ++ test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { + ret = ath11k_qmi_assign_target_mem_chunk(ab); + if (ret) { + ath11k_warn(ab, "failed to assign qmi target memory: %d\n", +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -94,6 +94,7 @@ struct target_mem_chunk { + u32 type; + dma_addr_t paddr; + u32 *vaddr; ++ void __iomem *iaddr; + }; + + struct target_info { diff --git a/package/kernel/mac80211/patches/ath11k/0144-ath11k-report-rssi-of-each-chain-to-mac80211-for-QCA.patch b/package/kernel/mac80211/patches/ath11k/0144-ath11k-report-rssi-of-each-chain-to-mac80211-for-QCA.patch new file mode 100644 index 000000000..aff101f5f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0144-ath11k-report-rssi-of-each-chain-to-mac80211-for-QCA.patch @@ -0,0 +1,654 @@ +From b488c766442f7d9c07ea0708aa2a1a6bff1baef5 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Fri, 17 Dec 2021 20:27:21 +0200 +Subject: [PATCH] ath11k: report rssi of each chain to mac80211 for + QCA6390/WCN6855 + +Command "iw wls1 station dump" does not show each chain's rssi currently. + +If the rssi of each chain from mon status which parsed in function +ath11k_hal_rx_parse_mon_status_tlv() is invalid, then ath11k send +wmi cmd WMI_REQUEST_STATS_CMDID with flag WMI_REQUEST_RSSI_PER_CHAIN_STAT +to firmware, and parse the rssi of chain in wmi WMI_UPDATE_STATS_EVENTID, +then report them to mac80211. + +WMI_REQUEST_STATS_CMDID is only sent when CONFIG_ATH11K_DEBUGFS is set, +it is only called by ath11k_mac_op_sta_statistics(). It does not effect +performance and power consumption. Because after STATION connected to +AP, it is only called every 6 seconds by NetworkManager in below stack. + +[ 797.005587] CPU: 0 PID: 701 Comm: NetworkManager Tainted: G W OE 5.13.0-rc6-wt-ath+ #2 +[ 797.005596] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 +[ 797.005600] RIP: 0010:ath11k_mac_op_sta_statistics+0x2f/0x1b0 [ath11k] +[ 797.005644] Code: 41 56 41 55 4c 8d aa 58 01 00 00 41 54 55 48 89 d5 53 48 8b 82 58 01 00 00 48 89 cb 4c 8b 70 20 49 8b 06 4c 8b a0 90 08 00 00 <0f> 0b 48 8b 82 b8 01 00 00 48 ba 00 00 00 00 01 00 00 00 48 89 81 +[ 797.005651] RSP: 0018:ffffb1fc80a4b890 EFLAGS: 00010282 +[ 797.005658] RAX: ffff8a5726200000 RBX: ffffb1fc80a4b958 RCX: ffffb1fc80a4b958 +[ 797.005664] RDX: ffff8a5726a609f0 RSI: ffff8a581247f598 RDI: ffff8a5702878800 +[ 797.005668] RBP: ffff8a5726a609f0 R08: 0000000000000000 R09: 0000000000000000 +[ 797.005672] R10: 0000000000000000 R11: 0000000000000007 R12: 02dd68024f75f480 +[ 797.005676] R13: ffff8a5726a60b48 R14: ffff8a5702879f40 R15: ffff8a5726a60000 +[ 797.005681] FS: 00007f632c52a380(0000) GS:ffff8a583a200000(0000) knlGS:0000000000000000 +[ 797.005687] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 797.005692] CR2: 00007fb025d69000 CR3: 00000001124f6005 CR4: 00000000000606f0 +[ 797.005698] Call Trace: +[ 797.005710] sta_set_sinfo+0xa7/0xb80 [mac80211] +[ 797.005820] ieee80211_get_station+0x50/0x70 [mac80211] +[ 797.005925] nl80211_get_station+0xd1/0x200 [cfg80211] +[ 797.006045] genl_family_rcv_msg_doit.isra.15+0x111/0x140 +[ 797.006059] genl_rcv_msg+0xe6/0x1e0 +[ 797.006065] ? nl80211_dump_station+0x220/0x220 [cfg80211] +[ 797.006223] ? nl80211_send_station.isra.72+0xf50/0xf50 [cfg80211] +[ 797.006348] ? genl_family_rcv_msg_doit.isra.15+0x140/0x140 +[ 797.006355] netlink_rcv_skb+0xb9/0xf0 +[ 797.006363] genl_rcv+0x24/0x40 +[ 797.006369] netlink_unicast+0x18e/0x290 +[ 797.006375] netlink_sendmsg+0x30f/0x450 +[ 797.006382] sock_sendmsg+0x5b/0x60 +[ 797.006393] ____sys_sendmsg+0x219/0x240 +[ 797.006403] ? copy_msghdr_from_user+0x5c/0x90 +[ 797.006413] ? ____sys_recvmsg+0xf5/0x190 +[ 797.006422] ___sys_sendmsg+0x88/0xd0 +[ 797.006432] ? copy_msghdr_from_user+0x5c/0x90 +[ 797.006443] ? ___sys_recvmsg+0x9e/0xd0 +[ 797.006454] ? __fget_files+0x58/0x90 +[ 797.006461] ? __fget_light+0x2d/0x70 +[ 797.006466] ? do_epoll_wait+0xce/0x720 +[ 797.006476] ? __sys_sendmsg+0x63/0xa0 +[ 797.006485] __sys_sendmsg+0x63/0xa0 +[ 797.006497] do_syscall_64+0x3c/0xb0 +[ 797.006509] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 797.006519] RIP: 0033:0x7f632d99912d +[ 797.006526] Code: 28 89 54 24 1c 48 89 74 24 10 89 7c 24 08 e8 ca ee ff ff 8b 54 24 1c 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 2f 44 89 c7 48 89 44 24 08 e8 fe ee ff ff 48 +[ 797.006533] RSP: 002b:00007ffd80808c00 EFLAGS: 00000293 ORIG_RAX: 000000000000002e +[ 797.006540] RAX: ffffffffffffffda RBX: 0000563dab99d840 RCX: 00007f632d99912d +[ 797.006545] RDX: 0000000000000000 RSI: 00007ffd80808c50 RDI: 000000000000000b +[ 797.006549] RBP: 00007ffd80808c50 R08: 0000000000000000 R09: 0000000000001000 +[ 797.006552] R10: 0000563dab96f010 R11: 0000000000000293 R12: 0000563dab99d840 +[ 797.006556] R13: 0000563dabbb28c0 R14: 00007f632dad4280 R15: 0000563dabab11c0 +[ 797.006563] ---[ end trace c9dcf08920c9945c ]--- + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02892.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211215090944.19729-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 + + drivers/net/wireless/ath/ath11k/core.h | 5 + + drivers/net/wireless/ath/ath11k/debugfs.c | 37 +++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 8 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 8 + + drivers/net/wireless/ath/ath11k/hal_rx.c | 11 ++ + drivers/net/wireless/ath/ath11k/hal_rx.h | 12 +- + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 40 +++++ + drivers/net/wireless/ath/ath11k/wmi.c | 179 ++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/wmi.h | 11 ++ + 11 files changed, 284 insertions(+), 34 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -91,6 +91,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, ++ .supports_rssi_stats = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -149,6 +150,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, ++ .supports_rssi_stats = false, + }, + { + .name = "qca6390 hw2.0", +@@ -206,6 +208,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, ++ .supports_rssi_stats = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -263,6 +266,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = true, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, ++ .supports_rssi_stats = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -320,6 +324,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, ++ .supports_rssi_stats = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -376,6 +381,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, ++ .supports_rssi_stats = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -387,6 +387,7 @@ struct ath11k_sta { + u64 rx_duration; + u64 tx_duration; + u8 rssi_comb; ++ s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct ath11k_htt_tx_stats *tx_stats; + struct ath11k_rx_peer_stats *rx_stats; + +@@ -417,6 +418,10 @@ enum ath11k_state { + /* Antenna noise floor */ + #define ATH11K_DEFAULT_NOISE_FLOOR -95 + ++#define ATH11K_INVALID_RSSI_FULL -1 ++ ++#define ATH11K_INVALID_RSSI_EMPTY -128 ++ + struct ath11k_fw_stats { + struct dentry *debugfs_fwstats; + u32 pdev_id; +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -126,6 +126,11 @@ void ath11k_debugfs_fw_stats_process(str + goto complete; + } + ++ if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) { ++ ar->debug.fw_stats_done = true; ++ goto complete; ++ } ++ + if (stats.stats_id == WMI_REQUEST_VDEV_STAT) { + if (list_empty(&stats.vdevs)) { + ath11k_warn(ab, "empty vdev stats"); +@@ -229,6 +234,38 @@ static int ath11k_debugfs_fw_stats_reque + return 0; + } + ++int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id, ++ u32 vdev_id, u32 stats_id) ++{ ++ struct ath11k_base *ab = ar->ab; ++ struct stats_request_params req_param; ++ int ret; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (ar->state != ATH11K_STATE_ON) { ++ ret = -ENETDOWN; ++ goto err_unlock; ++ } ++ ++ req_param.pdev_id = pdev_id; ++ req_param.vdev_id = vdev_id; ++ req_param.stats_id = stats_id; ++ ++ ret = ath11k_debugfs_fw_stats_request(ar, &req_param); ++ if (ret) ++ ath11k_warn(ab, "failed to request fw stats: %d\n", ret); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n", ++ pdev_id, vdev_id, stats_id); ++ ++err_unlock: ++ mutex_unlock(&ar->conf_mutex); ++ ++ return ret; ++} ++ + static int ath11k_open_pdev_stats(struct inode *inode, struct file *file) + { + struct ath11k *ar = inode->i_private; +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -117,6 +117,8 @@ void ath11k_debugfs_unregister(struct at + void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb); + + void ath11k_debugfs_fw_stats_init(struct ath11k *ar); ++int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id, ++ u32 vdev_id, u32 stats_id); + + static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar) + { +@@ -215,6 +217,12 @@ static inline int ath11k_debugfs_rx_filt + { + return 0; + } ++ ++static inline int ath11k_debugfs_get_fw_stats(struct ath11k *ar, ++ u32 pdev_id, u32 vdev_id, u32 stats_id) ++{ ++ return 0; ++} + + #endif /* CPTCFG_MAC80211_DEBUGFS*/ + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2768,6 +2768,7 @@ static void ath11k_dp_rx_update_peer_sta + { + struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats; + u32 num_msdu; ++ int i; + + if (!rx_stats) + return; +@@ -2829,6 +2830,13 @@ static void ath11k_dp_rx_update_peer_sta + rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu; + + arsta->rssi_comb = ppdu_info->rssi_comb; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) > ++ ARRAY_SIZE(ppdu_info->rssi_chain_pri20)); ++ ++ for (i = 0; i < ARRAY_SIZE(arsta->chain_signal); i++) ++ arsta->chain_signal[i] = ppdu_info->rssi_chain_pri20[i]; ++ + rx_stats->rx_duration += ppdu_info->rx_duration; + arsta->rx_duration = rx_stats->rx_duration; + } +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -1080,6 +1080,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + break; + } + case HAL_PHYRX_RSSI_LEGACY: { ++ int i; ++ bool db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, ++ ab->wmi_ab.svc_map); + struct hal_rx_phyrx_rssi_legacy_info *rssi = + (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data; + +@@ -1090,6 +1093,14 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + ppdu_info->rssi_comb = + FIELD_GET(HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB, + __le32_to_cpu(rssi->info0)); ++ ++ if (db2dbm) { ++ for (i = 0; i < ARRAY_SIZE(rssi->preamble); i++) { ++ ppdu_info->rssi_chain_pri20[i] = ++ le32_get_bits(rssi->preamble[i].rssi_2040, ++ HAL_RX_PHYRX_RSSI_PREAMBLE_PRI20); ++ } ++ } + break; + } + case HAL_RX_MPDU_START: { +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -112,6 +112,7 @@ struct hal_rx_mon_ppdu_info { + u8 ldpc; + u8 beamformed; + u8 rssi_comb; ++ u8 rssi_chain_pri20[HAL_RX_MAX_NSS]; + u8 tid; + u8 dcm; + u8 ru_alloc; +@@ -262,8 +263,17 @@ struct hal_rx_he_sig_b2_ofdma_info { + + #define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) + ++#define HAL_RX_PHYRX_RSSI_PREAMBLE_PRI20 GENMASK(7, 0) ++ ++struct hal_rx_phyrx_chain_rssi { ++ __le32 rssi_2040; ++ __le32 rssi_80; ++} __packed; ++ + struct hal_rx_phyrx_rssi_legacy_info { +- __le32 rsvd[35]; ++ __le32 rsvd[3]; ++ struct hal_rx_phyrx_chain_rssi pre_rssi[HAL_RX_MAX_NSS]; ++ struct hal_rx_phyrx_chain_rssi preamble[HAL_RX_MAX_NSS]; + __le32 info0; + } __packed; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -185,6 +185,7 @@ struct ath11k_hw_params { + bool supports_dynamic_smps_6ghz; + bool alloc_cacheable_memory; + bool wakeup_mhi; ++ bool supports_rssi_stats; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7775,12 +7775,42 @@ exit: + return ret; + } + ++static void ath11k_mac_put_chain_rssi(struct station_info *sinfo, ++ struct ath11k_sta *arsta, ++ char *pre, ++ bool clear) ++{ ++ struct ath11k *ar = arsta->arvif->ar; ++ int i; ++ s8 rssi; ++ ++ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { ++ sinfo->chains &= ~BIT(i); ++ rssi = arsta->chain_signal[i]; ++ if (clear) ++ arsta->chain_signal[i] = ATH11K_INVALID_RSSI_FULL; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac sta statistics %s rssi[%d] %d\n", pre, i, rssi); ++ ++ if (rssi != ATH11K_DEFAULT_NOISE_FLOOR && ++ rssi != ATH11K_INVALID_RSSI_FULL && ++ rssi != ATH11K_INVALID_RSSI_EMPTY && ++ rssi != 0) { ++ sinfo->chain_signal[i] = rssi; ++ sinfo->chains |= BIT(i); ++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); ++ } ++ } ++} ++ + static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) + { + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; ++ struct ath11k *ar = arsta->arvif->ar; + + sinfo->rx_duration = arsta->rx_duration; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); +@@ -7803,6 +7833,16 @@ static void ath11k_mac_op_sta_statistics + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + } + ++ ath11k_mac_put_chain_rssi(sinfo, arsta, "ppdu", false); ++ ++ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && ++ arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && ++ ar->ab->hw_params.supports_rssi_stats && ++ !ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, ++ WMI_REQUEST_RSSI_PER_CHAIN_STAT)) { ++ ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true); ++ } ++ + /* TODO: Use real NF instead of default one. */ + sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -73,6 +73,14 @@ struct wmi_tlv_dma_buf_release_parse { + bool meta_data_done; + }; + ++struct wmi_tlv_fw_stats_parse { ++ const struct wmi_stats_event *ev; ++ const struct wmi_per_chain_rssi_stats *rssi; ++ struct ath11k_fw_stats *stats; ++ int rssi_num; ++ bool chain_rssi_done; ++}; ++ + static const struct wmi_tlv_policy wmi_tlv_policies[] = { + [WMI_TAG_ARRAY_BYTE] + = { .min_len = 0 }, +@@ -132,6 +140,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_obss_color_collision_event) }, + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, ++ [WMI_TAG_PER_CHAIN_RSSI_STATS] = { ++ .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -5554,37 +5564,89 @@ ath11k_wmi_pull_bcn_stats(const struct w + dst->tx_bcn_outage_cnt = src->tx_bcn_outage_cnt; + } + +-int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, +- struct ath11k_fw_stats *stats) +-{ +- const void **tb; +- const struct wmi_stats_event *ev; +- const void *data; +- int i, ret; +- u32 len = skb->len; ++static int ath11k_wmi_tlv_rssi_chain_parse(struct ath11k_base *ab, ++ u16 tag, u16 len, ++ const void *ptr, void *data) ++{ ++ struct wmi_tlv_fw_stats_parse *parse = data; ++ const struct wmi_stats_event *ev = parse->ev; ++ struct ath11k_fw_stats *stats = parse->stats; ++ struct ath11k *ar; ++ struct ath11k_vif *arvif; ++ struct ieee80211_sta *sta; ++ struct ath11k_sta *arsta; ++ const struct wmi_rssi_stats *stats_rssi = (const struct wmi_rssi_stats *)ptr; ++ int j, ret = 0; + +- tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, len, GFP_ATOMIC); +- if (IS_ERR(tb)) { +- ret = PTR_ERR(tb); +- ath11k_warn(ab, "failed to parse tlv: %d\n", ret); +- return ret; ++ if (tag != WMI_TAG_RSSI_STATS) ++ return -EPROTO; ++ ++ rcu_read_lock(); ++ ++ ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id); ++ stats->stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats vdev id %d mac %pM\n", ++ stats_rssi->vdev_id, stats_rssi->peer_macaddr.addr); ++ ++ arvif = ath11k_mac_get_arvif(ar, stats_rssi->vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "not found vif for vdev id %d\n", ++ stats_rssi->vdev_id); ++ ret = -EPROTO; ++ goto exit; + } + +- ev = tb[WMI_TAG_STATS_EVENT]; +- data = tb[WMI_TAG_ARRAY_BYTE]; +- if (!ev || !data) { ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats bssid %pM vif %pK\n", ++ arvif->bssid, arvif->vif); ++ ++ sta = ieee80211_find_sta_by_ifaddr(ar->hw, ++ arvif->bssid, ++ NULL); ++ if (!sta) { ++ ath11k_warn(ab, "not found station for bssid %pM\n", ++ arvif->bssid); ++ ret = -EPROTO; ++ goto exit; ++ } ++ ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) > ++ ARRAY_SIZE(stats_rssi->rssi_avg_beacon)); ++ ++ for (j = 0; j < ARRAY_SIZE(arsta->chain_signal); j++) { ++ arsta->chain_signal[j] = stats_rssi->rssi_avg_beacon[j]; ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats beacon rssi[%d] %d data rssi[%d] %d\n", ++ j, ++ stats_rssi->rssi_avg_beacon[j], ++ j, ++ stats_rssi->rssi_avg_data[j]); ++ } ++ ++exit: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static int ath11k_wmi_tlv_fw_stats_data_parse(struct ath11k_base *ab, ++ struct wmi_tlv_fw_stats_parse *parse, ++ const void *ptr, ++ u16 len) ++{ ++ struct ath11k_fw_stats *stats = parse->stats; ++ const struct wmi_stats_event *ev = parse->ev; ++ int i; ++ const void *data = ptr; ++ ++ if (!ev) { + ath11k_warn(ab, "failed to fetch update stats ev"); +- kfree(tb); + return -EPROTO; + } + +- ath11k_dbg(ab, ATH11K_DBG_WMI, +- "wmi stats update ev pdev_id %d pdev %i vdev %i bcn %i\n", +- ev->pdev_id, +- ev->num_pdev_stats, ev->num_vdev_stats, +- ev->num_bcn_stats); +- +- stats->pdev_id = ev->pdev_id; + stats->stats_id = 0; + + for (i = 0; i < ev->num_pdev_stats; i++) { +@@ -5592,10 +5654,8 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + struct ath11k_fw_stats_pdev *dst; + + src = data; +- if (len < sizeof(*src)) { +- kfree(tb); ++ if (len < sizeof(*src)) + return -EPROTO; +- } + + stats->stats_id = WMI_REQUEST_PDEV_STAT; + +@@ -5617,10 +5677,8 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + struct ath11k_fw_stats_vdev *dst; + + src = data; +- if (len < sizeof(*src)) { +- kfree(tb); ++ if (len < sizeof(*src)) + return -EPROTO; +- } + + stats->stats_id = WMI_REQUEST_VDEV_STAT; + +@@ -5640,10 +5698,8 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + struct ath11k_fw_stats_bcn *dst; + + src = data; +- if (len < sizeof(*src)) { +- kfree(tb); ++ if (len < sizeof(*src)) + return -EPROTO; +- } + + stats->stats_id = WMI_REQUEST_BCN_STAT; + +@@ -5658,10 +5714,67 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + list_add_tail(&dst->list, &stats->bcn); + } + +- kfree(tb); + return 0; + } + ++static int ath11k_wmi_tlv_fw_stats_parse(struct ath11k_base *ab, ++ u16 tag, u16 len, ++ const void *ptr, void *data) ++{ ++ struct wmi_tlv_fw_stats_parse *parse = data; ++ int ret = 0; ++ ++ switch (tag) { ++ case WMI_TAG_STATS_EVENT: ++ parse->ev = (struct wmi_stats_event *)ptr; ++ parse->stats->pdev_id = parse->ev->pdev_id; ++ break; ++ case WMI_TAG_ARRAY_BYTE: ++ ret = ath11k_wmi_tlv_fw_stats_data_parse(ab, parse, ptr, len); ++ break; ++ case WMI_TAG_PER_CHAIN_RSSI_STATS: ++ parse->rssi = (struct wmi_per_chain_rssi_stats *)ptr; ++ ++ if (parse->ev->stats_id & WMI_REQUEST_RSSI_PER_CHAIN_STAT) ++ parse->rssi_num = parse->rssi->num_per_chain_rssi_stats; ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats id 0x%x num chain %d\n", ++ parse->ev->stats_id, ++ parse->rssi_num); ++ break; ++ case WMI_TAG_ARRAY_STRUCT: ++ if (parse->rssi_num && !parse->chain_rssi_done) { ++ ret = ath11k_wmi_tlv_iter(ab, ptr, len, ++ ath11k_wmi_tlv_rssi_chain_parse, ++ parse); ++ if (ret) { ++ ath11k_warn(ab, "failed to parse rssi chain %d\n", ++ ret); ++ return ret; ++ } ++ parse->chain_rssi_done = true; ++ } ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, ++ struct ath11k_fw_stats *stats) ++{ ++ struct wmi_tlv_fw_stats_parse parse = { }; ++ ++ stats->stats_id = 0; ++ parse.stats = stats; ++ ++ return ath11k_wmi_tlv_iter(ab, skb->data, skb->len, ++ ath11k_wmi_tlv_fw_stats_parse, ++ &parse); ++} ++ + size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head) + { + struct ath11k_fw_stats_vdev *i; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4439,6 +4439,17 @@ struct wmi_stats_event { + u32 num_peer_extd2_stats; + } __packed; + ++struct wmi_rssi_stats { ++ u32 vdev_id; ++ u32 rssi_avg_beacon[WMI_MAX_CHAINS]; ++ u32 rssi_avg_data[WMI_MAX_CHAINS]; ++ struct wmi_mac_addr peer_macaddr; ++} __packed; ++ ++struct wmi_per_chain_rssi_stats { ++ u32 num_per_chain_rssi_stats; ++} __packed; ++ + struct wmi_pdev_ctl_failsafe_chk_event { + u32 pdev_id; + u32 ctl_failsafe_status; diff --git a/package/kernel/mac80211/patches/ath11k/0145-ath11k-add-signal-report-to-mac80211-for-QCA6390-and.patch b/package/kernel/mac80211/patches/ath11k/0145-ath11k-add-signal-report-to-mac80211-for-QCA6390-and.patch new file mode 100644 index 000000000..f06c7313f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0145-ath11k-add-signal-report-to-mac80211-for-QCA6390-and.patch @@ -0,0 +1,170 @@ +From c3b39553fc7712a9621a19d9670d6f250943d50e Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Fri, 17 Dec 2021 20:27:21 +0200 +Subject: [PATCH] ath11k: add signal report to mac80211 for QCA6390 and WCN6855 + +IEEE80211_HW_USES_RSS is set in ath11k, then the device uses RSS and +thus requires parallel RX which implies using per-CPU station statistics +in sta_get_last_rx_stats() of mac80211. Currently signal is only set in +ath11k_mgmt_rx_event(), and not set for RX data packet, then it show +signal as 0 for iw command easily. + +Change to get signal from firmware and report to mac80211. + +For QCA6390 and WCN6855, the rssi value is already in dbm unit, so +don't need to convert it again. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211216070535.31732-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 22 ++++++++++-- + drivers/net/wireless/ath/ath11k/wmi.c | 49 +++++++++++++++++++++----- + 3 files changed, 61 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -387,6 +387,7 @@ struct ath11k_sta { + u64 rx_duration; + u64 tx_duration; + u8 rssi_comb; ++ s8 rssi_beacon; + s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct ath11k_htt_tx_stats *tx_stats; + struct ath11k_rx_peer_stats *rx_stats; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7811,6 +7811,9 @@ static void ath11k_mac_op_sta_statistics + { + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; + struct ath11k *ar = arsta->arvif->ar; ++ s8 signal; ++ bool db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, ++ ar->ab->wmi_ab.svc_map); + + sinfo->rx_duration = arsta->rx_duration; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); +@@ -7843,9 +7846,22 @@ static void ath11k_mac_op_sta_statistics + ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true); + } + +- /* TODO: Use real NF instead of default one. */ +- sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; +- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); ++ signal = arsta->rssi_comb; ++ if (!signal && ++ arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && ++ ar->ab->hw_params.supports_rssi_stats && ++ !(ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, ++ WMI_REQUEST_VDEV_STAT))) ++ signal = arsta->rssi_beacon; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac sta statistics db2dbm %u rssi comb %d rssi beacon %d\n", ++ db2dbm, arsta->rssi_comb, arsta->rssi_beacon); ++ ++ if (signal) { ++ sinfo->signal = db2dbm ? signal : signal + ATH11K_DEFAULT_NOISE_FLOOR; ++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); ++ } + } + + static const struct ieee80211_ops ath11k_ops = { +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -5639,7 +5639,11 @@ static int ath11k_wmi_tlv_fw_stats_data_ + { + struct ath11k_fw_stats *stats = parse->stats; + const struct wmi_stats_event *ev = parse->ev; +- int i; ++ struct ath11k *ar; ++ struct ath11k_vif *arvif; ++ struct ieee80211_sta *sta; ++ struct ath11k_sta *arsta; ++ int i, ret = 0; + const void *data = ptr; + + if (!ev) { +@@ -5649,13 +5653,19 @@ static int ath11k_wmi_tlv_fw_stats_data_ + + stats->stats_id = 0; + ++ rcu_read_lock(); ++ ++ ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id); ++ + for (i = 0; i < ev->num_pdev_stats; i++) { + const struct wmi_pdev_stats *src; + struct ath11k_fw_stats_pdev *dst; + + src = data; +- if (len < sizeof(*src)) +- return -EPROTO; ++ if (len < sizeof(*src)) { ++ ret = -EPROTO; ++ goto exit; ++ } + + stats->stats_id = WMI_REQUEST_PDEV_STAT; + +@@ -5677,11 +5687,30 @@ static int ath11k_wmi_tlv_fw_stats_data_ + struct ath11k_fw_stats_vdev *dst; + + src = data; +- if (len < sizeof(*src)) +- return -EPROTO; ++ if (len < sizeof(*src)) { ++ ret = -EPROTO; ++ goto exit; ++ } + + stats->stats_id = WMI_REQUEST_VDEV_STAT; + ++ arvif = ath11k_mac_get_arvif(ar, src->vdev_id); ++ if (arvif) { ++ sta = ieee80211_find_sta_by_ifaddr(ar->hw, ++ arvif->bssid, ++ NULL); ++ if (sta) { ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ arsta->rssi_beacon = src->beacon_snr; ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats vdev id %d snr %d\n", ++ src->vdev_id, src->beacon_snr); ++ } else { ++ ath11k_warn(ab, "not found station for bssid %pM\n", ++ arvif->bssid); ++ } ++ } ++ + data += sizeof(*src); + len -= sizeof(*src); + +@@ -5698,8 +5727,10 @@ static int ath11k_wmi_tlv_fw_stats_data_ + struct ath11k_fw_stats_bcn *dst; + + src = data; +- if (len < sizeof(*src)) +- return -EPROTO; ++ if (len < sizeof(*src)) { ++ ret = -EPROTO; ++ goto exit; ++ } + + stats->stats_id = WMI_REQUEST_BCN_STAT; + +@@ -5714,7 +5745,9 @@ static int ath11k_wmi_tlv_fw_stats_data_ + list_add_tail(&dst->list, &stats->bcn); + } + +- return 0; ++exit: ++ rcu_read_unlock(); ++ return ret; + } + + static int ath11k_wmi_tlv_fw_stats_parse(struct ath11k_base *ab, diff --git a/package/kernel/mac80211/patches/ath11k/0146-ath11k-fix-warning-of-RCU-usage-for-ath11k_mac_get_a.patch b/package/kernel/mac80211/patches/ath11k/0146-ath11k-fix-warning-of-RCU-usage-for-ath11k_mac_get_a.patch new file mode 100644 index 000000000..3e94f2fa7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0146-ath11k-fix-warning-of-RCU-usage-for-ath11k_mac_get_a.patch @@ -0,0 +1,124 @@ +From 01e782c891083f1847c0b62902bfe3c2812566c6 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Fri, 17 Dec 2021 20:27:21 +0200 +Subject: [PATCH] ath11k: fix warning of RCU usage for + ath11k_mac_get_arvif_by_vdev_id() + +When enable more debug config, it happen below warning. It is because +the caller does not add rcu_read_lock()/rcu_read_unlock() to wrap the +rcu_dereference(). + +Add rcu_read_lock()/rcu_read_unlock() to wrap rcu_dereference(), then +fixed it. + +[ 180.716604] ============================= +[ 180.716670] WARNING: suspicious RCU usage +[ 180.716734] 5.16.0-rc4-wt-ath+ #542 Not tainted +[ 180.716895] ----------------------------- +[ 180.716957] drivers/net/wireless/ath/ath11k/mac.c:506 suspicious rcu_dereference_check() usage! +[ 180.717023] + other info that might help us debug this: + +[ 180.717087] + rcu_scheduler_active = 2, debug_locks = 1 +[ 180.717151] no locks held by swapper/0/0. +[ 180.717215] + stack backtrace: +[ 180.717279] CPU: 0 PID: 0 Comm: swapper/0 Kdump: loaded Not tainted 5.16.0-rc4-wt-ath+ #542 +[ 180.717346] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 180.717411] Call Trace: +[ 180.717475] +[ 180.717541] dump_stack_lvl+0x57/0x7d +[ 180.717610] ath11k_mac_get_arvif_by_vdev_id+0x1ab/0x2d0 [ath11k] +[ 180.717694] ? ath11k_mac_get_arvif+0x140/0x140 [ath11k] +[ 180.717798] ? ath11k_wmi_tlv_op_rx+0xc1b/0x2520 [ath11k] +[ 180.717888] ? kfree+0xe8/0x2c0 +[ 180.717959] ath11k_wmi_tlv_op_rx+0xc27/0x2520 [ath11k] +[ 180.718038] ? ath11k_mgmt_rx_event+0xda0/0xda0 [ath11k] +[ 180.718113] ? __lock_acquire+0xb72/0x1870 +[ 180.718182] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 180.718250] ? sched_clock_cpu+0x15/0x1b0 +[ 180.718314] ? find_held_lock+0x33/0x110 +[ 180.718381] ? __lock_release+0x4bd/0x9f0 +[ 180.718447] ? lock_downgrade+0x130/0x130 +[ 180.718517] ath11k_htc_rx_completion_handler+0x38f/0x5b0 [ath11k] +[ 180.718596] ? __local_bh_enable_ip+0xa0/0x110 +[ 180.718662] ath11k_ce_recv_process_cb+0x5ac/0x920 [ath11k] +[ 180.718783] ? __lock_acquired+0x205/0x890 +[ 180.718864] ? ath11k_ce_rx_post_pipe+0x970/0x970 [ath11k] +[ 180.718949] ? __wake_up_bit+0x100/0x100 +[ 180.719020] ath11k_pci_ce_tasklet+0x5f/0xf0 [ath11k_pci] +[ 180.719085] ? tasklet_clear_sched+0x42/0xe0 +[ 180.719148] tasklet_action_common.constprop.0+0x204/0x2f0 +[ 180.719217] __do_softirq+0x276/0x86a +[ 180.719281] ? __common_interrupt+0x92/0x1d0 +[ 180.719350] __irq_exit_rcu+0x11c/0x180 +[ 180.719418] irq_exit_rcu+0x5/0x20 +[ 180.719482] common_interrupt+0xa4/0xc0 +[ 180.719547] +[ 180.719609] +[ 180.719671] asm_common_interrupt+0x1e/0x40 +[ 180.719772] RIP: 0010:cpuidle_enter_state+0x1f3/0x8d0 +[ 180.719838] Code: 00 41 8b 77 04 bf ff ff ff ff e8 78 f1 ff ff 31 ff e8 81 fa 52 fe 80 7c 24 08 00 0f 85 9e 01 00 00 e8 11 13 78 fe fb 45 85 e4 <0f> 88 8c 02 00 00 49 63 ec 48 8d 44 6d 00 48 8d 44 85 00 48 8d 7c +[ 180.719909] RSP: 0018:ffffffffa4607dd0 EFLAGS: 00000202 +[ 180.719982] RAX: 00000000002aea91 RBX: ffffffffa4a5fec0 RCX: 1ffffffff49ca501 +[ 180.720047] RDX: 0000000000000000 RSI: ffffffffa3c6e4e0 RDI: ffffffffa3dcf2a0 +[ 180.720110] RBP: 0000000000000002 R08: 0000000000000001 R09: ffffffffa4e54d17 +[ 180.720173] R10: fffffbfff49ca9a2 R11: 0000000000000001 R12: 0000000000000002 +[ 180.720236] R13: ffff8881169ccc04 R14: 0000002a13899598 R15: ffff8881169ccc00 +[ 180.720321] cpuidle_enter+0x45/0xa0 +[ 180.720413] cpuidle_idle_call+0x274/0x3f0 +[ 180.720503] ? arch_cpu_idle_exit+0x30/0x30 +[ 180.720869] ? tsc_verify_tsc_adjust+0x97/0x2e0 +[ 180.720935] ? lockdep_hardirqs_off+0x90/0xd0 +[ 180.721002] do_idle+0xe0/0x150 +[ 180.721069] cpu_startup_entry+0x14/0x20 +[ 180.721134] start_kernel+0x3a2/0x3c2 +[ 180.721200] secondary_startup_64_no_verify+0xb0/0xbb +[ 180.721274] + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02892.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211217064132.30911-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -3605,6 +3605,8 @@ ath11k_wmi_obss_color_collision_event(st + return; + } + ++ rcu_read_lock(); ++ + ev = tb[WMI_TAG_OBSS_COLOR_COLLISION_EVT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch obss color collision ev"); +@@ -3635,6 +3637,7 @@ ath11k_wmi_obss_color_collision_event(st + + exit: + kfree(tb); ++ rcu_read_unlock(); + } + + static void +@@ -6541,13 +6544,16 @@ static void ath11k_bcn_tx_status_event(s + return; + } + ++ rcu_read_lock(); + arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_id); + if (!arvif) { + ath11k_warn(ab, "invalid vdev id %d in bcn_tx_status", + vdev_id); ++ rcu_read_unlock(); + return; + } + ath11k_mac_bcn_tx_event(arvif); ++ rcu_read_unlock(); + } + + static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb) diff --git a/package/kernel/mac80211/patches/ath11k/0147-ath11k-report-tx-bitrate-for-iw-wlan-station-dump.patch b/package/kernel/mac80211/patches/ath11k/0147-ath11k-report-tx-bitrate-for-iw-wlan-station-dump.patch new file mode 100644 index 000000000..0b396428b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0147-ath11k-report-tx-bitrate-for-iw-wlan-station-dump.patch @@ -0,0 +1,533 @@ +From 1b8bb94c0612cf32e418e90ae93cf37214d84669 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 20 Dec 2021 18:11:09 +0200 +Subject: [PATCH] ath11k: report tx bitrate for iw wlan station dump + +HTT_T2H_MSG_TYPE_PPDU_STATS_IND is a message which include the ppdu +info, currently it is not report from firmware for ath11k, then the +tx bitrate of "iw wlan0 station dump" always show an invalid value +"tx bitrate: 6.0 MBit/s". + +To address the issue, this is to parse the info of tx complete report +from firmware and indicate the tx rate to mac80211. + +After that, "iw wlan0 station dump" show the correct tx bit rate such +as: +tx bitrate: 78.0 MBit/s MCS 12 +tx bitrate: 144.4 MBit/s VHT-MCS 7 short GI VHT-NSS 2 +tx bitrate: 286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0 +tx bitrate: 1921.5 MBit/s 160MHz HE-MCS 9 HE-NSS 2 HE-GI 0 HE-DCM 0 + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211217093722.5739-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/debugfs_sta.c | 78 +------------ + drivers/net/wireless/ath/ath11k/debugfs_sta.h | 2 - + drivers/net/wireless/ath/ath11k/dp_rx.c | 28 +---- + drivers/net/wireless/ath/ath11k/dp_tx.c | 106 +++++++++++++++++- + drivers/net/wireless/ath/ath11k/dp_tx.h | 1 + + drivers/net/wireless/ath/ath11k/hal_rx.c | 4 +- + drivers/net/wireless/ath/ath11k/hal_rx.h | 27 ----- + drivers/net/wireless/ath/ath11k/mac.c | 93 +++++++++++++++ + drivers/net/wireless/ath/ath11k/mac.h | 3 + + 10 files changed, 210 insertions(+), 133 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -383,6 +383,7 @@ struct ath11k_sta { + struct work_struct update_wk; + struct work_struct set_4addr_wk; + struct rate_info txrate; ++ u32 peer_nss; + struct rate_info last_txrate; + u64 rx_duration; + u64 tx_duration; +--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c +@@ -126,85 +126,9 @@ void ath11k_debugfs_sta_add_tx_stats(str + } + + void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, +- struct sk_buff *msdu, + struct hal_tx_status *ts) + { +- struct ath11k_base *ab = ar->ab; +- struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; +- enum hal_tx_rate_stats_pkt_type pkt_type; +- enum hal_tx_rate_stats_sgi sgi; +- enum hal_tx_rate_stats_bw bw; +- struct ath11k_peer *peer; +- struct ath11k_sta *arsta; +- struct ieee80211_sta *sta; +- u16 rate; +- u8 rate_idx = 0; +- int ret; +- u8 mcs; +- +- rcu_read_lock(); +- spin_lock_bh(&ab->base_lock); +- peer = ath11k_peer_find_by_id(ab, ts->peer_id); +- if (!peer || !peer->sta) { +- ath11k_warn(ab, "failed to find the peer\n"); +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); +- return; +- } +- +- sta = peer->sta; +- arsta = (struct ath11k_sta *)sta->drv_priv; +- +- memset(&arsta->txrate, 0, sizeof(arsta->txrate)); +- pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, +- ts->rate_stats); +- mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, +- ts->rate_stats); +- sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, +- ts->rate_stats); +- bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); +- +- if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || +- pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { +- ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, +- pkt_type, +- &rate_idx, +- &rate); +- if (ret < 0) +- goto err_out; +- arsta->txrate.legacy = rate; +- } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { +- if (mcs > 7) { +- ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs); +- goto err_out; +- } +- +- arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1); +- arsta->txrate.flags = RATE_INFO_FLAGS_MCS; +- if (sgi) +- arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; +- } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { +- if (mcs > 9) { +- ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs); +- goto err_out; +- } +- +- arsta->txrate.mcs = mcs; +- arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; +- if (sgi) +- arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; +- } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { +- /* TODO */ +- } +- +- arsta->txrate.nss = arsta->last_txrate.nss; +- arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); +- +- ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); +- +-err_out: +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); ++ ath11k_dp_tx_update_txcompl(ar, ts); + } + + static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file, +--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.h +@@ -19,7 +19,6 @@ void ath11k_debugfs_sta_add_tx_stats(str + struct ath11k_per_peer_tx_stats *peer_stats, + u8 legacy_rate_idx); + void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, +- struct sk_buff *msdu, + struct hal_tx_status *ts); + + #else /* CPTCFG_ATH11K_DEBUGFS */ +@@ -34,7 +33,6 @@ ath11k_debugfs_sta_add_tx_stats(struct a + } + + static inline void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, +- struct sk_buff *msdu, + struct hal_tx_status *ts) + { + } +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -1360,25 +1360,6 @@ int ath11k_dp_htt_tlv_iter(struct ath11k + return 0; + } + +-static inline u32 ath11k_he_gi_to_nl80211_he_gi(u8 sgi) +-{ +- u32 ret = 0; +- +- switch (sgi) { +- case RX_MSDU_START_SGI_0_8_US: +- ret = NL80211_RATE_INFO_HE_GI_0_8; +- break; +- case RX_MSDU_START_SGI_1_6_US: +- ret = NL80211_RATE_INFO_HE_GI_1_6; +- break; +- case RX_MSDU_START_SGI_3_2_US: +- ret = NL80211_RATE_INFO_HE_GI_3_2; +- break; +- } +- +- return ret; +-} +- + static void + ath11k_update_per_peer_tx_stats(struct ath11k *ar, + struct htt_ppdu_stats *ppdu_stats, u8 user) +@@ -1497,14 +1478,15 @@ ath11k_update_per_peer_tx_stats(struct a + arsta->txrate.mcs = mcs; + arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; + arsta->txrate.he_dcm = dcm; +- arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); +- arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc( +- (user_rate->ru_end - ++ arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); ++ arsta->txrate.he_ru_alloc = ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc ++ ((user_rate->ru_end - + user_rate->ru_start) + 1); + break; + } + + arsta->txrate.nss = nss; ++ + arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); + arsta->tx_duration += tx_duration; + memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); +@@ -2384,7 +2366,7 @@ static void ath11k_dp_rx_h_rate(struct a + } + rx_status->encoding = RX_ENC_HE; + rx_status->nss = nss; +- rx_status->he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); ++ rx_status->he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); + rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); + break; + } +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -415,6 +415,105 @@ static void ath11k_dp_tx_cache_peer_stat + } + } + ++void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts) ++{ ++ struct ath11k_base *ab = ar->ab; ++ struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; ++ enum hal_tx_rate_stats_pkt_type pkt_type; ++ enum hal_tx_rate_stats_sgi sgi; ++ enum hal_tx_rate_stats_bw bw; ++ struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; ++ struct ieee80211_sta *sta; ++ u16 rate, ru_tones; ++ u8 mcs, rate_idx, ofdma; ++ int ret; ++ ++ spin_lock_bh(&ab->base_lock); ++ peer = ath11k_peer_find_by_id(ab, ts->peer_id); ++ if (!peer || !peer->sta) { ++ ath11k_dbg(ab, ATH11K_DBG_DP_TX, ++ "failed to find the peer by id %u\n", ts->peer_id); ++ goto err_out; ++ } ++ ++ sta = peer->sta; ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ ++ memset(&arsta->txrate, 0, sizeof(arsta->txrate)); ++ pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, ++ ts->rate_stats); ++ mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, ++ ts->rate_stats); ++ sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, ++ ts->rate_stats); ++ bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); ++ ru_tones = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU, ts->rate_stats); ++ ofdma = FIELD_GET(HAL_TX_RATE_STATS_INFO0_OFDMA_TX, ts->rate_stats); ++ ++ /* This is to prefer choose the real NSS value arsta->last_txrate.nss, ++ * if it is invalid, then choose the NSS value while assoc. ++ */ ++ if (arsta->last_txrate.nss) ++ arsta->txrate.nss = arsta->last_txrate.nss; ++ else ++ arsta->txrate.nss = arsta->peer_nss; ++ ++ if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || ++ pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { ++ ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, ++ pkt_type, ++ &rate_idx, ++ &rate); ++ if (ret < 0) ++ goto err_out; ++ arsta->txrate.legacy = rate; ++ } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { ++ if (mcs > 7) { ++ ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs); ++ goto err_out; ++ } ++ ++ if (arsta->txrate.nss != 0) ++ arsta->txrate.mcs = mcs + 8 * (arsta->txrate.nss - 1); ++ arsta->txrate.flags = RATE_INFO_FLAGS_MCS; ++ if (sgi) ++ arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; ++ } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { ++ if (mcs > 9) { ++ ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs); ++ goto err_out; ++ } ++ ++ arsta->txrate.mcs = mcs; ++ arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; ++ if (sgi) ++ arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; ++ } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { ++ if (mcs > 11) { ++ ath11k_warn(ab, "Invalid HE mcs index %d\n", mcs); ++ goto err_out; ++ } ++ ++ arsta->txrate.mcs = mcs; ++ arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; ++ arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); ++ } ++ ++ arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); ++ if (ofdma && pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { ++ arsta->txrate.bw = RATE_INFO_BW_HE_RU; ++ arsta->txrate.he_ru_alloc = ++ ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones); ++ } ++ ++ if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) ++ ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); ++ ++err_out: ++ spin_unlock_bh(&ab->base_lock); ++} ++ + static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, + struct sk_buff *msdu, + struct hal_tx_status *ts) +@@ -460,7 +559,8 @@ static void ath11k_dp_tx_complete_msdu(s + (info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + +- if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) { ++ if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar)) || ++ ab->hw_params.single_pdev_only) { + if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) { + if (ar->last_ppdu_id == 0) { + ar->last_ppdu_id = ts->ppdu_id; +@@ -468,12 +568,12 @@ static void ath11k_dp_tx_complete_msdu(s + ar->cached_ppdu_id == ar->last_ppdu_id) { + ar->cached_ppdu_id = ar->last_ppdu_id; + ar->cached_stats.is_ampdu = true; +- ath11k_debugfs_sta_update_txcompl(ar, msdu, ts); ++ ath11k_dp_tx_update_txcompl(ar, ts); + memset(&ar->cached_stats, 0, + sizeof(struct ath11k_per_peer_tx_stats)); + } else { + ar->cached_stats.is_ampdu = false; +- ath11k_debugfs_sta_update_txcompl(ar, msdu, ts); ++ ath11k_dp_tx_update_txcompl(ar, ts); + memset(&ar->cached_stats, 0, + sizeof(struct ath11k_per_peer_tx_stats)); + } +--- a/drivers/net/wireless/ath/ath11k/dp_tx.h ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.h +@@ -15,6 +15,7 @@ struct ath11k_dp_htt_wbm_tx_status { + int ack_rssi; + }; + ++void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts); + int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab); + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, + struct ath11k_sta *arsta, struct sk_buff *skb); +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -1039,7 +1039,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + + ru_tones = FIELD_GET(HAL_RX_HE_SIG_B1_MU_INFO_INFO0_RU_ALLOCATION, + info0); +- ppdu_info->ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones); ++ ppdu_info->ru_alloc = ++ ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(ru_tones); ++ + ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; + break; + } +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -363,33 +363,6 @@ ath11k_hal_rx_parse_mon_status(struct at + struct hal_rx_mon_ppdu_info *ppdu_info, + struct sk_buff *skb); + +-static inline u32 ath11k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones) +-{ +- u32 ret = 0; +- +- switch (ru_tones) { +- case RU_26: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; +- break; +- case RU_52: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; +- break; +- case RU_106: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; +- break; +- case RU_242: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; +- break; +- case RU_484: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; +- break; +- case RU_996: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; +- break; +- } +- return ret; +-} +- + #define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0 0xDDBEEF + #define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1 0xADBEEF + #define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2 0xBDBEEF +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -246,6 +246,93 @@ static const u32 ath11k_smps_map[] = { + static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + ++enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy) ++{ ++ enum nl80211_he_ru_alloc ret; ++ ++ switch (ru_phy) { ++ case RU_26: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ case RU_52: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; ++ break; ++ case RU_106: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; ++ break; ++ case RU_242: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; ++ break; ++ case RU_484: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; ++ break; ++ case RU_996: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; ++ break; ++ default: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ } ++ ++ return ret; ++} ++ ++enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones) ++{ ++ enum nl80211_he_ru_alloc ret; ++ ++ switch (ru_tones) { ++ case 26: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ case 52: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; ++ break; ++ case 106: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; ++ break; ++ case 242: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; ++ break; ++ case 484: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; ++ break; ++ case 996: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; ++ break; ++ case (996 * 2): ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; ++ break; ++ default: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ } ++ ++ return ret; ++} ++ ++enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi) ++{ ++ enum nl80211_he_gi ret; ++ ++ switch (sgi) { ++ case RX_MSDU_START_SGI_0_8_US: ++ ret = NL80211_RATE_INFO_HE_GI_0_8; ++ break; ++ case RX_MSDU_START_SGI_1_6_US: ++ ret = NL80211_RATE_INFO_HE_GI_1_6; ++ break; ++ case RX_MSDU_START_SGI_3_2_US: ++ ret = NL80211_RATE_INFO_HE_GI_3_2; ++ break; ++ default: ++ ret = NL80211_RATE_INFO_HE_GI_0_8; ++ break; ++ } ++ ++ return ret; ++} ++ + u8 ath11k_mac_bw_to_mac80211_bw(u8 bw) + { + u8 ret = 0; +@@ -2541,8 +2628,12 @@ static void ath11k_peer_assoc_prepare(st + struct peer_assoc_params *arg, + bool reassoc) + { ++ struct ath11k_sta *arsta; ++ + lockdep_assert_held(&ar->conf_mutex); + ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ + memset(arg, 0, sizeof(*arg)); + + reinit_completion(&ar->peer_assoc_done); +@@ -2559,6 +2650,8 @@ static void ath11k_peer_assoc_prepare(st + ath11k_peer_assoc_h_qos(ar, vif, sta, arg); + ath11k_peer_assoc_h_smps(sta, arg); + ++ arsta->peer_nss = arg->peer_nss; ++ + /* TODO: amsdu_disable req? */ + } + +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -162,6 +162,9 @@ void ath11k_mac_drain_tx(struct ath11k * + void ath11k_mac_peer_cleanup_all(struct ath11k *ar); + int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx); + u8 ath11k_mac_bw_to_mac80211_bw(u8 bw); ++u32 ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi); ++enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy); ++enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones); + enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw); + enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher); + void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); diff --git a/package/kernel/mac80211/patches/ath11k/0148-ath11k-add-support-for-hardware-rfkill-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0148-ath11k-add-support-for-hardware-rfkill-for-QCA6390.patch new file mode 100644 index 000000000..ceb4c6638 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0148-ath11k-add-support-for-hardware-rfkill-for-QCA6390.patch @@ -0,0 +1,395 @@ +From ec038c6127fa772d2c5604e329f22371830d5fa6 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 20 Dec 2021 18:11:09 +0200 +Subject: [PATCH] ath11k: add support for hardware rfkill for QCA6390 + +When hardware rfkill is enabled in the firmware it will report the +capability via using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY +event to the host. ath11k will check the capability, and if it is enabled then +ath11k will set the GPIO information to firmware using WMI_PDEV_SET_PARAM. When +the firmware detects hardware rfkill is enabled by the user, it will report it +via WMI_RFKILL_STATE_CHANGE_EVENTID. Once ath11k receives the event it will +send wmi command WMI_PDEV_SET_PARAM to the firmware and also notifies cfg80211. + +This only enable rfkill feature for QCA6390, rfkill_pin is all initialized to 0 +for other chips in ath11k_hw_params. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211217102334.14907-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 70 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 4 ++ + drivers/net/wireless/ath/ath11k/hw.h | 3 ++ + drivers/net/wireless/ath/ath11k/mac.c | 58 +++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/mac.h | 2 + + drivers/net/wireless/ath/ath11k/wmi.c | 41 +++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 25 +++++++++ + 7 files changed, 203 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -52,6 +52,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 11, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074, + .svc_to_ce_map_len = 21, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = false, + .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, +@@ -114,6 +117,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 11, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018, + .svc_to_ce_map_len = 19, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = false, + .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, +@@ -173,6 +179,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, ++ .rfkill_pin = 48, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 1, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, +@@ -231,6 +240,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qcn9074, + .svc_to_ce_map_len = 18, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, + .rx_mac_buf_ring = false, +@@ -289,6 +301,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, +@@ -347,6 +362,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, +@@ -1015,6 +1033,27 @@ err_firmware_stop: + return ret; + } + ++static int ath11k_core_rfkill_config(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ int ret = 0, i; ++ ++ if (!(ab->target_caps.sys_cap_info & WMI_SYS_CAP_INFO_RFKILL)) ++ return 0; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ ar = ab->pdevs[i].ar; ++ ++ ret = ath11k_mac_rfkill_config(ar); ++ if (ret && ret != -EOPNOTSUPP) { ++ ath11k_warn(ab, "failed to configure rfkill: %d", ret); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ + int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab) + { + int ret; +@@ -1061,6 +1100,13 @@ int ath11k_core_qmi_firmware_ready(struc + goto err_core_stop; + } + ath11k_hif_irq_enable(ab); ++ ++ ret = ath11k_core_rfkill_config(ab); ++ if (ret && ret != -EOPNOTSUPP) { ++ ath11k_err(ab, "failed to config rfkill: %d\n", ret); ++ goto err_core_stop; ++ } ++ + mutex_unlock(&ab->core_lock); + + return 0; +@@ -1126,6 +1172,7 @@ void ath11k_core_halt(struct ath11k *ar) + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ab->update_11d_work); ++ cancel_work_sync(&ab->rfkill_work); + + rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); + synchronize_rcu(); +@@ -1133,6 +1180,28 @@ void ath11k_core_halt(struct ath11k *ar) + idr_init(&ar->txmgmt_idr); + } + ++static void ath11k_rfkill_work(struct work_struct *work) ++{ ++ struct ath11k_base *ab = container_of(work, struct ath11k_base, rfkill_work); ++ struct ath11k *ar; ++ bool rfkill_radio_on; ++ int i; ++ ++ spin_lock_bh(&ab->base_lock); ++ rfkill_radio_on = ab->rfkill_radio_on; ++ spin_unlock_bh(&ab->base_lock); ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ ar = ab->pdevs[i].ar; ++ if (!ar) ++ continue; ++ ++ /* notify cfg80211 radio state change */ ++ ath11k_mac_rfkill_enable_radio(ar, rfkill_radio_on); ++ wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on); ++ } ++} ++ + static void ath11k_update_11d(struct work_struct *work) + { + struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); +@@ -1339,6 +1408,7 @@ struct ath11k_base *ath11k_core_alloc(st + init_waitqueue_head(&ab->qmi.cold_boot_waitq); + INIT_WORK(&ab->restart_work, ath11k_core_restart); + INIT_WORK(&ab->update_11d_work, ath11k_update_11d); ++ INIT_WORK(&ab->rfkill_work, ath11k_rfkill_work); + timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); + init_completion(&ab->htc_suspend); + init_completion(&ab->wow.wakeup_completed); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -786,6 +786,10 @@ struct ath11k_base { + + struct ath11k_dbring_cap *db_caps; + u32 num_db_cap; ++ struct work_struct rfkill_work; ++ ++ /* true means radio is on */ ++ bool rfkill_radio_on; + + /* To synchronize 11d scan vdev id */ + struct mutex vdev_id_11d_lock; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -151,6 +151,9 @@ struct ath11k_hw_params { + u32 svc_to_ce_map_len; + + bool single_pdev_only; ++ u32 rfkill_pin; ++ u32 rfkill_cfg; ++ u32 rfkill_on_level; + + bool rxdma1_enable; + int num_rxmda_per_pdev; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5571,6 +5571,63 @@ static int ath11k_mac_mgmt_tx(struct ath + return 0; + } + ++int ath11k_mac_rfkill_config(struct ath11k *ar) ++{ ++ struct ath11k_base *ab = ar->ab; ++ u32 param; ++ int ret; ++ ++ if (ab->hw_params.rfkill_pin == 0) ++ return -EOPNOTSUPP; ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", ++ ab->hw_params.rfkill_pin, ab->hw_params.rfkill_cfg, ++ ab->hw_params.rfkill_on_level); ++ ++ param = FIELD_PREP(WMI_RFKILL_CFG_RADIO_LEVEL, ++ ab->hw_params.rfkill_on_level) | ++ FIELD_PREP(WMI_RFKILL_CFG_GPIO_PIN_NUM, ++ ab->hw_params.rfkill_pin) | ++ FIELD_PREP(WMI_RFKILL_CFG_PIN_AS_GPIO, ++ ab->hw_params.rfkill_cfg); ++ ++ ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG, ++ param, ar->pdev->pdev_id); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to set rfkill config 0x%x: %d\n", ++ param, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable) ++{ ++ enum wmi_rfkill_enable_radio param; ++ int ret; ++ ++ if (enable) ++ param = WMI_RFKILL_ENABLE_RADIO_ON; ++ else ++ param = WMI_RFKILL_ENABLE_RADIO_OFF; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac %d rfkill enable %d", ++ ar->pdev_idx, param); ++ ++ ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE, ++ param, ar->pdev->pdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n", ++ param, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ + static void ath11k_mac_op_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +@@ -5803,6 +5860,7 @@ static void ath11k_mac_op_stop(struct ie + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ar->ab->update_11d_work); ++ cancel_work_sync(&ar->ab->rfkill_work); + + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -147,6 +147,8 @@ u8 ath11k_mac_hw_rate_to_idx(const struc + + void __ath11k_mac_scan_finish(struct ath11k *ar); + void ath11k_mac_scan_finish(struct ath11k *ar); ++int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable); ++int ath11k_mac_rfkill_config(struct ath11k *ar); + + struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id); + struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab, +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -128,6 +128,8 @@ static const struct wmi_tlv_policy wmi_t + = { .min_len = sizeof(struct wmi_peer_assoc_conf_event) }, + [WMI_TAG_STATS_EVENT] + = { .min_len = sizeof(struct wmi_stats_event) }, ++ [WMI_TAG_RFKILL_EVENT] = { ++ .min_len = sizeof(struct wmi_rfkill_state_change_ev) }, + [WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] + = { .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) }, + [WMI_TAG_HOST_SWFDA_EVENT] = { +@@ -524,6 +526,8 @@ static int ath11k_pull_service_ready_tlv + cap->default_dbs_hw_mode_index = ev->default_dbs_hw_mode_index; + cap->num_msdu_desc = ev->num_msdu_desc; + ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi sys cap info 0x%x\n", cap->sys_cap_info); ++ + return 0; + } + +@@ -7334,6 +7338,40 @@ exit: + kfree(tb); + } + ++static void ath11k_rfkill_state_change_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ const struct wmi_rfkill_state_change_ev *ev; ++ const void **tb; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_RFKILL_EVENT]; ++ if (!ev) { ++ kfree(tb); ++ return; ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "wmi tlv rfkill state change gpio %d type %d radio_state %d\n", ++ ev->gpio_pin_num, ++ ev->int_type, ++ ev->radio_state); ++ ++ spin_lock_bh(&ab->base_lock); ++ ab->rfkill_radio_on = (ev->radio_state == WMI_RFKILL_RADIO_STATE_ON); ++ spin_unlock_bh(&ab->base_lock); ++ ++ queue_work(ab->workqueue, &ab->rfkill_work); ++ kfree(tb); ++} ++ + static void + ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab, + struct sk_buff *skb) +@@ -7606,6 +7644,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_11D_NEW_COUNTRY_EVENTID: + ath11k_reg_11d_new_cc_event(ab, skb); + break; ++ case WMI_RFKILL_STATE_CHANGE_EVENTID: ++ ath11k_rfkill_state_change_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5215,6 +5215,31 @@ struct target_resource_config { + u32 twt_ap_sta_count; + }; + ++enum wmi_sys_cap_info_flags { ++ WMI_SYS_CAP_INFO_RXTX_LED = BIT(0), ++ WMI_SYS_CAP_INFO_RFKILL = BIT(1), ++}; ++ ++#define WMI_RFKILL_CFG_GPIO_PIN_NUM GENMASK(5, 0) ++#define WMI_RFKILL_CFG_RADIO_LEVEL BIT(6) ++#define WMI_RFKILL_CFG_PIN_AS_GPIO GENMASK(10, 7) ++ ++enum wmi_rfkill_enable_radio { ++ WMI_RFKILL_ENABLE_RADIO_ON = 0, ++ WMI_RFKILL_ENABLE_RADIO_OFF = 1, ++}; ++ ++enum wmi_rfkill_radio_state { ++ WMI_RFKILL_RADIO_STATE_OFF = 1, ++ WMI_RFKILL_RADIO_STATE_ON = 2, ++}; ++ ++struct wmi_rfkill_state_change_ev { ++ u32 gpio_pin_num; ++ u32 int_type; ++ u32 radio_state; ++} __packed; ++ + #define WMI_MAX_MEM_REQS 32 + + #define MAX_RADIOS 3 diff --git a/package/kernel/mac80211/patches/ath11k/0149-ath11k-add-regdb.bin-download-for-regdb-offload.patch b/package/kernel/mac80211/patches/ath11k/0149-ath11k-add-regdb.bin-download-for-regdb-offload.patch new file mode 100644 index 000000000..a53892aca --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0149-ath11k-add-regdb.bin-download-for-regdb-offload.patch @@ -0,0 +1,256 @@ +From 01417e57939faffebfdeb2aef1f4388e95cf9271 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 20 Dec 2021 01:23:55 -0500 +Subject: [PATCH] ath11k: add regdb.bin download for regdb offload + +The regdomain is self-managed type for ath11k, the regdomain info is +reported from firmware, it is not from wireless regdb. Firmware fetch +the regdomain info from board data file before. Currently most of the +regdomain info has moved to another file regdb.bin from board data +file for some chips such as QCA6390 and WCN6855, so the regdomain info +left in board data file is not enough to support the feature which need +more regdomain info. + +After download regdb.bin, firmware will fetch the regdomain info from +regdb.bin instead of board data file and report to ath11k. If it does +not have the file regdb.bin, it also can initialize wlan success and +firmware then fetch regdomain info from board data file. + +Add download the regdb.bin before download board data for some specific +chip which support supports_regdb in hardware parameters. + +download regdb.bin log: +[430082.334162] ath11k_pci 0000:05:00.0: chip_id 0x2 chip_family 0xb board_id 0x106 soc_id 0x400c0200 +[430082.334169] ath11k_pci 0000:05:00.0: fw_version 0x110c8b4c fw_build_timestamp 2021-10-25 07:41 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HSP.1.1-02892-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 +[430082.334414] ath11k_pci 0000:05:00.0: boot firmware request ath11k/WCN6855/hw2.0/regdb.bin size 24310 + +output of "iw reg get" +global +country US: DFS-FCC + (2402 - 2472 @ 40), (N/A, 30), (N/A) + (5170 - 5250 @ 80), (N/A, 23), (N/A), AUTO-BW + (5250 - 5330 @ 80), (N/A, 23), (0 ms), DFS, AUTO-BW + (5490 - 5730 @ 160), (N/A, 23), (0 ms), DFS + (5735 - 5835 @ 80), (N/A, 30), (N/A) + (57240 - 63720 @ 2160), (N/A, 40), (N/A) + +phy#0 (self-managed) +country US: DFS-FCC + (2402 - 2472 @ 40), (6, 30), (N/A) + (5170 - 5250 @ 80), (N/A, 24), (N/A), AUTO-BW + (5250 - 5330 @ 80), (N/A, 24), (0 ms), DFS, AUTO-BW + (5490 - 5730 @ 160), (N/A, 24), (0 ms), DFS, AUTO-BW + (5735 - 5895 @ 160), (N/A, 30), (N/A), AUTO-BW + (5945 - 7125 @ 160), (N/A, 24), (N/A), NO-OUTDOOR, AUTO-BW + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211220062355.17021-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 28 ++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/core.h | 4 ++++ + drivers/net/wireless/ath/ath11k/hw.h | 2 ++ + drivers/net/wireless/ath/ath11k/qmi.c | 30 ++++++++++++++++++-------- + drivers/net/wireless/ath/ath11k/qmi.h | 1 + + 5 files changed, 52 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -87,6 +87,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, +@@ -149,6 +150,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, +@@ -210,6 +212,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), ++ .supports_regdb = true, + .fix_l1ss = true, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, +@@ -271,6 +274,7 @@ static const struct ath11k_hw_params ath + .num_peers = 128, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, +@@ -332,6 +336,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), ++ .supports_regdb = true, + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, +@@ -392,6 +397,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), ++ .supports_regdb = true, + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, +@@ -760,10 +766,12 @@ err: + return ret; + } + +-static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, +- struct ath11k_board_data *bd) ++int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, ++ struct ath11k_board_data *bd, ++ const char *name) + { +- bd->fw = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_BOARD_FILE); ++ bd->fw = ath11k_core_firmware_request(ab, name); ++ + if (IS_ERR(bd->fw)) + return PTR_ERR(bd->fw); + +@@ -791,7 +799,7 @@ int ath11k_core_fetch_bdf(struct ath11k_ + goto success; + + ab->bd_api = 1; +- ret = ath11k_core_fetch_board_data_api_1(ab, bd); ++ ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_DEFAULT_BOARD_FILE); + if (ret) { + ath11k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n", + ab->hw_params.fw.dir); +@@ -803,6 +811,18 @@ success: + return 0; + } + ++int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd) ++{ ++ int ret; ++ ++ ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_REGDB_FILE_NAME); ++ if (ret) ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to fetch %s from %s\n", ++ ATH11K_REGDB_FILE_NAME, ab->hw_params.fw.dir); ++ ++ return ret; ++} ++ + static void ath11k_core_stop(struct ath11k_base *ab) + { + if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -980,6 +980,10 @@ struct ath11k_base *ath11k_core_alloc(st + void ath11k_core_free(struct ath11k_base *ath11k); + int ath11k_core_fetch_bdf(struct ath11k_base *ath11k, + struct ath11k_board_data *bd); ++int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd); ++int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, ++ struct ath11k_board_data *bd, ++ const char *name); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -77,6 +77,7 @@ + #define ATH11K_DEFAULT_CAL_FILE "caldata.bin" + #define ATH11K_AMSS_FILE "amss.bin" + #define ATH11K_M3_FILE "m3.bin" ++#define ATH11K_REGDB_FILE_NAME "regdb.bin" + + enum ath11k_hw_rate_cck { + ATH11K_HW_RATE_CCK_LP_11M = 0, +@@ -181,6 +182,7 @@ struct ath11k_hw_params { + u32 num_peers; + bool supports_suspend; + u32 hal_desc_sz; ++ bool supports_regdb; + bool fix_l1ss; + bool credit_flow; + u8 max_tx_ring; +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2161,7 +2161,8 @@ err_free_req: + return ret; + } + +-static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) ++static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab, ++ bool regdb) + { + struct device *dev = ab->dev; + char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; +@@ -2172,13 +2173,21 @@ static int ath11k_qmi_load_bdf_qmi(struc + const u8 *tmp; + + memset(&bd, 0, sizeof(bd)); +- ret = ath11k_core_fetch_bdf(ab, &bd); +- if (ret) { +- ath11k_warn(ab, "qmi failed to fetch board file: %d\n", ret); +- goto out; ++ ++ if (regdb) { ++ ret = ath11k_core_fetch_regdb(ab, &bd); ++ } else { ++ ret = ath11k_core_fetch_bdf(ab, &bd); ++ if (ret) ++ ath11k_warn(ab, "qmi failed to fetch board file: %d\n", ret); + } + +- if (bd.len >= SELFMAG && memcmp(bd.data, ELFMAG, SELFMAG) == 0) ++ if (ret) ++ goto out; ++ ++ if (regdb) ++ bdf_type = ATH11K_QMI_BDF_TYPE_REGDB; ++ else if (bd.len >= SELFMAG && memcmp(bd.data, ELFMAG, SELFMAG) == 0) + bdf_type = ATH11K_QMI_BDF_TYPE_ELF; + else + bdf_type = ATH11K_QMI_BDF_TYPE_BIN; +@@ -2193,8 +2202,8 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + } + +- /* QCA6390 does not support cal data, skip it */ +- if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF) ++ /* QCA6390/WCN6855 does not support cal data, skip it */ ++ if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF || bdf_type == ATH11K_QMI_BDF_TYPE_REGDB) + goto out; + + if (ab->qmi.target.eeprom_caldata) { +@@ -2626,7 +2635,10 @@ static int ath11k_qmi_event_load_bdf(str + return ret; + } + +- ret = ath11k_qmi_load_bdf_qmi(ab); ++ if (ab->hw_params.supports_regdb) ++ ath11k_qmi_load_bdf_qmi(ab, true); ++ ++ ret = ath11k_qmi_load_bdf_qmi(ab, false); + if (ret < 0) { + ath11k_warn(ab, "failed to load board data file: %d\n", ret); + return ret; +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -48,6 +48,7 @@ enum ath11k_qmi_file_type { + enum ath11k_qmi_bdf_type { + ATH11K_QMI_BDF_TYPE_BIN = 0, + ATH11K_QMI_BDF_TYPE_ELF = 1, ++ ATH11K_QMI_BDF_TYPE_REGDB = 4, + }; + + enum ath11k_qmi_event_type { diff --git a/package/kernel/mac80211/patches/ath11k/0151-ath11k-add-support-of-firmware-logging-for-WCN6855.patch b/package/kernel/mac80211/patches/ath11k/0151-ath11k-add-support-of-firmware-logging-for-WCN6855.patch new file mode 100644 index 000000000..61378616b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0151-ath11k-add-support-of-firmware-logging-for-WCN6855.patch @@ -0,0 +1,295 @@ +From 42da1cc7bd537ea63ddebf88aedcdafcccb00131 Mon Sep 17 00:00:00 2001 +From: Cheng Wang +Date: Mon, 20 Dec 2021 20:10:53 +0800 +Subject: [PATCH] ath11k: add support of firmware logging for WCN6855 + +Host enables WMI firmware logging feature via QMI message. +Host receives firmware logging messages on WMI_DIAG_EVENTID, then +sends logging messages to user space via event tracing infrastructure. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Cheng Wang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211220121053.357087-1-quic_chengwan@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 ++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/qmi.c | 94 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/qmi.h | 12 ++++ + drivers/net/wireless/ath/ath11k/trace.h | 28 ++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 10 +++ + 6 files changed, 151 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -96,6 +96,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = true, + .wakeup_mhi = false, + .supports_rssi_stats = false, ++ .fw_wmi_diag_event = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -159,6 +160,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = true, + .wakeup_mhi = false, + .supports_rssi_stats = false, ++ .fw_wmi_diag_event = false, + }, + { + .name = "qca6390 hw2.0", +@@ -221,6 +223,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + .supports_rssi_stats = true, ++ .fw_wmi_diag_event = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -283,6 +286,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = true, + .wakeup_mhi = false, + .supports_rssi_stats = false, ++ .fw_wmi_diag_event = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -345,6 +349,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + .supports_rssi_stats = true, ++ .fw_wmi_diag_event = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -406,6 +411,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + .supports_rssi_stats = true, ++ .fw_wmi_diag_event = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -191,6 +191,7 @@ struct ath11k_hw_params { + bool alloc_cacheable_memory; + bool wakeup_mhi; + bool supports_rssi_stats; ++ bool fw_wmi_diag_event; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1584,6 +1584,50 @@ static struct qmi_elem_info qmi_wlanfw_c + }, + }; + ++static struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = { ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x10, ++ .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, ++ enablefwlog_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_1_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x10, ++ .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, ++ enablefwlog), ++ }, ++ { ++ .data_type = QMI_EOTI, ++ .array_type = NO_ARRAY, ++ .tlv_type = QMI_COMMON_TLV_TYPE, ++ }, ++}; ++ ++static struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { ++ { ++ .data_type = QMI_STRUCT, ++ .elem_len = 1, ++ .elem_size = sizeof(struct qmi_response_type_v01), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x02, ++ .offset = offsetof(struct qmi_wlanfw_wlan_ini_resp_msg_v01, ++ resp), ++ .ei_array = qmi_response_type_v01_ei, ++ }, ++ { ++ .data_type = QMI_EOTI, ++ .array_type = NO_ARRAY, ++ .tlv_type = QMI_COMMON_TLV_TYPE, ++ }, ++}; ++ + static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) + { + struct qmi_wlanfw_host_cap_req_msg_v01 req; +@@ -2504,6 +2548,48 @@ out: + return ret; + } + ++static int ath11k_qmi_wlanfw_wlan_ini_send(struct ath11k_base *ab, bool enable) ++{ ++ int ret; ++ struct qmi_txn txn; ++ struct qmi_wlanfw_wlan_ini_req_msg_v01 req = {}; ++ struct qmi_wlanfw_wlan_ini_resp_msg_v01 resp = {}; ++ ++ req.enablefwlog_valid = true; ++ req.enablefwlog = enable ? 1 : 0; ++ ++ ret = qmi_txn_init(&ab->qmi.handle, &txn, ++ qmi_wlanfw_wlan_ini_resp_msg_v01_ei, &resp); ++ if (ret < 0) ++ goto out; ++ ++ ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, ++ QMI_WLANFW_WLAN_INI_REQ_V01, ++ QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN, ++ qmi_wlanfw_wlan_ini_req_msg_v01_ei, &req); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to send wlan ini request, err = %d\n", ++ ret); ++ qmi_txn_cancel(&txn); ++ goto out; ++ } ++ ++ ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed wlan ini request, err = %d\n", ret); ++ goto out; ++ } ++ ++ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { ++ ath11k_warn(ab, "qmi wlan ini request failed, result: %d, err: %d\n", ++ resp.resp.result, resp.resp.error); ++ ret = -EINVAL; ++ } ++ ++out: ++ return ret; ++} ++ + void ath11k_qmi_firmware_stop(struct ath11k_base *ab) + { + int ret; +@@ -2524,6 +2610,14 @@ int ath11k_qmi_firmware_start(struct ath + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware start\n"); + ++ if (ab->hw_params.fw_wmi_diag_event) { ++ ret = ath11k_qmi_wlanfw_wlan_ini_send(ab, true); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to send wlan fw ini:%d\n", ret); ++ return ret; ++ } ++ } ++ + ret = ath11k_qmi_wlanfw_wlan_cfg_send(ab); + if (ret < 0) { + ath11k_warn(ab, "qmi failed to send wlan cfg: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -428,10 +428,12 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 { + #define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN 7 + #define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN 803 + #define QMI_WLANFW_WLAN_CFG_RESP_MSG_V01_MAX_LEN 7 ++#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN 4 + #define QMI_WLANFW_WLAN_MODE_REQ_V01 0x0022 + #define QMI_WLANFW_WLAN_MODE_RESP_V01 0x0022 + #define QMI_WLANFW_WLAN_CFG_REQ_V01 0x0023 + #define QMI_WLANFW_WLAN_CFG_RESP_V01 0x0023 ++#define QMI_WLANFW_WLAN_INI_REQ_V01 0x002F + #define QMI_WLANFW_MAX_STR_LEN_V01 16 + #define QMI_WLANFW_MAX_NUM_CE_V01 12 + #define QMI_WLANFW_MAX_NUM_SVC_V01 24 +@@ -473,6 +475,16 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 + struct qmi_response_type_v01 resp; + }; + ++struct qmi_wlanfw_wlan_ini_req_msg_v01 { ++ /* Must be set to true if enablefwlog is being passed */ ++ u8 enablefwlog_valid; ++ u8 enablefwlog; ++}; ++ ++struct qmi_wlanfw_wlan_ini_resp_msg_v01 { ++ struct qmi_response_type_v01 resp; ++}; ++ + int ath11k_qmi_firmware_start(struct ath11k_base *ab, + u32 mode); + void ath11k_qmi_firmware_stop(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -280,6 +280,34 @@ TRACE_EVENT(ath11k_log_dbg_dump, + __get_str(msg) + ) + ); ++ ++TRACE_EVENT(ath11k_wmi_diag, ++ TP_PROTO(struct ath11k_base *ab, const void *data, size_t len), ++ ++ TP_ARGS(ab, data, len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(u16, len) ++ __dynamic_array(u8, data, len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->len = len; ++ memcpy(__get_dynamic_array(data), data, len); ++ ), ++ ++ TP_printk( ++ "%s %s tlv diag len %d", ++ __get_str(driver), ++ __get_str(device), ++ __entry->len ++ ) ++); ++ + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ + + /* we don't want to use include/trace/events */ +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7525,6 +7525,13 @@ static void ath11k_wmi_event_wow_wakeup_ + complete(&ab->wow.wakeup_completed); + } + ++static void ++ath11k_wmi_diag_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ trace_ath11k_wmi_diag(ab, skb->data, skb->len); ++} ++ + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) + { + struct wmi_cmd_hdr *cmd_hdr; +@@ -7647,6 +7654,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_RFKILL_STATE_CHANGE_EVENTID: + ath11k_rfkill_state_change_event(ab, skb); + break; ++ case WMI_DIAG_EVENTID: ++ ath11k_wmi_diag_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/package/kernel/mac80211/patches/ath11k/0152-ath11k-Fix-unexpected-return-buffer-manager-error-fo.patch b/package/kernel/mac80211/patches/ath11k/0152-ath11k-Fix-unexpected-return-buffer-manager-error-fo.patch new file mode 100644 index 000000000..0e12b0519 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0152-ath11k-Fix-unexpected-return-buffer-manager-error-fo.patch @@ -0,0 +1,58 @@ +From 71c748b5e01e3e28838a8e26a8966fb5adb03df7 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 22 Dec 2021 09:35:35 +0800 +Subject: [PATCH] ath11k: Fix unexpected return buffer manager error for + QCA6390 + +We are seeing below error on QCA6390: +... +[70211.671189] ath11k_pci 0000:72:00.0: failed to parse rx error in wbm_rel ring desc -22 +[70212.696154] ath11k_pci 0000:72:00.0: failed to parse rx error in wbm_rel ring desc -22 +[70213.092941] ath11k_pci 0000:72:00.0: failed to parse rx error in wbm_rel ring desc -22 +... + +The reason is that, with commit 734223d78428 ("ath11k: change return +buffer manager for QCA6390"), ath11k expects the return buffer manager +(RBM) field of descriptor configured as HAL_RX_BUF_RBM_SW1_BM when +parsing error frames from WBM2SW3_RELEASE ring. This is a wrong change +cause the RBM field is set as HAL_RX_BUF_RBM_SW3_BM. + +The same issue also applies to REO2TCL ring though we have not got any +error reported. + +Fix it by changing RBM from HAL_RX_BUF_RBM_SW1_BM to HAL_RX_BUF_RBM_SW3_BM +for these two rings. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Fixes: 734223d78428 ("ath11k: change return buffer manager for QCA6390") +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211222013536.582527-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- + drivers/net/wireless/ath/ath11k/hal_rx.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -3837,7 +3837,7 @@ int ath11k_dp_process_rx_err(struct ath1 + ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, + &rbm); + if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST && +- rbm != ab->hw_params.hal_params->rx_buf_rbm) { ++ rbm != HAL_RX_BUF_RBM_SW3_BM) { + ab->soc_stats.invalid_rbm++; + ath11k_warn(ab, "invalid return buffer manager %d\n", rbm); + ath11k_dp_rx_link_desc_return(ab, desc, +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -374,7 +374,7 @@ int ath11k_hal_wbm_desc_parse_err(struct + + ret_buf_mgr = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, + wbm_desc->buf_addr_info.info1); +- if (ret_buf_mgr != ab->hw_params.hal_params->rx_buf_rbm) { ++ if (ret_buf_mgr != HAL_RX_BUF_RBM_SW3_BM) { + ab->soc_stats.invalid_rbm++; + return -EINVAL; + } diff --git a/package/kernel/mac80211/patches/ath11k/0153-codel-remove-unnecessary-sock.h-include.patch b/package/kernel/mac80211/patches/ath11k/0153-codel-remove-unnecessary-sock.h-include.patch new file mode 100644 index 000000000..cbe5476bb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0153-codel-remove-unnecessary-sock.h-include.patch @@ -0,0 +1,41 @@ +From 15fcb1031178f2a42425c2993b2ec7bb894c04d6 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Tue, 21 Dec 2021 11:39:40 -0800 +Subject: [PATCH] codel: remove unnecessary sock.h include + +Since sock.h is modified relatively often (60 times in the last +12 months) it seems worthwhile to decrease the incremental build +work. + +CoDel's header includes net/inet_ecn.h which in turn includes net/sock.h. +codel.h is itself included by mac80211 which is included by much of +the WiFi stack and drivers. Removing the net/inet_ecn.h include from +CoDel breaks the dependecy between WiFi and sock.h. + +Commit d068ca2ae2e6 ("codel: split into multiple files") moved all +the code which actually needs ECN helpers out to net/codel_impl.h, +the include can be moved there as well. + +This decreases the incremental build size after touching sock.h +from 4999 objects to 4051 objects. + +Fix unmasked missing includes in WiFi drivers. + +Acked-by: Kalle Valo +Link: https://lore.kernel.org/r/20211221193941.3805147-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -3,6 +3,8 @@ + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + */ + ++#include ++ + #include "debugfs.h" + + #include "core.h" diff --git a/package/kernel/mac80211/patches/ath11k/0154-codel-remove-unnecessary-pkt_sched.h-include.patch b/package/kernel/mac80211/patches/ath11k/0154-codel-remove-unnecessary-pkt_sched.h-include.patch new file mode 100644 index 000000000..bb833ba7a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0154-codel-remove-unnecessary-pkt_sched.h-include.patch @@ -0,0 +1,37 @@ +From e6e5904455815626b711c7d48cacd253f4d72f84 Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Tue, 21 Dec 2021 11:39:41 -0800 +Subject: [PATCH] codel: remove unnecessary pkt_sched.h include + +Commit d068ca2ae2e6 ("codel: split into multiple files") moved all +Qdisc-related code to codel_qdisc.h, move the include of pkt_sched.h +as well. + +This is similar to the previous commit, although we don't care as +much about incremental builds after pkt_sched.h was touched itself +it is included by net/sch_generic.h which is modified ~20 times +a year. + +This decreases the incremental build size after touching pkt_sched.h +from 1592 to 617 objects. + +Fix unmasked missing includes in WiFi drivers. + +Acked-by: Kalle Valo +Link: https://lore.kernel.org/r/20211221193941.3805147-2-kuba@kernel.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/wireless/ath/ath11k/reg.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -2,6 +2,8 @@ + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + */ ++#include ++ + #include "core.h" + #include "debug.h" + diff --git a/package/kernel/mac80211/patches/ath11k/0155-ath11k-add-missing-of_node_put-to-avoid-leak.patch b/package/kernel/mac80211/patches/ath11k/0155-ath11k-add-missing-of_node_put-to-avoid-leak.patch new file mode 100644 index 000000000..5e348f23e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0155-ath11k-add-missing-of_node_put-to-avoid-leak.patch @@ -0,0 +1,39 @@ +From 3d38faef0de1756994b3d95e47b2302842f729e2 Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Mon, 10 Jan 2022 16:24:13 +0200 +Subject: [PATCH] ath11k: add missing of_node_put() to avoid leak + +The node pointer is returned by of_find_node_by_type() +or of_parse_phandle() with refcount incremented. Calling +of_node_put() to aovid the refcount leak. + +Fixes: 6ac04bdc5edb ("ath11k: Use reserved host DDR addresses from DT for PCI devices") +Reported-by: Hulk Robot +Signed-off-by: Yang Yingliang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211221114003.335557-1-yangyingliang@huawei.com +--- + drivers/net/wireless/ath/ath11k/mhi.c | 1 + + drivers/net/wireless/ath/ath11k/qmi.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -332,6 +332,7 @@ static int ath11k_mhi_read_addr_from_dt( + return -ENOENT; + + ret = of_address_to_resource(np, 0, &res); ++ of_node_put(np); + if (ret) + return ret; + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1936,6 +1936,7 @@ static int ath11k_qmi_assign_target_mem_ + } + + ret = of_address_to_resource(hremote_node, 0, &res); ++ of_node_put(hremote_node); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to get reg from hremote\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0156-ath11k-fix-workqueue-not-getting-destroyed-after-rmm.patch b/package/kernel/mac80211/patches/ath11k/0156-ath11k-fix-workqueue-not-getting-destroyed-after-rmm.patch new file mode 100644 index 000000000..42a871095 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0156-ath11k-fix-workqueue-not-getting-destroyed-after-rmm.patch @@ -0,0 +1,43 @@ +From 9f4ecacf2fa47b8aadd9bca2e88cde01856de028 Mon Sep 17 00:00:00 2001 +From: Aditya Kumar Singh +Date: Mon, 10 Jan 2022 16:24:14 +0200 +Subject: [PATCH] ath11k: fix workqueue not getting destroyed after rmmod + +Currently, ath11k_core_alloc() creates a single thread workqueue. +This workqueue is not detroyed during clean up when ath11k modules +are unloaded from the kernel and is left as it is. +If workqueue is not destroyed, it could lead to kernel +memory scarcity in a longer run. This could affect self and +other drivers workability as well. + +Add destroy workqueue in ath11k_core_free(). + +Tested on: IPQ8074 WLAN.HK.2.4.0.1-01746-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Aditya Kumar Singh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1640231787-17408-1-git-send-email-quic_adisi@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -1404,6 +1405,9 @@ EXPORT_SYMBOL(ath11k_core_deinit); + + void ath11k_core_free(struct ath11k_base *ab) + { ++ flush_workqueue(ab->workqueue); ++ destroy_workqueue(ab->workqueue); ++ + kfree(ab); + } + EXPORT_SYMBOL(ath11k_core_free); diff --git a/package/kernel/mac80211/patches/ath11k/0157-ath11k-Refactor-the-fallback-routine-when-peer-creat.patch b/package/kernel/mac80211/patches/ath11k/0157-ath11k-Refactor-the-fallback-routine-when-peer-creat.patch new file mode 100644 index 000000000..16c9cf3f3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0157-ath11k-Refactor-the-fallback-routine-when-peer-creat.patch @@ -0,0 +1,82 @@ +From fbed57d897f6ea065c45806959337a6f28d2a94d Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Mon, 10 Jan 2022 16:24:14 +0200 +Subject: [PATCH] ath11k: Refactor the fallback routine when peer create fails + +When there is an error in peer create process from +ath11k_peer_find(), the code attempts to handle a fallback +for peer create. When this fallback fails, the driver returns +the fallback return code rather than actual error code +(-ENOENT). So refactor the fallback routine to return +the actual error code. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01067-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1640244819-21183-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/peer.c | 40 +++++++++++++++----------- + 1 file changed, 23 insertions(+), 17 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/peer.c ++++ b/drivers/net/wireless/ath/ath11k/peer.c +@@ -252,7 +252,7 @@ int ath11k_peer_create(struct ath11k *ar + { + struct ath11k_peer *peer; + struct ath11k_sta *arsta; +- int ret; ++ int ret, fbret; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -291,22 +291,8 @@ int ath11k_peer_create(struct ath11k *ar + ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n", + param->peer_addr, param->vdev_id); + +- reinit_completion(&ar->peer_delete_done); +- +- ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, +- param->vdev_id); +- if (ret) { +- ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", +- param->vdev_id, param->peer_addr); +- return ret; +- } +- +- ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, +- param->peer_addr); +- if (ret) +- return ret; +- +- return -ENOENT; ++ ret = -ENOENT; ++ goto cleanup; + } + + peer->pdev_idx = ar->pdev_idx; +@@ -335,4 +321,24 @@ int ath11k_peer_create(struct ath11k *ar + spin_unlock_bh(&ar->ab->base_lock); + + return 0; ++ ++cleanup: ++ reinit_completion(&ar->peer_delete_done); ++ ++ fbret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, ++ param->vdev_id); ++ if (fbret) { ++ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", ++ param->vdev_id, param->peer_addr); ++ goto exit; ++ } ++ ++ fbret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, ++ param->peer_addr); ++ if (fbret) ++ ath11k_warn(ar->ab, "failed wait for peer %pM delete done id %d fallback ret %d\n", ++ param->peer_addr, param->vdev_id, fbret); ++ ++exit: ++ return ret; + } diff --git a/package/kernel/mac80211/patches/ath11k/0158-ath11k-add-LDPC-FEC-type-in-802.11-radiotap-header.patch b/package/kernel/mac80211/patches/ath11k/0158-ath11k-add-LDPC-FEC-type-in-802.11-radiotap-header.patch new file mode 100644 index 000000000..572a9e2c6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0158-ath11k-add-LDPC-FEC-type-in-802.11-radiotap-header.patch @@ -0,0 +1,126 @@ +From b3febdccde3eb086b892485c923cd6b73b2ce9d7 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Tue, 11 Jan 2022 16:42:52 +0200 +Subject: [PATCH] ath11k: add LDPC FEC type in 802.11 radiotap header + +LDPC is one the FEC type advertised in msdu_start info2 for HT packet +type. Hence, add hardware specific callback for fetching LDPC +support from msdu start and enable RX_ENC_FLAG_LDPC flag while passing +rx status to mac80211. + +Tested-on: IPQ8074 WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638294648-844-3-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 12 +++++++++++- + drivers/net/wireless/ath/ath11k/hw.c | 16 ++++++++++++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 3 files changed, 28 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -43,6 +43,13 @@ static inline u8 ath11k_dp_rx_h_msdu_sta + } + + static inline ++bool ath11k_dp_rx_h_msdu_start_ldpc_support(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ return ab->hw_params.hw_ops->rx_desc_get_ldpc_support(desc); ++} ++ ++static inline + u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, + struct hal_rx_desc *desc) + { +@@ -2313,7 +2320,7 @@ static void ath11k_dp_rx_h_rate(struct a + u8 bw; + u8 rate_mcs, nss; + u8 sgi; +- bool is_cck; ++ bool is_cck, is_ldpc; + + pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(ar->ab, rx_desc); + bw = ath11k_dp_rx_h_msdu_start_rx_bw(ar->ab, rx_desc); +@@ -2355,6 +2362,9 @@ static void ath11k_dp_rx_h_rate(struct a + if (sgi) + rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); ++ is_ldpc = ath11k_dp_rx_h_msdu_start_ldpc_support(ar->ab, rx_desc); ++ if (is_ldpc) ++ rx_status->enc_flags |= RX_ENC_FLAG_LDPC; + break; + case RX_MSDU_START_PKT_TYPE_11AX: + rx_status->rate_idx = rate_mcs; +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -273,6 +273,12 @@ static u8 ath11k_hw_ipq8074_rx_desc_get_ + __le32_to_cpu(desc->u.ipq8074.msdu_start.info2)); + } + ++static bool ath11k_hw_ipq8074_rx_desc_get_ldpc_support(struct hal_rx_desc *desc) ++{ ++ return FIELD_GET(RX_MSDU_START_INFO2_LDPC, ++ __le32_to_cpu(desc->u.ipq8074.msdu_start.info2)); ++} ++ + static bool ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) + { + return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID, +@@ -444,6 +450,12 @@ static u8 ath11k_hw_qcn9074_rx_desc_get_ + __le32_to_cpu(desc->u.qcn9074.msdu_start.info2)); + } + ++static bool ath11k_hw_qcn9074_rx_desc_get_ldpc_support(struct hal_rx_desc *desc) ++{ ++ return FIELD_GET(RX_MSDU_START_INFO2_LDPC, ++ __le32_to_cpu(desc->u.qcn9074.msdu_start.info2)); ++} ++ + static bool ath11k_hw_qcn9074_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) + { + return !!FIELD_GET(RX_MPDU_START_INFO11_MPDU_SEQ_CTRL_VALID, +@@ -815,6 +827,7 @@ const struct ath11k_hw_ops ipq8074_ops = + .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_ipq8074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no, +@@ -853,6 +866,7 @@ const struct ath11k_hw_ops ipq6018_ops = + .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_ipq8074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no, +@@ -891,6 +905,7 @@ const struct ath11k_hw_ops qca6390_ops = + .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_ipq8074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no, +@@ -929,6 +944,7 @@ const struct ath11k_hw_ops qcn9074_ops = + .rx_desc_get_encrypt_type = ath11k_hw_qcn9074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_qcn9074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_qcn9074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_qcn9074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_qcn9074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_qcn9074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_qcn9074_rx_desc_get_mpdu_start_seq_no, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -210,6 +210,7 @@ struct ath11k_hw_ops { + u32 (*rx_desc_get_encrypt_type)(struct hal_rx_desc *desc); + u8 (*rx_desc_get_decap_type)(struct hal_rx_desc *desc); + u8 (*rx_desc_get_mesh_ctl)(struct hal_rx_desc *desc); ++ bool (*rx_desc_get_ldpc_support)(struct hal_rx_desc *desc); + bool (*rx_desc_get_mpdu_seq_ctl_vld)(struct hal_rx_desc *desc); + bool (*rx_desc_get_mpdu_fc_valid)(struct hal_rx_desc *desc); + u16 (*rx_desc_get_mpdu_start_seq_no)(struct hal_rx_desc *desc); diff --git a/package/kernel/mac80211/patches/ath11k/0159-ath11k-free-peer-for-station-when-disconnect-from-AP.patch b/package/kernel/mac80211/patches/ath11k/0159-ath11k-free-peer-for-station-when-disconnect-from-AP.patch new file mode 100644 index 000000000..6bfe0a821 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0159-ath11k-free-peer-for-station-when-disconnect-from-AP.patch @@ -0,0 +1,244 @@ +From 212ad7cb7d7592669c067125949e0a8e31ce6a0b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 11 Jan 2022 16:42:52 +0200 +Subject: [PATCH] ath11k: free peer for station when disconnect from AP for + QCA6390/WCN6855 + +Commit b4a0f54156ac ("ath11k: move peer delete after vdev stop of station +for QCA6390 and WCN6855") is to fix firmware crash by changing the WMI +command sequence, but actually skip all the peer delete operation, then +it lead commit 58595c9874c6 ("ath11k: Fixing dangling pointer issue upon +peer delete failure") not take effect, and then happened a use-after-free +warning from KASAN. because the peer->sta is not set to NULL and then used +later. + +Change to only skip the WMI_PEER_DELETE_CMDID for QCA6390/WCN6855. + +log of user-after-free: + +[ 534.888665] BUG: KASAN: use-after-free in ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888696] Read of size 8 at addr ffff8881396bb1b8 by task rtcwake/2860 + +[ 534.888705] CPU: 4 PID: 2860 Comm: rtcwake Kdump: loaded Tainted: G W 5.15.0-wt-ath+ #523 +[ 534.888712] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 534.888716] Call Trace: +[ 534.888720] +[ 534.888726] dump_stack_lvl+0x57/0x7d +[ 534.888736] print_address_description.constprop.0+0x1f/0x170 +[ 534.888745] ? ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888771] kasan_report.cold+0x83/0xdf +[ 534.888783] ? ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888810] ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888840] ath11k_dp_rx_process_mon_status+0x529/0xa70 [ath11k] +[ 534.888874] ? ath11k_dp_rx_mon_status_bufs_replenish+0x3f0/0x3f0 [ath11k] +[ 534.888897] ? check_prev_add+0x20f0/0x20f0 +[ 534.888922] ? __lock_acquire+0xb72/0x1870 +[ 534.888937] ? find_held_lock+0x33/0x110 +[ 534.888954] ath11k_dp_rx_process_mon_rings+0x297/0x520 [ath11k] +[ 534.888981] ? rcu_read_unlock+0x40/0x40 +[ 534.888990] ? ath11k_dp_rx_pdev_alloc+0xd90/0xd90 [ath11k] +[ 534.889026] ath11k_dp_service_mon_ring+0x67/0xe0 [ath11k] +[ 534.889053] ? ath11k_dp_rx_process_mon_rings+0x520/0x520 [ath11k] +[ 534.889075] call_timer_fn+0x167/0x4a0 +[ 534.889084] ? add_timer_on+0x3b0/0x3b0 +[ 534.889103] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 534.889117] __run_timers.part.0+0x539/0x8b0 +[ 534.889123] ? ath11k_dp_rx_process_mon_rings+0x520/0x520 [ath11k] +[ 534.889157] ? call_timer_fn+0x4a0/0x4a0 +[ 534.889164] ? mark_lock_irq+0x1c30/0x1c30 +[ 534.889173] ? clockevents_program_event+0xdd/0x280 +[ 534.889189] ? mark_held_locks+0xa5/0xe0 +[ 534.889203] run_timer_softirq+0x97/0x180 +[ 534.889213] __do_softirq+0x276/0x86a +[ 534.889230] __irq_exit_rcu+0x11c/0x180 +[ 534.889238] irq_exit_rcu+0x5/0x20 +[ 534.889244] sysvec_apic_timer_interrupt+0x8e/0xc0 +[ 534.889251] +[ 534.889254] +[ 534.889259] asm_sysvec_apic_timer_interrupt+0x12/0x20 +[ 534.889265] RIP: 0010:_raw_spin_unlock_irqrestore+0x38/0x70 +[ 534.889271] Code: 74 24 10 e8 ea c2 bf fd 48 89 ef e8 12 53 c0 fd 81 e3 00 02 00 00 75 25 9c 58 f6 c4 02 75 2d 48 85 db 74 01 fb bf 01 00 00 00 13 a7 b5 fd 65 8b 05 cc d9 9c 5e 85 c0 74 0a 5b 5d c3 e8 a0 ee +[ 534.889276] RSP: 0018:ffffc90002e5f880 EFLAGS: 00000206 +[ 534.889284] RAX: 0000000000000006 RBX: 0000000000000200 RCX: ffffffff9f256f10 +[ 534.889289] RDX: 0000000000000000 RSI: ffffffffa1c6e420 RDI: 0000000000000001 +[ 534.889293] RBP: ffff8881095e6200 R08: 0000000000000001 R09: ffffffffa40d2b8f +[ 534.889298] R10: fffffbfff481a571 R11: 0000000000000001 R12: ffff8881095e6e68 +[ 534.889302] R13: ffffc90002e5f908 R14: 0000000000000246 R15: 0000000000000000 +[ 534.889316] ? mark_lock+0xd0/0x14a0 +[ 534.889332] klist_next+0x1d4/0x450 +[ 534.889340] ? dpm_wait_for_subordinate+0x2d0/0x2d0 +[ 534.889350] device_for_each_child+0xa8/0x140 +[ 534.889360] ? device_remove_class_symlinks+0x1b0/0x1b0 +[ 534.889370] ? __lock_release+0x4bd/0x9f0 +[ 534.889378] ? dpm_suspend+0x26b/0x3f0 +[ 534.889390] dpm_wait_for_subordinate+0x82/0x2d0 +[ 534.889400] ? dpm_for_each_dev+0xa0/0xa0 +[ 534.889410] ? dpm_suspend+0x233/0x3f0 +[ 534.889427] __device_suspend+0xd4/0x10c0 +[ 534.889440] ? wait_for_completion_io+0x270/0x270 +[ 534.889456] ? async_suspend_late+0xe0/0xe0 +[ 534.889463] ? async_schedule_node_domain+0x468/0x640 +[ 534.889482] dpm_suspend+0x25a/0x3f0 +[ 534.889491] ? dpm_suspend_end+0x1a0/0x1a0 +[ 534.889497] ? ktime_get+0x214/0x2f0 +[ 534.889502] ? lockdep_hardirqs_on+0x79/0x100 +[ 534.889509] ? recalibrate_cpu_khz+0x10/0x10 +[ 534.889516] ? ktime_get+0x119/0x2f0 +[ 534.889528] dpm_suspend_start+0xab/0xc0 +[ 534.889538] suspend_devices_and_enter+0x1ca/0x350 +[ 534.889546] ? suspend_enter+0x850/0x850 +[ 534.889566] enter_state+0x27c/0x3d7 +[ 534.889575] pm_suspend.cold+0x42/0x189 +[ 534.889583] state_store+0xab/0x160 +[ 534.889595] ? sysfs_file_ops+0x160/0x160 +[ 534.889601] kernfs_fop_write_iter+0x2b5/0x450 +[ 534.889615] new_sync_write+0x36a/0x600 +[ 534.889625] ? new_sync_read+0x600/0x600 +[ 534.889639] ? rcu_read_unlock+0x40/0x40 +[ 534.889668] vfs_write+0x619/0x910 +[ 534.889681] ksys_write+0xf4/0x1d0 +[ 534.889689] ? __ia32_sys_read+0xa0/0xa0 +[ 534.889699] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 534.889707] ? syscall_enter_from_user_mode+0x1d/0x50 +[ 534.889719] do_syscall_64+0x3b/0x90 +[ 534.889725] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 534.889731] RIP: 0033:0x7f0b9bc931e7 +[ 534.889736] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 534.889741] RSP: 002b:00007ffd9d34cc88 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 534.889749] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f0b9bc931e7 +[ 534.889753] RDX: 0000000000000004 RSI: 0000561cd023c5f0 RDI: 0000000000000004 +[ 534.889757] RBP: 0000561cd023c5f0 R08: 0000000000000000 R09: 0000000000000004 +[ 534.889761] R10: 0000561ccef842a6 R11: 0000000000000246 R12: 0000000000000004 +[ 534.889765] R13: 0000561cd0239590 R14: 00007f0b9bd6f4a0 R15: 00007f0b9bd6e8a0 +[ 534.889789] + +[ 534.889796] Allocated by task 2711: +[ 534.889800] kasan_save_stack+0x1b/0x40 +[ 534.889805] __kasan_kmalloc+0x7c/0x90 +[ 534.889810] sta_info_alloc+0x98/0x1ef0 [mac80211] +[ 534.889874] ieee80211_prep_connection+0x30b/0x11e0 [mac80211] +[ 534.889950] ieee80211_mgd_auth+0x529/0xe00 [mac80211] +[ 534.890024] cfg80211_mlme_auth+0x332/0x6f0 [cfg80211] +[ 534.890090] nl80211_authenticate+0x839/0xcf0 [cfg80211] +[ 534.890147] genl_family_rcv_msg_doit+0x1f4/0x2f0 +[ 534.890154] genl_rcv_msg+0x280/0x500 +[ 534.890160] netlink_rcv_skb+0x11c/0x340 +[ 534.890165] genl_rcv+0x1f/0x30 +[ 534.890170] netlink_unicast+0x42b/0x700 +[ 534.890176] netlink_sendmsg+0x71b/0xc60 +[ 534.890181] sock_sendmsg+0xdf/0x110 +[ 534.890187] ____sys_sendmsg+0x5c0/0x850 +[ 534.890192] ___sys_sendmsg+0xe4/0x160 +[ 534.890197] __sys_sendmsg+0xb2/0x140 +[ 534.890202] do_syscall_64+0x3b/0x90 +[ 534.890207] entry_SYSCALL_64_after_hwframe+0x44/0xae + +[ 534.890215] Freed by task 2825: +[ 534.890218] kasan_save_stack+0x1b/0x40 +[ 534.890223] kasan_set_track+0x1c/0x30 +[ 534.890227] kasan_set_free_info+0x20/0x30 +[ 534.890232] __kasan_slab_free+0xce/0x100 +[ 534.890237] slab_free_freelist_hook+0xf0/0x1a0 +[ 534.890242] kfree+0xe5/0x370 +[ 534.890248] __sta_info_flush+0x333/0x4b0 [mac80211] +[ 534.890308] ieee80211_set_disassoc+0x324/0xd20 [mac80211] +[ 534.890382] ieee80211_mgd_deauth+0x537/0xee0 [mac80211] +[ 534.890472] cfg80211_mlme_deauth+0x349/0x810 [cfg80211] +[ 534.890526] cfg80211_mlme_down+0x1ce/0x270 [cfg80211] +[ 534.890578] cfg80211_disconnect+0x4f5/0x7b0 [cfg80211] +[ 534.890631] cfg80211_leave+0x24/0x40 [cfg80211] +[ 534.890677] wiphy_suspend+0x23d/0x2f0 [cfg80211] +[ 534.890723] dpm_run_callback+0xf4/0x1b0 +[ 534.890728] __device_suspend+0x648/0x10c0 +[ 534.890733] async_suspend+0x16/0xe0 +[ 534.890737] async_run_entry_fn+0x90/0x4f0 +[ 534.890741] process_one_work+0x866/0x1490 +[ 534.890747] worker_thread+0x596/0x1010 +[ 534.890751] kthread+0x35d/0x420 +[ 534.890756] ret_from_fork+0x22/0x30 + +[ 534.890763] The buggy address belongs to the object at ffff8881396ba000 + which belongs to the cache kmalloc-8k of size 8192 +[ 534.890767] The buggy address is located 4536 bytes inside of + 8192-byte region [ffff8881396ba000, ffff8881396bc000) +[ 534.890772] The buggy address belongs to the page: +[ 534.890775] page:ffffea0004e5ae00 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1396b8 +[ 534.890780] head:ffffea0004e5ae00 order:3 compound_mapcount:0 compound_pincount:0 +[ 534.890784] flags: 0x200000000010200(slab|head|node=0|zone=2) +[ 534.890791] raw: 0200000000010200 ffffea000562be08 ffffea0004b04c08 ffff88810004e340 +[ 534.890795] raw: 0000000000000000 0000000000010001 00000001ffffffff 0000000000000000 +[ 534.890798] page dumped because: kasan: bad access detected + +[ 534.890804] Memory state around the buggy address: +[ 534.890807] ffff8881396bb080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890811] ffff8881396bb100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890814] >ffff8881396bb180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890817] ^ +[ 534.890821] ffff8881396bb200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890824] ffff8881396bb280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890827] ================================================================== +[ 534.890830] Disabling lock debugging due to kernel taint + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Fixes: b4a0f54156ac ("ath11k: move peer delete after vdev stop of station for QCA6390 and WCN6855") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211222070431.29595-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 31 ++++++++++++++++----------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4504,24 +4504,30 @@ static int ath11k_mac_op_sta_state(struc + sta->addr, arvif->vdev_id); + } else if ((old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) { +- ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); ++ bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay && ++ vif->type == NL80211_IFTYPE_STATION; + +- if (ar->ab->hw_params.vdev_start_delay && +- vif->type == NL80211_IFTYPE_STATION) +- goto free; ++ ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + +- ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); +- if (ret) +- ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n", +- sta->addr, arvif->vdev_id); +- else +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n", +- sta->addr, arvif->vdev_id); ++ if (!skip_peer_delete) { ++ ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "Failed to delete peer: %pM for VDEV: %d\n", ++ sta->addr, arvif->vdev_id); ++ else ++ ath11k_dbg(ar->ab, ++ ATH11K_DBG_MAC, ++ "Removed peer: %pM for VDEV: %d\n", ++ sta->addr, arvif->vdev_id); ++ } + + ath11k_mac_dec_num_stations(arvif, sta); + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); +- if (peer && peer->sta == sta) { ++ if (skip_peer_delete && peer) { ++ peer->sta = NULL; ++ } else if (peer && peer->sta == sta) { + ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", + vif->addr, arvif->vdev_id); + peer->sta = NULL; +@@ -4531,7 +4537,6 @@ static int ath11k_mac_op_sta_state(struc + } + spin_unlock_bh(&ar->ab->base_lock); + +-free: + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + diff --git a/package/kernel/mac80211/patches/ath11k/0160-ath11k-enable-RX-PPDU-stats-in-monitor-co-exist-mode.patch b/package/kernel/mac80211/patches/ath11k/0160-ath11k-enable-RX-PPDU-stats-in-monitor-co-exist-mode.patch new file mode 100644 index 000000000..571efbe9b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0160-ath11k-enable-RX-PPDU-stats-in-monitor-co-exist-mode.patch @@ -0,0 +1,222 @@ +From 67a9d399fcb03177152a8797a855cbd4c995c2de Mon Sep 17 00:00:00 2001 +From: Miles Hu +Date: Wed, 12 Jan 2022 10:15:10 +0200 +Subject: [PATCH] ath11k: enable RX PPDU stats in monitor co-exist mode + +RX PPDU statistics collection is missing when monitor mode co-exists +with other modes. This commit combines the processing of the destination +ring with the status ring to fix the issue. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: Miles Hu +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220111032224.14093-1-quic_alokad@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 6 ++ + drivers/net/wireless/ath/ath11k/dp_rx.c | 84 +++++++---------------- + drivers/net/wireless/ath/ath11k/hal_rx.h | 8 +-- + 3 files changed, 34 insertions(+), 64 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -666,6 +666,12 @@ static ssize_t ath11k_write_extd_rx_stat + goto exit; + } + ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) { ++ ar->debug.extd_rx_stats = enable; ++ ret = count; ++ goto exit; ++ } ++ + if (enable) { + rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START; + rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START; +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -20,6 +20,9 @@ + + #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) + ++static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, ++ u32 quota, struct napi_struct *napi); ++ + static inline + u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) + { +@@ -3097,12 +3100,14 @@ int ath11k_dp_rx_process_mon_status(stru + enum hal_rx_mon_status hal_status; + struct sk_buff *skb; + struct sk_buff_head skb_list; +- struct hal_rx_mon_ppdu_info ppdu_info; + struct ath11k_peer *peer; + struct ath11k_sta *arsta; + int num_buffs_reaped = 0; + u32 rx_buf_sz; + u16 log_type = 0; ++ struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; ++ struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; ++ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; + + __skb_queue_head_init(&skb_list); + +@@ -3111,8 +3116,8 @@ int ath11k_dp_rx_process_mon_status(stru + if (!num_buffs_reaped) + goto exit; + +- memset(&ppdu_info, 0, sizeof(ppdu_info)); +- ppdu_info.peer_id = HAL_INVALID_PEERID; ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; + + while ((skb = __skb_dequeue(&skb_list))) { + if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { +@@ -3126,9 +3131,18 @@ int ath11k_dp_rx_process_mon_status(stru + if (log_type) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + +- hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb); ++ hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); + +- if (ppdu_info.peer_id == HAL_INVALID_PEERID || ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && ++ pmon->mon_ppdu_status == DP_PPDU_STATUS_START && ++ hal_status == HAL_TLV_STATUS_PPDU_DONE) { ++ rx_mon_stats->status_ppdu_done++; ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; ++ ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_START; ++ } ++ ++ if (ppdu_info->peer_id == HAL_INVALID_PEERID || + hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { + dev_kfree_skb_any(skb); + continue; +@@ -3136,17 +3150,17 @@ int ath11k_dp_rx_process_mon_status(stru + + rcu_read_lock(); + spin_lock_bh(&ab->base_lock); +- peer = ath11k_peer_find_by_id(ab, ppdu_info.peer_id); ++ peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); + + if (!peer || !peer->sta) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "failed to find the peer with peer_id %d\n", +- ppdu_info.peer_id); ++ ppdu_info->peer_id); + goto next_skb; + } + + arsta = (struct ath11k_sta *)peer->sta->drv_priv; +- ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info); ++ ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); + + if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +@@ -3156,8 +3170,8 @@ next_skb: + rcu_read_unlock(); + + dev_kfree_skb_any(skb); +- memset(&ppdu_info, 0, sizeof(ppdu_info)); +- ppdu_info.peer_id = HAL_INVALID_PEERID; ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; + } + exit: + return num_buffs_reaped; +@@ -5116,38 +5130,6 @@ static void ath11k_dp_rx_mon_dest_proces + } + } + +-static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar, +- int mac_id, u32 quota, +- struct napi_struct *napi) +-{ +- struct ath11k_pdev_dp *dp = &ar->dp; +- struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; +- struct hal_rx_mon_ppdu_info *ppdu_info; +- struct sk_buff *status_skb; +- u32 tlv_status = HAL_TLV_STATUS_BUF_DONE; +- struct ath11k_pdev_mon_stats *rx_mon_stats; +- +- ppdu_info = &pmon->mon_ppdu_info; +- rx_mon_stats = &pmon->rx_mon_stats; +- +- if (pmon->mon_ppdu_status != DP_PPDU_STATUS_START) +- return; +- +- while (!skb_queue_empty(&pmon->rx_status_q)) { +- status_skb = skb_dequeue(&pmon->rx_status_q); +- +- tlv_status = ath11k_hal_rx_parse_mon_status(ar->ab, ppdu_info, +- status_skb); +- if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) { +- rx_mon_stats->status_ppdu_done++; +- pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; +- ath11k_dp_rx_mon_dest_process(ar, mac_id, quota, napi); +- pmon->mon_ppdu_status = DP_PPDU_STATUS_START; +- } +- dev_kfree_skb_any(status_skb); +- } +-} +- + static u32 + ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, + void *ring_entry, struct sk_buff **head_msdu, +@@ -5499,22 +5481,6 @@ reap_status_ring: + return quota; + } + +-static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, +- struct napi_struct *napi, int budget) +-{ +- struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); +- struct ath11k_pdev_dp *dp = &ar->dp; +- struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; +- int num_buffs_reaped = 0; +- +- num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ar->ab, mac_id, &budget, +- &pmon->rx_status_q); +- if (num_buffs_reaped) +- ath11k_dp_rx_mon_status_process_tlv(ar, mac_id, budget, napi); +- +- return num_buffs_reaped; +-} +- + int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, + struct napi_struct *napi, int budget) + { +@@ -5524,8 +5490,6 @@ int ath11k_dp_rx_process_mon_rings(struc + if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && + ab->hw_params.full_monitor_mode) + ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget); +- else if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) +- ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); + else + ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -65,10 +65,6 @@ enum hal_rx_reception_type { + HAL_RX_RECEPTION_TYPE_MAX, + }; + +-#define HAL_TLV_STATUS_PPDU_NOT_DONE 0 +-#define HAL_TLV_STATUS_PPDU_DONE 1 +-#define HAL_TLV_STATUS_BUF_DONE 2 +-#define HAL_TLV_STATUS_PPDU_NON_STD_DONE 3 + #define HAL_RX_FCS_LEN 4 + + enum hal_rx_mon_status { +@@ -77,6 +73,10 @@ enum hal_rx_mon_status { + HAL_RX_MON_STATUS_BUF_DONE, + }; + ++#define HAL_TLV_STATUS_PPDU_NOT_DONE HAL_RX_MON_STATUS_PPDU_NOT_DONE ++#define HAL_TLV_STATUS_PPDU_DONE HAL_RX_MON_STATUS_PPDU_DONE ++#define HAL_TLV_STATUS_BUF_DONE HAL_RX_MON_STATUS_BUF_DONE ++ + struct hal_sw_mon_ring_entries { + dma_addr_t mon_dst_paddr; + dma_addr_t mon_status_paddr; diff --git a/package/kernel/mac80211/patches/ath11k/0161-ath11k-move-function-ath11k_dp_rx_process_mon_status.patch b/package/kernel/mac80211/patches/ath11k/0161-ath11k-move-function-ath11k_dp_rx_process_mon_status.patch new file mode 100644 index 000000000..c0a14de99 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0161-ath11k-move-function-ath11k_dp_rx_process_mon_status.patch @@ -0,0 +1,210 @@ +From 3cd04a438754aaa4297a5561ad9149eda73ce14d Mon Sep 17 00:00:00 2001 +From: Aloka Dixit +Date: Wed, 12 Jan 2022 10:15:10 +0200 +Subject: [PATCH] ath11k: move function ath11k_dp_rx_process_mon_status + +Move the function below ath11k_dp_rx_mon_dest_process() and remove +the forward declaration. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220111032224.14093-2-quic_alokad@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 171 ++++++++++++------------ + 1 file changed, 84 insertions(+), 87 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -20,9 +20,6 @@ + + #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) + +-static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, +- u32 quota, struct napi_struct *napi); +- + static inline + u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) + { +@@ -3093,90 +3090,6 @@ move_next: + return num_buffs_reaped; + } + +-int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, +- struct napi_struct *napi, int budget) +-{ +- struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); +- enum hal_rx_mon_status hal_status; +- struct sk_buff *skb; +- struct sk_buff_head skb_list; +- struct ath11k_peer *peer; +- struct ath11k_sta *arsta; +- int num_buffs_reaped = 0; +- u32 rx_buf_sz; +- u16 log_type = 0; +- struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; +- struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; +- struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; +- +- __skb_queue_head_init(&skb_list); +- +- num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget, +- &skb_list); +- if (!num_buffs_reaped) +- goto exit; +- +- memset(ppdu_info, 0, sizeof(*ppdu_info)); +- ppdu_info->peer_id = HAL_INVALID_PEERID; +- +- while ((skb = __skb_dequeue(&skb_list))) { +- if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { +- log_type = ATH11K_PKTLOG_TYPE_LITE_RX; +- rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; +- } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { +- log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; +- rx_buf_sz = DP_RX_BUFFER_SIZE; +- } +- +- if (log_type) +- trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +- +- hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); +- +- if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && +- pmon->mon_ppdu_status == DP_PPDU_STATUS_START && +- hal_status == HAL_TLV_STATUS_PPDU_DONE) { +- rx_mon_stats->status_ppdu_done++; +- pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; +- ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); +- pmon->mon_ppdu_status = DP_PPDU_STATUS_START; +- } +- +- if (ppdu_info->peer_id == HAL_INVALID_PEERID || +- hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { +- dev_kfree_skb_any(skb); +- continue; +- } +- +- rcu_read_lock(); +- spin_lock_bh(&ab->base_lock); +- peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); +- +- if (!peer || !peer->sta) { +- ath11k_dbg(ab, ATH11K_DBG_DATA, +- "failed to find the peer with peer_id %d\n", +- ppdu_info->peer_id); +- goto next_skb; +- } +- +- arsta = (struct ath11k_sta *)peer->sta->drv_priv; +- ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); +- +- if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) +- trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +- +-next_skb: +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); +- +- dev_kfree_skb_any(skb); +- memset(ppdu_info, 0, sizeof(*ppdu_info)); +- ppdu_info->peer_id = HAL_INVALID_PEERID; +- } +-exit: +- return num_buffs_reaped; +-} +- + static void ath11k_dp_rx_frag_timer(struct timer_list *timer) + { + struct dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); +@@ -5130,6 +5043,90 @@ static void ath11k_dp_rx_mon_dest_proces + } + } + ++int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, ++ struct napi_struct *napi, int budget) ++{ ++ struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); ++ enum hal_rx_mon_status hal_status; ++ struct sk_buff *skb; ++ struct sk_buff_head skb_list; ++ struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; ++ int num_buffs_reaped = 0; ++ u32 rx_buf_sz; ++ u16 log_type = 0; ++ struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; ++ struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; ++ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; ++ ++ __skb_queue_head_init(&skb_list); ++ ++ num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget, ++ &skb_list); ++ if (!num_buffs_reaped) ++ goto exit; ++ ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; ++ ++ while ((skb = __skb_dequeue(&skb_list))) { ++ if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_LITE_RX; ++ rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; ++ } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; ++ rx_buf_sz = DP_RX_BUFFER_SIZE; ++ } ++ ++ if (log_type) ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); ++ ++ hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && ++ pmon->mon_ppdu_status == DP_PPDU_STATUS_START && ++ hal_status == HAL_TLV_STATUS_PPDU_DONE) { ++ rx_mon_stats->status_ppdu_done++; ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; ++ ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_START; ++ } ++ ++ if (ppdu_info->peer_id == HAL_INVALID_PEERID || ++ hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ ++ rcu_read_lock(); ++ spin_lock_bh(&ab->base_lock); ++ peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); ++ ++ if (!peer || !peer->sta) { ++ ath11k_dbg(ab, ATH11K_DBG_DATA, ++ "failed to find the peer with peer_id %d\n", ++ ppdu_info->peer_id); ++ goto next_skb; ++ } ++ ++ arsta = (struct ath11k_sta *)peer->sta->drv_priv; ++ ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); ++ ++ if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); ++ ++next_skb: ++ spin_unlock_bh(&ab->base_lock); ++ rcu_read_unlock(); ++ ++ dev_kfree_skb_any(skb); ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; ++ } ++exit: ++ return num_buffs_reaped; ++} ++ + static u32 + ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, + void *ring_entry, struct sk_buff **head_msdu, diff --git a/package/kernel/mac80211/patches/ath11k/0162-ath11k-fix-error-code-in-ath11k_qmi_assign_target_me.patch b/package/kernel/mac80211/patches/ath11k/0162-ath11k-fix-error-code-in-ath11k_qmi_assign_target_me.patch new file mode 100644 index 000000000..4ed157d67 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0162-ath11k-fix-error-code-in-ath11k_qmi_assign_target_me.patch @@ -0,0 +1,28 @@ +From c9b41832dc080fa59bad597de94865b3ea2d5bab Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 12 Jan 2022 10:15:11 +0200 +Subject: [PATCH] ath11k: fix error code in + ath11k_qmi_assign_target_mem_chunk() + +The "ret" vairable is not set at this point. It could be uninitialized +or zero. The correct thing to return is -ENODEV. + +Fixes: 6ac04bdc5edb ("ath11k: Use reserved host DDR addresses from DT for PCI devices") +Signed-off-by: Dan Carpenter +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220111071445.GA11243@kili +--- + drivers/net/wireless/ath/ath11k/qmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1932,7 +1932,7 @@ static int ath11k_qmi_assign_target_mem_ + if (!hremote_node) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to get hremote_node\n"); +- return ret; ++ return -ENODEV; + } + + ret = of_address_to_resource(hremote_node, 0, &res); diff --git a/package/kernel/mac80211/patches/ath11k/0163-ath11k-Reconfigure-hardware-rate-for-WCN6855-after-v.patch b/package/kernel/mac80211/patches/ath11k/0163-ath11k-Reconfigure-hardware-rate-for-WCN6855-after-v.patch new file mode 100644 index 000000000..f935a2610 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0163-ath11k-Reconfigure-hardware-rate-for-WCN6855-after-v.patch @@ -0,0 +1,68 @@ +From dc7ff75690ea7e1920be08b2b9cc89647667bb90 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 12 Jan 2022 10:54:00 +0800 +Subject: [PATCH] ath11k: Reconfigure hardware rate for WCN6855 after vdev is + started + +There is an issue that WCN6855 tries to connect to an AP using +a hardware rate of 1Mb/s , even though the AP has announced +expected rates as [24, 36, 48, 54] in Probe Response frame. + +The reason is that WCN6855 firmware clears hardware rate info +of management frames when vdev starts and uses 1Mb/s as default. +To solve it, reconfigure the rate after vdev is started. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220112025400.2222-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -603,6 +603,7 @@ struct ath11k { + struct completion finish_11d_ch_list; + bool pending_11d; + bool regdom_set_by_user; ++ int hw_rate_code; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2862,6 +2862,11 @@ static void ath11k_recalculate_mgmt_rate + if (ret) + ath11k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret); + ++ /* For WCN6855, firmware will clear this param when vdev starts, hence ++ * cache it here so that we can reconfigure it once vdev starts. ++ */ ++ ar->hw_rate_code = hw_rate_code; ++ + vdev_param = WMI_VDEV_PARAM_BEACON_RATE; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, + hw_rate_code); +@@ -6960,6 +6965,19 @@ static int ath11k_start_vdev_delay(struc + return ret; + } + ++ /* Reconfigure hardware rate code since it is cleared by firmware. ++ */ ++ if (ar->hw_rate_code > 0) { ++ u32 vdev_param = WMI_VDEV_PARAM_MGMT_RATE; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, ++ ar->hw_rate_code); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret); ++ return ret; ++ } ++ } ++ + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr); + if (ret) { diff --git a/package/kernel/mac80211/patches/ath11k/0164-ath11k-set-WMI_PEER_40MHZ-while-peer-assoc-for-6-GHz.patch b/package/kernel/mac80211/patches/ath11k/0164-ath11k-set-WMI_PEER_40MHZ-while-peer-assoc-for-6-GHz.patch new file mode 100644 index 000000000..b488ef5fb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0164-ath11k-set-WMI_PEER_40MHZ-while-peer-assoc-for-6-GHz.patch @@ -0,0 +1,31 @@ +From 1cb747192de2edb7e55920af8c458e4792908486 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 18 Jan 2022 22:42:11 -0500 +Subject: [PATCH] ath11k: set WMI_PEER_40MHZ while peer assoc for 6 GHz + +When station connect to AP of 6 GHz with 40 MHz bandwidth, the TX is +always stay 20 MHz, it is because the flag WMI_PEER_40MHZ is not set +while peer assoc. Add the flag if remote peer is 40 MHz bandwidth. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Fixes: c3a7d7eb4c98 ("ath11k: add 6 GHz params in peer assoc command") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220119034211.28622-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2319,6 +2319,9 @@ static void ath11k_peer_assoc_h_he_6ghz( + if (!arg->he_flag || band != NL80211_BAND_6GHZ || !sta->he_6ghz_capa.capa) + return; + ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_40) ++ arg->bw_40 = true; ++ + if (sta->bandwidth == IEEE80211_STA_RX_BW_80) + arg->bw_80 = true; + diff --git a/package/kernel/mac80211/patches/ath11k/0165-ath11k-avoid-firmware-crash-when-reg-set-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0165-ath11k-avoid-firmware-crash-when-reg-set-for-QCA6390.patch new file mode 100644 index 000000000..cb83d0c3d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0165-ath11k-avoid-firmware-crash-when-reg-set-for-QCA6390.patch @@ -0,0 +1,136 @@ +From 0d6e997b76216ca104167a2a0fb79823a7fa9e97 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 18 Jan 2022 23:13:55 -0500 +Subject: [PATCH] ath11k: avoid firmware crash when reg set for QCA6390/WCN6855 + +For the NL80211_REGDOM_SET_BY_USER hint from cfg80211, it set the new +alpha2 code to ath11k, then ath11k send WMI_SET_INIT_COUNTRY_CMDID to +firmware for all chips currently. When test with WCN6855/QCA6390 chips, +this WMI CMD leads firmware crash. + +For AP based chips(ipq8074/qcn9074), WMI_SET_INIT_COUNTRY_CMDID is used +to send to firmware, for STATION based chips(WCN6855/QCA6390), it need to +use another WMI CMD WMI_SET_CURRENT_COUNTRY_CMDID. + +Add flag current_cc_support in hardware parameters, it is used to +distinguish AP/STA platform. After that, the firmware will work +normal and the regulatory feature works well for QCA6390/WCN6855. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220119041355.32014-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 ++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/reg.c | 25 +++++++++++++++++-------- + 3 files changed, 24 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -98,6 +98,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, ++ .current_cc_support = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -162,6 +163,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, ++ .current_cc_support = false, + }, + { + .name = "qca6390 hw2.0", +@@ -225,6 +227,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, ++ .current_cc_support = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -288,6 +291,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, ++ .current_cc_support = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -351,6 +355,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, ++ .current_cc_support = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -413,6 +418,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, ++ .current_cc_support = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -192,6 +192,7 @@ struct ath11k_hw_params { + bool wakeup_mhi; + bool supports_rssi_stats; + bool fw_wmi_diag_event; ++ bool current_cc_support; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -48,6 +48,7 @@ ath11k_reg_notifier(struct wiphy *wiphy, + { + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wmi_init_country_params init_country_param; ++ struct wmi_set_current_country_params set_current_param = {}; + struct ath11k *ar = hw->priv; + int ret; + +@@ -76,18 +77,26 @@ ath11k_reg_notifier(struct wiphy *wiphy, + return; + } + +- /* Set the country code to the firmware and wait for ++ /* Set the country code to the firmware and will receive + * the WMI_REG_CHAN_LIST_CC EVENT for updating the + * reg info + */ +- init_country_param.flags = ALPHA_IS_SET; +- memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2); +- init_country_param.cc_info.alpha2[2] = 0; +- +- ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); +- if (ret) +- ath11k_warn(ar->ab, +- "INIT Country code set to fw failed : %d\n", ret); ++ if (ar->ab->hw_params.current_cc_support) { ++ memcpy(&set_current_param.alpha2, request->alpha2, 2); ++ ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed set current country code: %d\n", ret); ++ } else { ++ init_country_param.flags = ALPHA_IS_SET; ++ memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2); ++ init_country_param.cc_info.alpha2[2] = 0; ++ ++ ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "INIT Country code set to fw failed : %d\n", ret); ++ } + + ath11k_mac_11d_scan_stop(ar); + ar->regdom_set_by_user = true; diff --git a/package/kernel/mac80211/patches/ath11k/0166-ath11k-Rename-ath11k_ahb_ext_irq_config.patch b/package/kernel/mac80211/patches/ath11k/0166-ath11k-Rename-ath11k_ahb_ext_irq_config.patch new file mode 100644 index 000000000..c1d4de513 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0166-ath11k-Rename-ath11k_ahb_ext_irq_config.patch @@ -0,0 +1,35 @@ +From a76ed59163ba82462ccb262b4c3590a3c1a115dd Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 19 Jan 2022 14:48:13 +0530 +Subject: [PATCH] ath11k: Rename ath11k_ahb_ext_irq_config + +Rename ath11k_ahb_ext_irq_config() to ath11k_ahb_config_ext_irq() +for just symmetry with ath11k_ahb_free_ext_irq(). + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642583893-21485-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ahb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -466,7 +466,7 @@ static irqreturn_t ath11k_ahb_ext_interr + return IRQ_HANDLED; + } + +-static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) ++static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab) + { + struct ath11k_hw_params *hw = &ab->hw_params; + int i, j; +@@ -574,7 +574,7 @@ static int ath11k_ahb_config_irq(struct + } + + /* Configure external interrupts */ +- ret = ath11k_ahb_ext_irq_config(ab); ++ ret = ath11k_ahb_config_ext_irq(ab); + + return ret; + } diff --git a/package/kernel/mac80211/patches/ath11k/0167-ath11k-fix-kernel-panic-during-unload-load-ath11k-mo.patch b/package/kernel/mac80211/patches/ath11k/0167-ath11k-fix-kernel-panic-during-unload-load-ath11k-mo.patch new file mode 100644 index 000000000..c81c650f8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0167-ath11k-fix-kernel-panic-during-unload-load-ath11k-mo.patch @@ -0,0 +1,55 @@ +From 22b59cb965f79ee1accf83172441c9ca0ecb632a Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 19 Jan 2022 14:49:33 +0530 +Subject: [PATCH] ath11k: fix kernel panic during unload/load ath11k modules + +Call netif_napi_del() from ath11k_ahb_free_ext_irq() to fix +the following kernel panic when unload/load ath11k modules +for few iterations. + +[ 971.201365] Unable to handle kernel paging request at virtual address 6d97a208 +[ 971.204227] pgd = 594c2919 +[ 971.211478] [6d97a208] *pgd=00000000 +[ 971.214120] Internal error: Oops: 5 [#1] PREEMPT SMP ARM +[ 971.412024] CPU: 2 PID: 4435 Comm: insmod Not tainted 5.4.89 #0 +[ 971.434256] Hardware name: Generic DT based system +[ 971.440165] PC is at napi_by_id+0x10/0x40 +[ 971.445019] LR is at netif_napi_add+0x160/0x1dc + +[ 971.743127] (napi_by_id) from [<807d89a0>] (netif_napi_add+0x160/0x1dc) +[ 971.751295] (netif_napi_add) from [<7f1209ac>] (ath11k_ahb_config_irq+0xf8/0x414 [ath11k_ahb]) +[ 971.759164] (ath11k_ahb_config_irq [ath11k_ahb]) from [<7f12135c>] (ath11k_ahb_probe+0x40c/0x51c [ath11k_ahb]) +[ 971.768567] (ath11k_ahb_probe [ath11k_ahb]) from [<80666864>] (platform_drv_probe+0x48/0x94) +[ 971.779670] (platform_drv_probe) from [<80664718>] (really_probe+0x1c8/0x450) +[ 971.789389] (really_probe) from [<80664cc4>] (driver_probe_device+0x15c/0x1b8) +[ 971.797547] (driver_probe_device) from [<80664f60>] (device_driver_attach+0x44/0x60) +[ 971.805795] (device_driver_attach) from [<806650a0>] (__driver_attach+0x124/0x140) +[ 971.814822] (__driver_attach) from [<80662adc>] (bus_for_each_dev+0x58/0xa4) +[ 971.823328] (bus_for_each_dev) from [<80663a2c>] (bus_add_driver+0xf0/0x1e8) +[ 971.831662] (bus_add_driver) from [<806658a4>] (driver_register+0xa8/0xf0) +[ 971.839822] (driver_register) from [<8030269c>] (do_one_initcall+0x78/0x1ac) +[ 971.847638] (do_one_initcall) from [<80392524>] (do_init_module+0x54/0x200) +[ 971.855968] (do_init_module) from [<803945b0>] (load_module+0x1e30/0x1ffc) +[ 971.864126] (load_module) from [<803948b0>] (sys_init_module+0x134/0x17c) +[ 971.871852] (sys_init_module) from [<80301000>] (ret_fast_syscall+0x0/0x50) + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.6.0.1-00760-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642583973-21599-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ahb.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -391,6 +391,8 @@ static void ath11k_ahb_free_ext_irq(stru + + for (j = 0; j < irq_grp->num_irq; j++) + free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); ++ ++ netif_napi_del(&irq_grp->napi); + } + } + diff --git a/package/kernel/mac80211/patches/ath11k/0168-ath11k-Fix-uninitialized-symbol-rx_buf_sz.patch b/package/kernel/mac80211/patches/ath11k/0168-ath11k-Fix-uninitialized-symbol-rx_buf_sz.patch new file mode 100644 index 000000000..ccc13290b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0168-ath11k-Fix-uninitialized-symbol-rx_buf_sz.patch @@ -0,0 +1,57 @@ +From dca857f07dc14c923a3c47965e771f435807b39c Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 19 Jan 2022 20:53:13 +0530 +Subject: [PATCH] ath11k: Fix uninitialized symbol 'rx_buf_sz' + +Add missing else statement in ath11k_dp_rx_process_mon_status() +to fix below smatch warnings, + drivers/net/wireless/ath/ath11k/dp_rx.c:3105 + ath11k_dp_rx_process_mon_status() + error: uninitialized symbol 'rx_buf_sz'. + +Fixes: ab18e3bc1c13 ("ath11k: Fix pktlog lite rx events") + +Reported-by: Dan Carpenter +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642605793-13518-1-git-send-email-quic_akolli@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.h | 1 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 7 +++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -88,6 +88,7 @@ enum ath11k_pktlog_mode { + }; + + enum ath11k_pktlog_enum { ++ ATH11K_PKTLOG_TYPE_INVALID = 0, + ATH11K_PKTLOG_TYPE_TX_CTRL = 1, + ATH11K_PKTLOG_TYPE_TX_STAT = 2, + ATH11K_PKTLOG_TYPE_TX_MSDU_ID = 3, +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -5054,7 +5054,7 @@ int ath11k_dp_rx_process_mon_status(stru + struct ath11k_sta *arsta; + int num_buffs_reaped = 0; + u32 rx_buf_sz; +- u16 log_type = 0; ++ u16 log_type; + struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; + struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; + struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; +@@ -5076,9 +5076,12 @@ int ath11k_dp_rx_process_mon_status(stru + } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { + log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; + rx_buf_sz = DP_RX_BUFFER_SIZE; ++ } else { ++ log_type = ATH11K_PKTLOG_TYPE_INVALID; ++ rx_buf_sz = 0; + } + +- if (log_type) ++ if (log_type != ATH11K_PKTLOG_TYPE_INVALID) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + + hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); diff --git a/package/kernel/mac80211/patches/ath11k/0169-ath11k-Fix-missing-rx_desc_get_ldpc_support-in-wcn68.patch b/package/kernel/mac80211/patches/ath11k/0169-ath11k-Fix-missing-rx_desc_get_ldpc_support-in-wcn68.patch new file mode 100644 index 000000000..1249b4639 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0169-ath11k-Fix-missing-rx_desc_get_ldpc_support-in-wcn68.patch @@ -0,0 +1,67 @@ +From 648ab4720cb76d0b5b1e49d3c0f0bdf28e22e52a Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 26 Jan 2022 09:01:44 +0800 +Subject: [PATCH] ath11k: Fix missing rx_desc_get_ldpc_support in wcn6855_ops + +rx_desc_get_ldpc_support is missing in wcn6855_ops, resulting on WCN6855 a +kernel crash after connecting to an AP and waiting for few minutes. Fix it by +implementing WCN6855's version of this field and adding it to wcn6855_ops. + +Crash stack: +[ 184.862605] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 184.862615] #PF: supervisor instruction fetch in kernel mode +[ 184.862620] #PF: error_code(0x0010) - not-present page +[ 184.862626] PGD 0 P4D 0 +[ 184.862634] Oops: 0010 [#1] PREEMPT SMP PTI +[ 184.862642] CPU: 1 PID: 0 Comm: swapper/1 Kdump: loaded Not tainted 5.16.0-wt-ath+ #1 +[ 184.862651] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0059.2019.1112.1124 11/12/2019 +[ 184.862656] RIP: 0010:0x0 +[ 184.862669] Code: Unable to access opcode bytes at RIP 0xffffffffffffffd6. +[ 184.862673] RSP: 0018:ffff9eedc003cca8 EFLAGS: 00010202 +[ 184.862680] RAX: 0000000000000000 RBX: ffff9eedc003cd30 RCX: 0000000000000002 +[ 184.862686] RDX: 0000000000000002 RSI: ffffffffc1773458 RDI: ffff8eb5843de240 +[ 184.862692] RBP: ffff8eb59685a0e0 R08: 0000000000000001 R09: ffff8eb6fef2b000 +[ 184.862700] R10: ffff9eedc003cd70 R11: ffff8eb5880a9ff0 R12: ffff8eb5843de240 +[ 184.862707] R13: 0000000000000000 R14: 0000000000000008 R15: 0000000000000003 +[ 184.862714] FS: 0000000000000000(0000) GS:ffff8eb6f6c40000(0000) knlGS:0000000000000000 +[ 184.862723] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 184.862733] CR2: ffffffffffffffd6 CR3: 000000002f60a001 CR4: 00000000003706e0 +[ 184.862743] Call Trace: +[ 184.862751] +[ 184.862759] ath11k_dp_rx_h_ppdu+0x210/0x350 [ath11k] +[ 184.862841] ath11k_dp_rx_process_received_packets+0x1e6/0x6b0 [ath11k] +[ 184.862891] ath11k_dp_process_rx+0x32d/0x3e0 [ath11k] + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Fixes: b3febdccde3e ("ath11k: add LDPC FEC type in 802.11 radiotap header") +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220126010144.2090-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/hw.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -813,6 +813,12 @@ static u16 ath11k_hw_wcn6855_mpdu_info_g + return peer_id; + } + ++static bool ath11k_hw_wcn6855_rx_desc_get_ldpc_support(struct hal_rx_desc *desc) ++{ ++ return FIELD_GET(RX_MSDU_START_INFO2_LDPC, ++ __le32_to_cpu(desc->u.wcn6855.msdu_start.info2)); ++} ++ + const struct ath11k_hw_ops ipq8074_ops = { + .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, + .wmi_init_config = ath11k_init_wmi_config_ipq8074, +@@ -983,6 +989,7 @@ const struct ath11k_hw_ops wcn6855_ops = + .rx_desc_get_encrypt_type = ath11k_hw_wcn6855_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_wcn6855_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_wcn6855_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_wcn6855_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_wcn6855_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_wcn6855_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_wcn6855_rx_desc_get_mpdu_start_seq_no, diff --git a/package/kernel/mac80211/patches/ath11k/0170-ath11k-pci-fix-crash-on-suspend-if-board-file-is-not.patch b/package/kernel/mac80211/patches/ath11k/0170-ath11k-pci-fix-crash-on-suspend-if-board-file-is-not.patch new file mode 100644 index 000000000..436f7e47b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0170-ath11k-pci-fix-crash-on-suspend-if-board-file-is-not.patch @@ -0,0 +1,84 @@ +From b4f4c56459a5c744f7f066b9fc2b54ea995030c5 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Thu, 27 Jan 2022 11:01:16 +0200 +Subject: [PATCH] ath11k: pci: fix crash on suspend if board file is not found + +Mario reported that the kernel was crashing on suspend if ath11k was not able +to find a board file: + +[ 473.693286] PM: Suspending system (s2idle) +[ 473.693291] printk: Suspending console(s) (use no_console_suspend to debug) +[ 474.407787] BUG: unable to handle page fault for address: 0000000000002070 +[ 474.407791] #PF: supervisor read access in kernel mode +[ 474.407794] #PF: error_code(0x0000) - not-present page +[ 474.407798] PGD 0 P4D 0 +[ 474.407801] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 474.407805] CPU: 2 PID: 2350 Comm: kworker/u32:14 Tainted: G W 5.16.0 #248 +[...] +[ 474.407868] Call Trace: +[ 474.407870] +[ 474.407874] ? _raw_spin_lock_irqsave+0x2a/0x60 +[ 474.407882] ? lock_timer_base+0x72/0xa0 +[ 474.407889] ? _raw_spin_unlock_irqrestore+0x29/0x3d +[ 474.407892] ? try_to_del_timer_sync+0x54/0x80 +[ 474.407896] ath11k_dp_rx_pktlog_stop+0x49/0xc0 [ath11k] +[ 474.407912] ath11k_core_suspend+0x34/0x130 [ath11k] +[ 474.407923] ath11k_pci_pm_suspend+0x1b/0x50 [ath11k_pci] +[ 474.407928] pci_pm_suspend+0x7e/0x170 +[ 474.407935] ? pci_pm_freeze+0xc0/0xc0 +[ 474.407939] dpm_run_callback+0x4e/0x150 +[ 474.407947] __device_suspend+0x148/0x4c0 +[ 474.407951] async_suspend+0x20/0x90 +dmesg-efi-164255130401001: +Oops#1 Part1 +[ 474.407955] async_run_entry_fn+0x33/0x120 +[ 474.407959] process_one_work+0x220/0x3f0 +[ 474.407966] worker_thread+0x4a/0x3d0 +[ 474.407971] kthread+0x17a/0x1a0 +[ 474.407975] ? process_one_work+0x3f0/0x3f0 +[ 474.407979] ? set_kthread_struct+0x40/0x40 +[ 474.407983] ret_from_fork+0x22/0x30 +[ 474.407991] + +The issue here is that board file loading happens after ath11k_pci_probe() +succesfully returns (ath11k initialisation happends asynchronously) and the +suspend handler is still enabled, of course failing as ath11k is not properly +initialised. Fix this by checking ATH11K_FLAG_QMI_FAIL during both suspend and +resume. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Reported-by: Mario Limonciello +Link: https://bugzilla.kernel.org/show_bug.cgi?id=215504 +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220127090117.2024-1-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -1571,6 +1571,11 @@ static __maybe_unused int ath11k_pci_pm_ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + ++ if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n"); ++ return 0; ++ } ++ + ret = ath11k_core_suspend(ab); + if (ret) + ath11k_warn(ab, "failed to suspend core: %d\n", ret); +@@ -1583,6 +1588,11 @@ static __maybe_unused int ath11k_pci_pm_ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + ++ if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n"); ++ return 0; ++ } ++ + ret = ath11k_core_resume(ab); + if (ret) + ath11k_warn(ab, "failed to resume core: %d\n", ret); diff --git a/package/kernel/mac80211/patches/ath11k/0171-ath11k-mhi-use-mhi_sync_power_up.patch b/package/kernel/mac80211/patches/ath11k/0171-ath11k-mhi-use-mhi_sync_power_up.patch new file mode 100644 index 000000000..6e23d989c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0171-ath11k-mhi-use-mhi_sync_power_up.patch @@ -0,0 +1,77 @@ +From 3df6d74aedfdca919cca475d15dfdbc8b05c9e5d Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Thu, 27 Jan 2022 11:01:17 +0200 +Subject: [PATCH] ath11k: mhi: use mhi_sync_power_up() + +If amss.bin was missing ath11k would crash during 'rmmod ath11k_pci'. The +reason for that was that we were using mhi_async_power_up() which does not +check any errors. But mhi_sync_power_up() on the other hand does check for +errors so let's use that to fix the crash. + +I was not able to find a reason why an async version was used. +ath11k_mhi_start() (which enables state ATH11K_MHI_POWER_ON) is called from +ath11k_hif_power_up(), which can sleep. So sync version should be safe to use +here. + +[ 145.569731] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN PTI +[ 145.569789] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +[ 145.569843] CPU: 2 PID: 1628 Comm: rmmod Kdump: loaded Tainted: G W 5.16.0-wt-ath+ #567 +[ 145.569898] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 145.569956] RIP: 0010:ath11k_hal_srng_access_begin+0xb5/0x2b0 [ath11k] +[ 145.570028] Code: df 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 ec 01 00 00 48 8b ab a8 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 ea 48 c1 ea 03 <0f> b6 14 02 48 89 e8 83 e0 07 83 c0 03 45 85 ed 75 48 38 d0 7c 08 +[ 145.570089] RSP: 0018:ffffc900025d7ac0 EFLAGS: 00010246 +[ 145.570144] RAX: dffffc0000000000 RBX: ffff88814fca2dd8 RCX: 1ffffffff50cb455 +[ 145.570196] RDX: 0000000000000000 RSI: ffff88814fca2dd8 RDI: ffff88814fca2e80 +[ 145.570252] RBP: 0000000000000000 R08: 0000000000000000 R09: ffffffffa8659497 +[ 145.570329] R10: fffffbfff50cb292 R11: 0000000000000001 R12: ffff88814fca0000 +[ 145.570410] R13: 0000000000000000 R14: ffff88814fca2798 R15: ffff88814fca2dd8 +[ 145.570465] FS: 00007fa399988540(0000) GS:ffff888233e00000(0000) knlGS:0000000000000000 +[ 145.570519] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 145.570571] CR2: 00007fa399b51421 CR3: 0000000137898002 CR4: 00000000003706e0 +[ 145.570623] Call Trace: +[ 145.570675] +[ 145.570727] ? ath11k_ce_tx_process_cb+0x34b/0x860 [ath11k] +[ 145.570797] ath11k_ce_tx_process_cb+0x356/0x860 [ath11k] +[ 145.570864] ? tasklet_init+0x150/0x150 +[ 145.570919] ? ath11k_ce_alloc_pipes+0x280/0x280 [ath11k] +[ 145.570986] ? tasklet_clear_sched+0x42/0xe0 +[ 145.571042] ? tasklet_kill+0xe9/0x1b0 +[ 145.571095] ? tasklet_clear_sched+0xe0/0xe0 +[ 145.571148] ? irq_has_action+0x120/0x120 +[ 145.571202] ath11k_ce_cleanup_pipes+0x45a/0x580 [ath11k] +[ 145.571270] ? ath11k_pci_stop+0x10e/0x170 [ath11k_pci] +[ 145.571345] ath11k_core_stop+0x8a/0xc0 [ath11k] +[ 145.571434] ath11k_core_deinit+0x9e/0x150 [ath11k] +[ 145.571499] ath11k_pci_remove+0xd2/0x260 [ath11k_pci] +[ 145.571553] pci_device_remove+0x9a/0x1c0 +[ 145.571605] __device_release_driver+0x332/0x660 +[ 145.571659] driver_detach+0x1e7/0x2c0 +[ 145.571712] bus_remove_driver+0xe2/0x2d0 +[ 145.571772] pci_unregister_driver+0x21/0x250 +[ 145.571826] __do_sys_delete_module+0x30a/0x4b0 +[ 145.571879] ? free_module+0xac0/0xac0 +[ 145.571933] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 145.571986] ? syscall_enter_from_user_mode+0x1d/0x50 +[ 145.572039] ? lockdep_hardirqs_on+0x79/0x100 +[ 145.572097] do_syscall_64+0x3b/0x90 +[ 145.572153] entry_SYSCALL_64_after_hwframe+0x44/0xae + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220127090117.2024-2-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -563,7 +563,7 @@ static int ath11k_mhi_set_state(struct a + ret = 0; + break; + case ATH11K_MHI_POWER_ON: +- ret = mhi_async_power_up(ab_pci->mhi_ctrl); ++ ret = mhi_sync_power_up(ab_pci->mhi_ctrl); + break; + case ATH11K_MHI_POWER_OFF: + mhi_power_down(ab_pci->mhi_ctrl, true); diff --git a/package/kernel/mac80211/patches/ath11k/0172-ath11k-Add-debugfs-interface-to-configure-firmware-d.patch b/package/kernel/mac80211/patches/ath11k/0172-ath11k-Add-debugfs-interface-to-configure-firmware-d.patch new file mode 100644 index 000000000..3c4c3bed6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0172-ath11k-Add-debugfs-interface-to-configure-firmware-d.patch @@ -0,0 +1,404 @@ +From f295ad912910e08d9b887a0c952f82d9612459d4 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Mon, 31 Jan 2022 16:16:44 +0200 +Subject: [PATCH] ath11k: Add debugfs interface to configure firmware debug log + level + +Add debugfs interface "fw_dbglog_config" to configure firmware log level. +Configuration is done via WMI command WMI_DBGLOG_CFG_CMDID. + +Command to configure, +echo " " > +/sys/kernel/debug/ath11k//macX/fw_dbglog_config + +where dbglog_param can be, + 1) WMI_DEBUG_LOG_PARAM_LOG_LEVEL - configure log level for a given module + here, = <0xaaaa00bb>, 'aaaa' - module id and 'bb' - loglevel + 2) WMI_DEBUG_LOG_PARAM_VDEV_ENABLE - enable debug log for a given vdev + here, = vdev_id + 3) WMI_DEBUG_LOG_PARAM_VDEV_DISABLE - disable debug log for a given vdev + except ERROR logs + here, = vdev_id + 4) WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP - set vdev enable bitmap + here, = vdev_enable_bitmap + 5) WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP - set a given log level to all the + modules specified in the module bitmap. Command to configure for this log param, + + $ echo "5 " > + /sys/kernel/debug/ath11k//macX/fw_dbglog_config + here, + = <0xaaaaaaaa000000bb>, 'aaaaaaaa' - module bitmap and + 'bb' - loglevel + = index of module bitmap. Max module id is 512. + So, module_id_index is 0-15. + = to indicate if more configuration to follow. + + 6) WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP - Wow mode specific logging enable. + Command to configure for this log param, + + $ echo "6 " > + /sys/kernel/debug/ath11k//macX/fw_dbglog_config + here, + = <0xaaaaaaaa000000bb>, 'aaaaaaaa' - module bitmap and + 'bb' - loglevel + = index of module bitmap. Max module id is 512. + So, module_id_index is 0-15. + = to indicate if more configuration to follow. + +Sample command usage, + +To enable module WLAN_MODULE_WMI and log level ATH11K_FW_DBGLOG_VERBOSE, +echo "1 0x10001" > /sys/kernel/debug/ath11k//macX/fw_dbglog_config + +To enable module bit map from 32 to 63 and log level ATH11K_FW_DBGLOG_VERBOSE, +echo "5 0xffffffff00000001 1 1" > /sys/kernel/debug/ath11k//macX/fw_dbglog_config + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642405103-32302-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 4 + + drivers/net/wireless/ath/ath11k/debugfs.c | 66 ++++++++++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 124 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 53 +++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 18 ++++ + 5 files changed, 265 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -441,6 +441,8 @@ struct ath11k_dbg_htt_stats { + spinlock_t lock; + }; + ++#define MAX_MODULE_ID_BITMAP_WORDS 16 ++ + struct ath11k_debug { + struct dentry *debugfs_pdev; + struct ath11k_dbg_htt_stats htt_stats; +@@ -454,6 +456,8 @@ struct ath11k_debug { + u32 pktlog_peer_valid; + u8 pktlog_peer_addr[ETH_ALEN]; + u32 rx_filter; ++ u32 mem_offset; ++ u32 module_id_bitmap[MAX_MODULE_ID_BITMAP_WORDS]; + }; + + struct ath11k_per_peer_tx_stats { +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -876,6 +876,69 @@ static const struct file_operations fops + .llseek = default_llseek, + }; + ++static ssize_t ath11k_write_fw_dbglog(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k *ar = file->private_data; ++ char buf[128] = {0}; ++ struct ath11k_fw_dbglog dbglog; ++ unsigned int param, mod_id_index, is_end; ++ u64 value; ++ int ret, num; ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ++ user_buf, count); ++ if (ret <= 0) ++ return ret; ++ ++ num = sscanf(buf, "%u %llx %u %u", ¶m, &value, &mod_id_index, &is_end); ++ ++ if (num < 2) ++ return -EINVAL; ++ ++ mutex_lock(&ar->conf_mutex); ++ if (param == WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP || ++ param == WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP) { ++ if (num != 4 || mod_id_index > (MAX_MODULE_ID_BITMAP_WORDS - 1)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ar->debug.module_id_bitmap[mod_id_index] = upper_32_bits(value); ++ if (!is_end) { ++ ret = count; ++ goto out; ++ } ++ } else { ++ if (num != 2) { ++ ret = -EINVAL; ++ goto out; ++ } ++ } ++ ++ dbglog.param = param; ++ dbglog.value = lower_32_bits(value); ++ ret = ath11k_wmi_fw_dbglog_cfg(ar, ar->debug.module_id_bitmap, &dbglog); ++ if (ret) { ++ ath11k_warn(ar->ab, "fw dbglog config failed from debugfs: %d\n", ++ ret); ++ goto out; ++ } ++ ++ ret = count; ++ ++out: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++} ++ ++static const struct file_operations fops_fw_dbglog = { ++ .write = ath11k_write_fw_dbglog, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ + int ath11k_debugfs_pdev_create(struct ath11k_base *ab) + { + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) +@@ -1142,6 +1205,9 @@ int ath11k_debugfs_register(struct ath11 + debugfs_create_file("pktlog_filter", 0644, + ar->debug.debugfs_pdev, ar, + &fops_pktlog_filter); ++ debugfs_create_file("fw_dbglog_config", 0600, ++ ar->debug.debugfs_pdev, ar, ++ &fops_fw_dbglog); + + if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) { + debugfs_create_file("dfs_simulate_radar", 0200, +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -108,6 +108,130 @@ enum ath11k_dbg_aggr_mode { + ATH11K_DBG_AGGR_MODE_MAX, + }; + ++enum fw_dbglog_wlan_module_id { ++ WLAN_MODULE_ID_MIN = 0, ++ WLAN_MODULE_INF = WLAN_MODULE_ID_MIN, ++ WLAN_MODULE_WMI, ++ WLAN_MODULE_STA_PWRSAVE, ++ WLAN_MODULE_WHAL, ++ WLAN_MODULE_COEX, ++ WLAN_MODULE_ROAM, ++ WLAN_MODULE_RESMGR_CHAN_MANAGER, ++ WLAN_MODULE_RESMGR, ++ WLAN_MODULE_VDEV_MGR, ++ WLAN_MODULE_SCAN, ++ WLAN_MODULE_RATECTRL, ++ WLAN_MODULE_AP_PWRSAVE, ++ WLAN_MODULE_BLOCKACK, ++ WLAN_MODULE_MGMT_TXRX, ++ WLAN_MODULE_DATA_TXRX, ++ WLAN_MODULE_HTT, ++ WLAN_MODULE_HOST, ++ WLAN_MODULE_BEACON, ++ WLAN_MODULE_OFFLOAD, ++ WLAN_MODULE_WAL, ++ WLAN_WAL_MODULE_DE, ++ WLAN_MODULE_PCIELP, ++ WLAN_MODULE_RTT, ++ WLAN_MODULE_RESOURCE, ++ WLAN_MODULE_DCS, ++ WLAN_MODULE_CACHEMGR, ++ WLAN_MODULE_ANI, ++ WLAN_MODULE_P2P, ++ WLAN_MODULE_CSA, ++ WLAN_MODULE_NLO, ++ WLAN_MODULE_CHATTER, ++ WLAN_MODULE_WOW, ++ WLAN_MODULE_WAL_VDEV, ++ WLAN_MODULE_WAL_PDEV, ++ WLAN_MODULE_TEST, ++ WLAN_MODULE_STA_SMPS, ++ WLAN_MODULE_SWBMISS, ++ WLAN_MODULE_WMMAC, ++ WLAN_MODULE_TDLS, ++ WLAN_MODULE_HB, ++ WLAN_MODULE_TXBF, ++ WLAN_MODULE_BATCH_SCAN, ++ WLAN_MODULE_THERMAL_MGR, ++ WLAN_MODULE_PHYERR_DFS, ++ WLAN_MODULE_RMC, ++ WLAN_MODULE_STATS, ++ WLAN_MODULE_NAN, ++ WLAN_MODULE_IBSS_PWRSAVE, ++ WLAN_MODULE_HIF_UART, ++ WLAN_MODULE_LPI, ++ WLAN_MODULE_EXTSCAN, ++ WLAN_MODULE_UNIT_TEST, ++ WLAN_MODULE_MLME, ++ WLAN_MODULE_SUPPL, ++ WLAN_MODULE_ERE, ++ WLAN_MODULE_OCB, ++ WLAN_MODULE_RSSI_MONITOR, ++ WLAN_MODULE_WPM, ++ WLAN_MODULE_CSS, ++ WLAN_MODULE_PPS, ++ WLAN_MODULE_SCAN_CH_PREDICT, ++ WLAN_MODULE_MAWC, ++ WLAN_MODULE_CMC_QMIC, ++ WLAN_MODULE_EGAP, ++ WLAN_MODULE_NAN20, ++ WLAN_MODULE_QBOOST, ++ WLAN_MODULE_P2P_LISTEN_OFFLOAD, ++ WLAN_MODULE_HALPHY, ++ WLAN_WAL_MODULE_ENQ, ++ WLAN_MODULE_GNSS, ++ WLAN_MODULE_WAL_MEM, ++ WLAN_MODULE_SCHED_ALGO, ++ WLAN_MODULE_TX, ++ WLAN_MODULE_RX, ++ WLAN_MODULE_WLM, ++ WLAN_MODULE_RU_ALLOCATOR, ++ WLAN_MODULE_11K_OFFLOAD, ++ WLAN_MODULE_STA_TWT, ++ WLAN_MODULE_AP_TWT, ++ WLAN_MODULE_UL_OFDMA, ++ WLAN_MODULE_HPCS_PULSE, ++ WLAN_MODULE_DTF, ++ WLAN_MODULE_QUIET_IE, ++ WLAN_MODULE_SHMEM_MGR, ++ WLAN_MODULE_CFIR, ++ WLAN_MODULE_CODE_COVER, ++ WLAN_MODULE_SHO, ++ WLAN_MODULE_MLO_MGR, ++ WLAN_MODULE_PEER_INIT, ++ WLAN_MODULE_STA_MLO_PS, ++ ++ WLAN_MODULE_ID_MAX, ++ WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, ++}; ++ ++enum fw_dbglog_log_level { ++ ATH11K_FW_DBGLOG_ML = 0, ++ ATH11K_FW_DBGLOG_VERBOSE = 0, ++ ATH11K_FW_DBGLOG_INFO, ++ ATH11K_FW_DBGLOG_INFO_LVL_1, ++ ATH11K_FW_DBGLOG_INFO_LVL_2, ++ ATH11K_FW_DBGLOG_WARN, ++ ATH11K_FW_DBGLOG_ERR, ++ ATH11K_FW_DBGLOG_LVL_MAX ++}; ++ ++struct ath11k_fw_dbglog { ++ enum wmi_debug_log_param param; ++ union { ++ struct { ++ /* log_level values are given in enum fw_dbglog_log_level */ ++ u16 log_level; ++ /* module_id values are given in enum fw_dbglog_wlan_module_id */ ++ u16 module_id; ++ }; ++ /* value is either log_level&module_id/vdev_id/vdev_id_bitmap/log_level ++ * according to param ++ */ ++ u32 value; ++ }; ++}; ++ + #ifdef CPTCFG_ATH11K_DEBUGFS + int ath11k_debugfs_soc_create(struct ath11k_base *ab); + void ath11k_debugfs_soc_destroy(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7798,6 +7798,59 @@ int ath11k_wmi_simulate_radar(struct ath + return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args); + } + ++int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, ++ struct ath11k_fw_dbglog *dbglog) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_debug_log_config_cmd_fixed_param *cmd; ++ struct sk_buff *skb; ++ struct wmi_tlv *tlv; ++ int ret, len; ++ ++ len = sizeof(*cmd) + TLV_HDR_SIZE + (MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_debug_log_config_cmd_fixed_param *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_DEBUG_LOG_CONFIG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ cmd->dbg_log_param = dbglog->param; ++ ++ tlv = (struct wmi_tlv *)((u8 *)cmd + sizeof(*cmd)); ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) | ++ FIELD_PREP(WMI_TLV_LEN, MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ ++ switch (dbglog->param) { ++ case WMI_DEBUG_LOG_PARAM_LOG_LEVEL: ++ case WMI_DEBUG_LOG_PARAM_VDEV_ENABLE: ++ case WMI_DEBUG_LOG_PARAM_VDEV_DISABLE: ++ case WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP: ++ cmd->value = dbglog->value; ++ break; ++ case WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP: ++ case WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP: ++ cmd->value = dbglog->value; ++ memcpy(tlv->value, module_id_bitmap, ++ MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ /* clear current config to be used for next user config */ ++ memset(module_id_bitmap, 0, ++ MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ break; ++ default: ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_DBGLOG_CFG_CMDID); ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_DBGLOG_CFG_CMDID\n"); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ + int ath11k_wmi_connect(struct ath11k_base *ab) + { + u32 i; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -12,6 +12,7 @@ + struct ath11k_base; + struct ath11k; + struct ath11k_fw_stats; ++struct ath11k_fw_dbglog; + + #define PSOC_HOST_MAX_NUM_SS (8) + +@@ -5240,6 +5241,21 @@ struct wmi_rfkill_state_change_ev { + u32 radio_state; + } __packed; + ++enum wmi_debug_log_param { ++ WMI_DEBUG_LOG_PARAM_LOG_LEVEL = 0x1, ++ WMI_DEBUG_LOG_PARAM_VDEV_ENABLE, ++ WMI_DEBUG_LOG_PARAM_VDEV_DISABLE, ++ WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP, ++ WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP, ++ WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP, ++}; ++ ++struct wmi_debug_log_config_cmd_fixed_param { ++ u32 tlv_header; ++ u32 dbg_log_param; ++ u32 value; ++} __packed; ++ + #define WMI_MAX_MEM_REQS 32 + + #define MAX_RADIOS 3 +@@ -5582,4 +5598,6 @@ int ath11k_wmi_wow_host_wakeup_ind(struc + int ath11k_wmi_wow_enable(struct ath11k *ar); + int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, + const u8 mac_addr[ETH_ALEN]); ++int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, ++ struct ath11k_fw_dbglog *dbglog); + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0173-ath11k-add-WMI-calls-to-manually-add-del-pause-resum.patch b/package/kernel/mac80211/patches/ath11k/0173-ath11k-add-WMI-calls-to-manually-add-del-pause-resum.patch new file mode 100644 index 000000000..596edee35 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0173-ath11k-add-WMI-calls-to-manually-add-del-pause-resum.patch @@ -0,0 +1,455 @@ +From 3d00e8b5b818266f43d1fabdb961e215cab45dfb Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 31 Jan 2022 16:16:44 +0200 +Subject: [PATCH] ath11k: add WMI calls to manually add/del/pause/resume TWT + dialogs + +These calls are used for debugging and will be required for WFA +certification tests. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: John Crispin +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220131031043.1295-1-alokad@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 247 ++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/wmi.h | 114 ++++++++++++ + 3 files changed, 358 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -608,6 +608,7 @@ struct ath11k { + bool pending_11d; + bool regdom_set_by_user; + int hw_rate_code; ++ u8 twt_enabled; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -144,6 +144,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, + [WMI_TAG_PER_CHAIN_RSSI_STATS] = { + .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, ++ [WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = { ++ .min_len = sizeof(struct wmi_twt_add_dialog_event) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -3085,11 +3087,12 @@ ath11k_wmi_send_twt_enable_cmd(struct at + /* TODO add MBSSID support */ + cmd->mbss_support = 0; + +- ret = ath11k_wmi_cmd_send(wmi, skb, +- WMI_TWT_ENABLE_CMDID); ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ENABLE_CMDID); + if (ret) { + ath11k_warn(ab, "Failed to send WMI_TWT_ENABLE_CMDID"); + dev_kfree_skb(skb); ++ } else { ++ ar->twt_enabled = 1; + } + return ret; + } +@@ -3114,11 +3117,181 @@ ath11k_wmi_send_twt_disable_cmd(struct a + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + cmd->pdev_id = pdev_id; + +- ret = ath11k_wmi_cmd_send(wmi, skb, +- WMI_TWT_DISABLE_CMDID); ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DISABLE_CMDID); + if (ret) { + ath11k_warn(ab, "Failed to send WMI_TWT_DISABLE_CMDID"); + dev_kfree_skb(skb); ++ } else { ++ ar->twt_enabled = 0; ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_add_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_add_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_add_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_ADD_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ cmd->wake_intvl_us = params->wake_intvl_us; ++ cmd->wake_intvl_mantis = params->wake_intvl_mantis; ++ cmd->wake_dura_us = params->wake_dura_us; ++ cmd->sp_offset_us = params->sp_offset_us; ++ cmd->flags = params->twt_cmd; ++ if (params->flag_bcast) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_BCAST; ++ if (params->flag_trigger) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_TRIGGER; ++ if (params->flag_flow_type) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_FLOW_TYPE; ++ if (params->flag_protection) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_PROTECTION; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi add twt dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", ++ cmd->vdev_id, cmd->dialog_id, cmd->wake_intvl_us, ++ cmd->wake_intvl_mantis, cmd->wake_dura_us, cmd->sp_offset_us, ++ cmd->flags); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ADD_DIALOG_CMDID); ++ ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to add twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_del_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_del_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_del_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_DEL_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi delete twt dialog vdev %u dialog id %u\n", ++ cmd->vdev_id, cmd->dialog_id); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DEL_DIALOG_CMDID); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to delete twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_pause_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_pause_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_pause_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_TWT_PAUSE_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi pause twt dialog vdev %u dialog id %u\n", ++ cmd->vdev_id, cmd->dialog_id); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_PAUSE_DIALOG_CMDID); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to pause twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_resume_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_resume_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_resume_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_TWT_RESUME_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ cmd->sp_offset_us = params->sp_offset_us; ++ cmd->next_twt_size = params->next_twt_size; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi resume twt dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", ++ cmd->vdev_id, cmd->dialog_id, cmd->sp_offset_us, ++ cmd->next_twt_size); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_RESUME_DIALOG_CMDID); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to resume twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); + } + return ret; + } +@@ -7532,6 +7705,66 @@ ath11k_wmi_diag_event(struct ath11k_base + trace_ath11k_wmi_diag(ab, skb->data, skb->len); + } + ++static const char *ath11k_wmi_twt_add_dialog_event_status(u32 status) ++{ ++ switch (status) { ++ case WMI_ADD_TWT_STATUS_OK: ++ return "ok"; ++ case WMI_ADD_TWT_STATUS_TWT_NOT_ENABLED: ++ return "twt disabled"; ++ case WMI_ADD_TWT_STATUS_USED_DIALOG_ID: ++ return "dialog id in use"; ++ case WMI_ADD_TWT_STATUS_INVALID_PARAM: ++ return "invalid parameters"; ++ case WMI_ADD_TWT_STATUS_NOT_READY: ++ return "not ready"; ++ case WMI_ADD_TWT_STATUS_NO_RESOURCE: ++ return "resource unavailable"; ++ case WMI_ADD_TWT_STATUS_NO_ACK: ++ return "no ack"; ++ case WMI_ADD_TWT_STATUS_NO_RESPONSE: ++ return "no response"; ++ case WMI_ADD_TWT_STATUS_DENIED: ++ return "denied"; ++ case WMI_ADD_TWT_STATUS_UNKNOWN_ERROR: ++ fallthrough; ++ default: ++ return "unknown error"; ++ } ++} ++ ++static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ const void **tb; ++ const struct wmi_twt_add_dialog_event *ev; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, ++ "failed to parse wmi twt add dialog status event tlv: %d\n", ++ ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT]; ++ if (!ev) { ++ ath11k_warn(ab, "failed to fetch twt add dialog wmi event\n"); ++ goto exit; ++ } ++ ++ if (ev->status) ++ ath11k_warn(ab, ++ "wmi add twt dialog event vdev %d dialog id %d status %s\n", ++ ev->vdev_id, ev->dialog_id, ++ ath11k_wmi_twt_add_dialog_event_status(ev->status)); ++ ++exit: ++ kfree(tb); ++} ++ + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) + { + struct wmi_cmd_hdr *cmd_hdr; +@@ -7629,11 +7862,17 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: + ath11k_wmi_obss_color_collision_event(ab, skb); + break; ++ case WMI_TWT_ADD_DIALOG_EVENTID: ++ ath11k_wmi_twt_add_dialog_event(ab, skb); ++ break; + /* add Unsupported events here */ + case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: + case WMI_PEER_OPER_MODE_CHANGE_EVENTID: + case WMI_TWT_ENABLE_EVENTID: + case WMI_TWT_DISABLE_EVENTID: ++ case WMI_TWT_DEL_DIALOG_EVENTID: ++ case WMI_TWT_PAUSE_DIALOG_EVENTID: ++ case WMI_TWT_RESUME_DIALOG_EVENTID: + case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: + case WMI_PEER_CREATE_CONF_EVENTID: + ath11k_dbg(ab, ATH11K_DBG_WMI, +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4953,6 +4953,112 @@ struct wmi_twt_disable_params_cmd { + u32 pdev_id; + } __packed; + ++enum WMI_HOST_TWT_COMMAND { ++ WMI_HOST_TWT_COMMAND_REQUEST_TWT = 0, ++ WMI_HOST_TWT_COMMAND_SUGGEST_TWT, ++ WMI_HOST_TWT_COMMAND_DEMAND_TWT, ++ WMI_HOST_TWT_COMMAND_TWT_GROUPING, ++ WMI_HOST_TWT_COMMAND_ACCEPT_TWT, ++ WMI_HOST_TWT_COMMAND_ALTERNATE_TWT, ++ WMI_HOST_TWT_COMMAND_DICTATE_TWT, ++ WMI_HOST_TWT_COMMAND_REJECT_TWT, ++}; ++ ++#define WMI_TWT_ADD_DIALOG_FLAG_BCAST BIT(8) ++#define WMI_TWT_ADD_DIALOG_FLAG_TRIGGER BIT(9) ++#define WMI_TWT_ADD_DIALOG_FLAG_FLOW_TYPE BIT(10) ++#define WMI_TWT_ADD_DIALOG_FLAG_PROTECTION BIT(11) ++ ++struct wmi_twt_add_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++ u32 wake_intvl_us; ++ u32 wake_intvl_mantis; ++ u32 wake_dura_us; ++ u32 sp_offset_us; ++ u32 flags; ++} __packed; ++ ++struct wmi_twt_add_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++ u32 wake_intvl_us; ++ u32 wake_intvl_mantis; ++ u32 wake_dura_us; ++ u32 sp_offset_us; ++ u8 twt_cmd; ++ u8 flag_bcast; ++ u8 flag_trigger; ++ u8 flag_flow_type; ++ u8 flag_protection; ++} __packed; ++ ++enum wmi_twt_add_dialog_status { ++ WMI_ADD_TWT_STATUS_OK, ++ WMI_ADD_TWT_STATUS_TWT_NOT_ENABLED, ++ WMI_ADD_TWT_STATUS_USED_DIALOG_ID, ++ WMI_ADD_TWT_STATUS_INVALID_PARAM, ++ WMI_ADD_TWT_STATUS_NOT_READY, ++ WMI_ADD_TWT_STATUS_NO_RESOURCE, ++ WMI_ADD_TWT_STATUS_NO_ACK, ++ WMI_ADD_TWT_STATUS_NO_RESPONSE, ++ WMI_ADD_TWT_STATUS_DENIED, ++ WMI_ADD_TWT_STATUS_UNKNOWN_ERROR, ++}; ++ ++struct wmi_twt_add_dialog_event { ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++ u32 status; ++} __packed; ++ ++struct wmi_twt_del_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_del_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_pause_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_pause_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_resume_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++ u32 sp_offset_us; ++ u32 next_twt_size; ++} __packed; ++ ++struct wmi_twt_resume_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++ u32 sp_offset_us; ++ u32 next_twt_size; ++} __packed; ++ + struct wmi_obss_spatial_reuse_params_cmd { + u32 tlv_header; + u32 pdev_id; +@@ -5562,6 +5668,14 @@ void ath11k_wmi_fw_stats_fill(struct ath + int ath11k_wmi_simulate_radar(struct ath11k *ar); + int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id); + int ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id); ++int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_add_dialog_params *params); ++int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_del_dialog_params *params); ++int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_pause_dialog_params *params); ++int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_resume_dialog_params *params); + int ath11k_wmi_send_obss_spr_cmd(struct ath11k *ar, u32 vdev_id, + struct ieee80211_he_obss_pd *he_obss_pd); + int ath11k_wmi_pdev_set_srg_bss_color_bitmap(struct ath11k *ar, u32 *bitmap); diff --git a/package/kernel/mac80211/patches/ath11k/0174-ath11k-add-debugfs-for-TWT-debug-calls.patch b/package/kernel/mac80211/patches/ath11k/0174-ath11k-add-debugfs-for-TWT-debug-calls.patch new file mode 100644 index 000000000..1cc77a650 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0174-ath11k-add-debugfs-for-TWT-debug-calls.patch @@ -0,0 +1,347 @@ +From fe98a6137d03a9e51db2197674c355d64eb3b709 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 31 Jan 2022 16:16:44 +0200 +Subject: [PATCH] ath11k: add debugfs for TWT debug calls + +New debugfs files to manually add/delete/pause/resume TWT +dialogs for test/debug purposes. + +The debugfs files expect the following parameters +- Add dialog +echo ' + + <1:Broadcast /0:Individual> <1:Triggered / 0:Untriggered> + <1:Unannounced /0:Announced> <1:Protected / 0:Unprotected>' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/add_dialog + +Example (Non-triggered and un-announced): +echo '00:03:7F:20:13:52 1 102400 100 30720 20480 4 0 0 1 0' > + /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/twt/add_dialog + +- Delete dialog +echo ' ' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/del_dialog + +- Pause dialog +echo ' ' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/pause_dialog + +- Resume dialog +echo ' ' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/resume_dialog + +Example: +echo '00:03:7F:20:13:52 1 2000000 3' > + /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/twt/resume_dialog + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: John Crispin +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220131031043.1295-2-alokad@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 3 + + drivers/net/wireless/ath/ath11k/debugfs.c | 222 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 14 +- + drivers/net/wireless/ath/ath11k/mac.c | 7 + + 4 files changed, 245 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -263,6 +263,9 @@ struct ath11k_vif { + bool bcca_zero_sent; + bool do_not_send_tmpl; + struct ieee80211_chanctx_conf chanctx; ++#ifdef CPTCFG_ATH11K_DEBUGFS ++ struct dentry *debugfs_twt; ++#endif /* CPTCFG_ATH11K_DEBUGFS */ + }; + + struct ath11k_vif_iter { +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -1224,3 +1224,225 @@ int ath11k_debugfs_register(struct ath11 + void ath11k_debugfs_unregister(struct ath11k *ar) + { + } ++ ++static ssize_t ath11k_write_twt_add_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_add_dialog_params params = { 0 }; ++ u8 buf[128] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, ++ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u %u %u %hhu %hhu %hhu %hhu %hhu", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id, ++ ¶ms.wake_intvl_us, ++ ¶ms.wake_intvl_mantis, ++ ¶ms.wake_dura_us, ++ ¶ms.sp_offset_us, ++ ¶ms.twt_cmd, ++ ¶ms.flag_bcast, ++ ¶ms.flag_trigger, ++ ¶ms.flag_flow_type, ++ ¶ms.flag_protection); ++ if (ret != 16) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t ath11k_write_twt_del_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_del_dialog_params params = { 0 }; ++ u8 buf[64] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id); ++ if (ret != 7) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_del_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t ath11k_write_twt_pause_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_pause_dialog_params params = { 0 }; ++ u8 buf[64] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id); ++ if (ret != 7) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_pause_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t ath11k_write_twt_resume_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_resume_dialog_params params = { 0 }; ++ u8 buf[64] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id, ++ ¶ms.sp_offset_us, ++ ¶ms.next_twt_size); ++ if (ret != 9) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_resume_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static const struct file_operations ath11k_fops_twt_add_dialog = { ++ .write = ath11k_write_twt_add_dialog, ++ .open = simple_open ++}; ++ ++static const struct file_operations ath11k_fops_twt_del_dialog = { ++ .write = ath11k_write_twt_del_dialog, ++ .open = simple_open ++}; ++ ++static const struct file_operations ath11k_fops_twt_pause_dialog = { ++ .write = ath11k_write_twt_pause_dialog, ++ .open = simple_open ++}; ++ ++static const struct file_operations ath11k_fops_twt_resume_dialog = { ++ .write = ath11k_write_twt_resume_dialog, ++ .open = simple_open ++}; ++ ++int ath11k_debugfs_add_interface(struct ath11k_vif *arvif) ++{ ++ if (arvif->vif->type == NL80211_IFTYPE_AP && !arvif->debugfs_twt) { ++ arvif->debugfs_twt = debugfs_create_dir("twt", ++ arvif->vif->debugfs_dir); ++ if (!arvif->debugfs_twt || IS_ERR(arvif->debugfs_twt)) { ++ ath11k_warn(arvif->ar->ab, ++ "failed to create directory %p\n", ++ arvif->debugfs_twt); ++ arvif->debugfs_twt = NULL; ++ return -1; ++ } ++ ++ debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_add_dialog); ++ ++ debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_del_dialog); ++ ++ debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_pause_dialog); ++ ++ debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_resume_dialog); ++ } ++ return 0; ++} ++ ++void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif) ++{ ++ debugfs_remove_recursive(arvif->debugfs_twt); ++ arvif->debugfs_twt = NULL; ++} +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -276,6 +276,9 @@ static inline int ath11k_debugfs_rx_filt + return ar->debug.rx_filter; + } + ++int ath11k_debugfs_add_interface(struct ath11k_vif *arvif); ++void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif); ++ + #else + static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab) + { +@@ -349,6 +352,15 @@ static inline int ath11k_debugfs_get_fw_ + return 0; + } + +-#endif /* CPTCFG_MAC80211_DEBUGFS*/ ++static inline int ath11k_debugfs_add_interface(struct ath11k_vif *arvif) ++{ ++ return 0; ++} ++ ++static inline void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif) ++{ ++} ++ ++#endif /* CPTCFG_ATH11K_DEBUGFS*/ + + #endif /* _ATH11K_DEBUGFS_H_ */ +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6354,6 +6354,10 @@ static int ath11k_mac_op_add_interface(s + } + } + ++ ret = ath11k_debugfs_add_interface(arvif); ++ if (ret) ++ goto err_peer_del; ++ + mutex_unlock(&ar->conf_mutex); + + return 0; +@@ -6388,6 +6392,7 @@ err_vdev_del: + spin_unlock_bh(&ar->data_lock); + + err: ++ ath11k_debugfs_remove_interface(arvif); + mutex_unlock(&ar->conf_mutex); + + return ret; +@@ -6486,6 +6491,8 @@ err_vdev_del: + /* Recalc txpower for remaining vdev */ + ath11k_mac_txpower_recalc(ar); + ++ ath11k_debugfs_remove_interface(arvif); ++ + /* TODO: recal traffic pause state based on the available vdevs */ + + mutex_unlock(&ar->conf_mutex); diff --git a/package/kernel/mac80211/patches/ath11k/0176-ath11k-fix-uninitialized-rate_idx-in-ath11k_dp_tx_up.patch b/package/kernel/mac80211/patches/ath11k/0176-ath11k-fix-uninitialized-rate_idx-in-ath11k_dp_tx_up.patch new file mode 100644 index 000000000..138f24f59 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0176-ath11k-fix-uninitialized-rate_idx-in-ath11k_dp_tx_up.patch @@ -0,0 +1,31 @@ +From 8c4c567fa291e4805d5116f1333b2ed83877032b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 9 Feb 2022 01:08:16 -0500 +Subject: [PATCH] ath11k: fix uninitialized rate_idx in + ath11k_dp_tx_update_txcompl() + +The rate_idx which passed to ath11k_debugfs_sta_add_tx_stats() by +ath11k_dp_tx_update_txcompl() is not initialized, add initialization +for it. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Fixes: 1b8bb94c0612 ("ath11k: report tx bitrate for iw wlan station dump") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060816.423-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -426,7 +426,7 @@ void ath11k_dp_tx_update_txcompl(struct + struct ath11k_sta *arsta; + struct ieee80211_sta *sta; + u16 rate, ru_tones; +- u8 mcs, rate_idx, ofdma; ++ u8 mcs, rate_idx = 0, ofdma; + int ret; + + spin_lock_bh(&ab->base_lock); diff --git a/package/kernel/mac80211/patches/ath11k/0177-ath11k-fix-WARN_ON-during-ath11k_mac_update_vif_chan.patch b/package/kernel/mac80211/patches/ath11k/0177-ath11k-fix-WARN_ON-during-ath11k_mac_update_vif_chan.patch new file mode 100644 index 000000000..d41724a1f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0177-ath11k-fix-WARN_ON-during-ath11k_mac_update_vif_chan.patch @@ -0,0 +1,63 @@ +From 5ed98fb704d97894a2c7217989fd8290e4b7b985 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 9 Feb 2022 19:43:38 +0530 +Subject: [PATCH] ath11k: fix WARN_ON during ath11k_mac_update_vif_chan + +Fix WARN_ON() from ath11k_mac_update_vif_chan() if vdev is not up. +Since change_chanctx can be called even before vdev_up from +ieee80211_start_ap->ieee80211_vif_use_channel-> +ieee80211_recalc_radar_chanctx. + +Do vdev stop followed by a vdev start in case of vdev is down. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644416019-820-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 32 ++++++++++++++++++++++----- + 1 file changed, 26 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6856,13 +6856,33 @@ ath11k_mac_update_vif_chan(struct ath11k + if (WARN_ON(!arvif->is_started)) + continue; + +- if (WARN_ON(!arvif->is_up)) +- continue; ++ /* change_chanctx can be called even before vdev_up from ++ * ieee80211_start_ap->ieee80211_vif_use_channel-> ++ * ieee80211_recalc_radar_chanctx. ++ * ++ * Firmware expect vdev_restart only if vdev is up. ++ * If vdev is down then it expect vdev_stop->vdev_start. ++ */ ++ if (arvif->is_up) { ++ ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); ++ if (ret) { ++ ath11k_warn(ab, "failed to restart vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++ } else { ++ ret = ath11k_mac_vdev_stop(arvif); ++ if (ret) { ++ ath11k_warn(ab, "failed to stop vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++ ++ ret = ath11k_mac_vdev_start(arvif, &vifs[i].new_ctx->def); ++ if (ret) ++ ath11k_warn(ab, "failed to start vdev %d: %d\n", ++ arvif->vdev_id, ret); + +- ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); +- if (ret) { +- ath11k_warn(ab, "failed to restart vdev %d: %d\n", +- arvif->vdev_id, ret); + continue; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0178-ath11k-fix-radar-detection-in-160-Mhz.patch b/package/kernel/mac80211/patches/ath11k/0178-ath11k-fix-radar-detection-in-160-Mhz.patch new file mode 100644 index 000000000..64f34d3c1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0178-ath11k-fix-radar-detection-in-160-Mhz.patch @@ -0,0 +1,118 @@ +From 4f6dd92305f74c43f09e2ff867011e0029ee0e0d Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 9 Feb 2022 19:43:39 +0530 +Subject: [PATCH] ath11k: fix radar detection in 160 Mhz + +Radar detection fails in the secondary 80 MHz when the +the AP's primary 80 MHz is in non-DFS region in 160 MHz. + +This is due to WMI channel flag WMI_CHAN_INFO_DFS_FREQ2 is not set +properly in case of the primary 80 MHz is in non-DFS region. +HALPHY detects the radar pulses in the secondary 80 MHz only when +WMI_CHAN_INFO_DFS_FREQ2 is set. + +Fix this issue by setting WMI channel flag WMI_CHAN_INFO_DFS_FREQ2 +based on the radar_enabled flag from the channel context. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644416019-820-2-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6630,12 +6630,13 @@ static void ath11k_mac_op_remove_chanctx + + static int + ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, +- const struct cfg80211_chan_def *chandef, ++ struct ieee80211_chanctx_conf *ctx, + bool restart) + { + struct ath11k *ar = arvif->ar; + struct ath11k_base *ab = ar->ab; + struct wmi_vdev_start_req_arg arg = {}; ++ const struct cfg80211_chan_def *chandef = &ctx->def; + int he_support = arvif->vif->bss_conf.he_support; + int ret = 0; + +@@ -6670,8 +6671,7 @@ ath11k_mac_vdev_start_restart(struct ath + arg.channel.chan_radar = + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); + +- arg.channel.freq2_radar = +- !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); ++ arg.channel.freq2_radar = ctx->radar_enabled; + + arg.channel.passive = arg.channel.chan_radar; + +@@ -6781,15 +6781,15 @@ err: + } + + static int ath11k_mac_vdev_start(struct ath11k_vif *arvif, +- const struct cfg80211_chan_def *chandef) ++ struct ieee80211_chanctx_conf *ctx) + { +- return ath11k_mac_vdev_start_restart(arvif, chandef, false); ++ return ath11k_mac_vdev_start_restart(arvif, ctx, false); + } + + static int ath11k_mac_vdev_restart(struct ath11k_vif *arvif, +- const struct cfg80211_chan_def *chandef) ++ struct ieee80211_chanctx_conf *ctx) + { +- return ath11k_mac_vdev_start_restart(arvif, chandef, true); ++ return ath11k_mac_vdev_start_restart(arvif, ctx, true); + } + + struct ath11k_mac_change_chanctx_arg { +@@ -6864,7 +6864,7 @@ ath11k_mac_update_vif_chan(struct ath11k + * If vdev is down then it expect vdev_stop->vdev_start. + */ + if (arvif->is_up) { +- ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); ++ ret = ath11k_mac_vdev_restart(arvif, vifs[i].new_ctx); + if (ret) { + ath11k_warn(ab, "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -6878,7 +6878,7 @@ ath11k_mac_update_vif_chan(struct ath11k + continue; + } + +- ret = ath11k_mac_vdev_start(arvif, &vifs[i].new_ctx->def); ++ ret = ath11k_mac_vdev_start(arvif, vifs[i].new_ctx); + if (ret) + ath11k_warn(ab, "failed to start vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -6967,7 +6967,8 @@ static void ath11k_mac_op_change_chanctx + if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) + goto unlock; + +- if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) ++ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH || ++ changed & IEEE80211_CHANCTX_CHANGE_RADAR) + ath11k_mac_update_active_vif_chan(ar, ctx); + + /* TODO: Recalc radar detection */ +@@ -6987,7 +6988,7 @@ static int ath11k_start_vdev_delay(struc + if (WARN_ON(arvif->is_started)) + return -EBUSY; + +- ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx.def); ++ ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", + arvif->vdev_id, vif->addr, +@@ -7081,7 +7082,7 @@ ath11k_mac_op_assign_vif_chanctx(struct + goto out; + } + +- ret = ath11k_mac_vdev_start(arvif, &ctx->def); ++ ret = ath11k_mac_vdev_start(arvif, ctx); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", + arvif->vdev_id, vif->addr, diff --git a/package/kernel/mac80211/patches/ath11k/0179-ath11k-fix-destination-monitor-ring-out-of-sync.patch b/package/kernel/mac80211/patches/ath11k/0179-ath11k-fix-destination-monitor-ring-out-of-sync.patch new file mode 100644 index 000000000..5352ae89a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0179-ath11k-fix-destination-monitor-ring-out-of-sync.patch @@ -0,0 +1,111 @@ +From 1e15aacd12386d8f1372929a3fd52db9ef3344fc Mon Sep 17 00:00:00 2001 +From: Karthikeyan Kathirvel +Date: Thu, 10 Feb 2022 12:17:06 +0530 +Subject: [PATCH] ath11k: fix destination monitor ring out of sync + +More than 20000 PPDU id jumping causing status ring and destination +ring processing not sync. The status ring is processed and the +destination ring is not processed. Since destination is not reaped for +so long, backpressure occurs at the destination ring. + +To address this issue update the PPDU id with the latest PPDU, this +will allow the destination ring to be reaped and will prevent the +rings from getting out of sync. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1.r1-00026-QCAHKSWPL_SILICONZ-2 +Signed-off-by: Karthikeyan Kathirvel +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220210064706.6171-1-quic_kathirve@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp.h | 3 ++ + drivers/net/wireless/ath/ath11k/dp_rx.c | 42 +++++++++++++++++++++---- + 2 files changed, 39 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -115,6 +115,8 @@ struct ath11k_pdev_mon_stats { + u32 dest_mpdu_drop; + u32 dup_mon_linkdesc_cnt; + u32 dup_mon_buf_cnt; ++ u32 dest_mon_stuck; ++ u32 dest_mon_not_reaped; + }; + + struct dp_full_mon_mpdu { +@@ -167,6 +169,7 @@ struct ath11k_mon_data { + + struct ath11k_pdev_dp { + u32 mac_id; ++ u32 mon_dest_ring_stuck_cnt; + atomic_t num_tx_pending; + wait_queue_head_t tx_empty_waitq; + struct dp_rxdma_ring rx_refill_buf_ring; +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4959,6 +4959,12 @@ mon_deliver_fail: + return -EINVAL; + } + ++/* The destination ring processing is stuck if the destination is not ++ * moving while status ring moves 16 PPDU. The destination ring processing ++ * skips this destination ring PPDU as a workaround. ++ */ ++#define MON_DEST_RING_STUCK_MAX_CNT 16 ++ + static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, + u32 quota, struct napi_struct *napi) + { +@@ -4972,6 +4978,7 @@ static void ath11k_dp_rx_mon_dest_proces + u32 ring_id; + struct ath11k_pdev_mon_stats *rx_mon_stats; + u32 npackets = 0; ++ u32 mpdu_rx_bufs_used; + + if (ar->ab->hw_params.rxdma1_enable) + ring_id = dp->rxdma_mon_dst_ring.ring_id; +@@ -5001,16 +5008,39 @@ static void ath11k_dp_rx_mon_dest_proces + head_msdu = NULL; + tail_msdu = NULL; + +- rx_bufs_used += ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry, +- &head_msdu, +- &tail_msdu, +- &npackets, &ppdu_id); ++ mpdu_rx_bufs_used = ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry, ++ &head_msdu, ++ &tail_msdu, ++ &npackets, &ppdu_id); ++ ++ rx_bufs_used += mpdu_rx_bufs_used; ++ ++ if (mpdu_rx_bufs_used) { ++ dp->mon_dest_ring_stuck_cnt = 0; ++ } else { ++ dp->mon_dest_ring_stuck_cnt++; ++ rx_mon_stats->dest_mon_not_reaped++; ++ } ++ ++ if (dp->mon_dest_ring_stuck_cnt > MON_DEST_RING_STUCK_MAX_CNT) { ++ rx_mon_stats->dest_mon_stuck++; ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "status ring ppdu_id=%d dest ring ppdu_id=%d mon_dest_ring_stuck_cnt=%d dest_mon_not_reaped=%u dest_mon_stuck=%u\n", ++ pmon->mon_ppdu_info.ppdu_id, ppdu_id, ++ dp->mon_dest_ring_stuck_cnt, ++ rx_mon_stats->dest_mon_not_reaped, ++ rx_mon_stats->dest_mon_stuck); ++ pmon->mon_ppdu_info.ppdu_id = ppdu_id; ++ continue; ++ } + + if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) { + pmon->mon_ppdu_status = DP_PPDU_STATUS_START; + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, +- "dest_rx: new ppdu_id %x != status ppdu_id %x", +- ppdu_id, pmon->mon_ppdu_info.ppdu_id); ++ "dest_rx: new ppdu_id %x != status ppdu_id %x dest_mon_not_reaped = %u dest_mon_stuck = %u\n", ++ ppdu_id, pmon->mon_ppdu_info.ppdu_id, ++ rx_mon_stats->dest_mon_not_reaped, ++ rx_mon_stats->dest_mon_stuck); + break; + } + if (head_msdu && tail_msdu) { diff --git a/package/kernel/mac80211/patches/ath11k/0181-ath11k-add-ath11k_qmi_free_resource-for-recovery.patch b/package/kernel/mac80211/patches/ath11k/0181-ath11k-add-ath11k_qmi_free_resource-for-recovery.patch new file mode 100644 index 000000000..831cfb2bb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0181-ath11k-add-ath11k_qmi_free_resource-for-recovery.patch @@ -0,0 +1,38 @@ +From 5f71968e3c769b1d3c3cb0831ef870663b3c1f89 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 14 Feb 2022 19:53:16 +0200 +Subject: [PATCH] ath11k: add ath11k_qmi_free_resource() for recovery + +ath11k_qmi_free_target_mem_chunk() and ath11k_qmi_m3_free() is static +in qmi.c, they are needed for recovery, export them in a new function. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060012.32478-2-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 5 +++++ + drivers/net/wireless/ath/ath11k/qmi.h | 1 + + 2 files changed, 6 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -3025,3 +3025,8 @@ void ath11k_qmi_deinit_service(struct at + } + EXPORT_SYMBOL(ath11k_qmi_deinit_service); + ++void ath11k_qmi_free_resource(struct ath11k_base *ab) ++{ ++ ath11k_qmi_free_target_mem_chunk(ab); ++ ath11k_qmi_m3_free(ab); ++} +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -492,5 +492,6 @@ void ath11k_qmi_event_work(struct work_s + void ath11k_qmi_msg_recv_work(struct work_struct *work); + void ath11k_qmi_deinit_service(struct ath11k_base *ab); + int ath11k_qmi_init_service(struct ath11k_base *ab); ++void ath11k_qmi_free_resource(struct ath11k_base *ab); + + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0182-ath11k-fix-invalid-m3-buffer-address.patch b/package/kernel/mac80211/patches/ath11k/0182-ath11k-fix-invalid-m3-buffer-address.patch new file mode 100644 index 000000000..1c8ceb97e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0182-ath11k-fix-invalid-m3-buffer-address.patch @@ -0,0 +1,29 @@ +From e52b6a02bfc00d74cee385dea60f9894121c1f2d Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Feb 2022 19:53:16 +0200 +Subject: [PATCH] ath11k: fix invalid m3 buffer address + +This is to fix m3 buffer reuse issue as m3_mem->size isn't set to +ZERO in free function, which leads invalid m3 downloading to +firmware and firmware crashed. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Carl Huang +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060012.32478-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2342,6 +2342,7 @@ static void ath11k_qmi_m3_free(struct at + dma_free_coherent(ab->dev, m3_mem->size, + m3_mem->vaddr, m3_mem->paddr); + m3_mem->vaddr = NULL; ++ m3_mem->size = 0; + } + + static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) diff --git a/package/kernel/mac80211/patches/ath11k/0183-ath11k-configure-RDDM-size-to-mhi-for-recovery-by-fi.patch b/package/kernel/mac80211/patches/ath11k/0183-ath11k-configure-RDDM-size-to-mhi-for-recovery-by-fi.patch new file mode 100644 index 000000000..865aa9836 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0183-ath11k-configure-RDDM-size-to-mhi-for-recovery-by-fi.patch @@ -0,0 +1,35 @@ +From 03e0add74212b63674ffa1304e55d6c929fb8458 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 14 Feb 2022 19:53:16 +0200 +Subject: [PATCH] ath11k: configure RDDM size to mhi for recovery by firmware + +The rddm_size is needed by firmware while mhi enter RDDM state, add it +to support recovery when ath11k receive MHI_CB_EE_RDDM message. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060012.32478-4-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mhi.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -13,6 +13,7 @@ + #include "pci.h" + + #define MHI_TIMEOUT_DEFAULT_MS 90000 ++#define RDDM_DUMP_SIZE 0x420000 + + static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { + { +@@ -384,6 +385,7 @@ int ath11k_mhi_register(struct ath11k_pc + mhi_ctrl->iova_stop = 0xFFFFFFFF; + } + ++ mhi_ctrl->rddm_size = RDDM_DUMP_SIZE; + mhi_ctrl->sbl_size = SZ_512K; + mhi_ctrl->seg_len = SZ_512K; + mhi_ctrl->fbc_download = true; diff --git a/package/kernel/mac80211/patches/ath11k/0184-ath11k-Replace-zero-length-arrays-with-flexible-arra.patch b/package/kernel/mac80211/patches/ath11k/0184-ath11k-Replace-zero-length-arrays-with-flexible-arra.patch new file mode 100644 index 000000000..3099cccf8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0184-ath11k-Replace-zero-length-arrays-with-flexible-arra.patch @@ -0,0 +1,137 @@ +From e9e591686ccb51d53048dabe8e6020b5a3bba45d Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Wed, 16 Feb 2022 13:48:36 -0600 +Subject: [PATCH] ath11k: Replace zero-length arrays with flexible-array + members +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is a regular need in the kernel to provide a way to declare +having a dynamically sized set of trailing elements in a structure. +Kernel code should always use “flexible array members”[1] for these +cases. The older style of one-element or zero-length arrays should +no longer be used[2]. + +[1] https://en.wikipedia.org/wiki/Flexible_array_member +[2] https://www.kernel.org/doc/html/v5.16/process/deprecated.html#zero-length-and-one-element-arrays + +Link: https://github.com/KSPP/linux/issues/78 +Signed-off-by: Gustavo A. R. Silva +Reviewed-by: Kees Cook +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220216194836.GA904035@embeddedor +--- + drivers/net/wireless/ath/ath11k/ce.h | 2 +- + drivers/net/wireless/ath/ath11k/core.h | 2 +- + drivers/net/wireless/ath/ath11k/dp.h | 10 +++++----- + drivers/net/wireless/ath/ath11k/rx_desc.h | 6 +++--- + drivers/net/wireless/ath/ath11k/spectral.c | 2 +- + 5 files changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.h ++++ b/drivers/net/wireless/ath/ath11k/ce.h +@@ -145,7 +145,7 @@ struct ath11k_ce_ring { + u32 hal_ring_id; + + /* keep last */ +- struct sk_buff *skb[0]; ++ struct sk_buff *skb[]; + }; + + struct ath11k_ce_pipe { +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -815,7 +815,7 @@ struct ath11k_base { + } id; + + /* must be last */ +- u8 drv_priv[0] __aligned(sizeof(void *)); ++ u8 drv_priv[] __aligned(sizeof(void *)); + }; + + struct ath11k_fw_stats_pdev { +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -1173,12 +1173,12 @@ struct ath11k_htt_ppdu_stats_msg { + u32 ppdu_id; + u32 timestamp; + u32 rsvd; +- u8 data[0]; ++ u8 data[]; + } __packed; + + struct htt_tlv { + u32 header; +- u8 value[0]; ++ u8 value[]; + } __packed; + + #define HTT_TLV_TAG GENMASK(11, 0) +@@ -1365,7 +1365,7 @@ struct htt_ppdu_stats_usr_cmn_array { + * tx_ppdu_stats_info is variable length, with length = + * number_of_ppdu_stats * sizeof (struct htt_tx_ppdu_stats_info) + */ +- struct htt_tx_ppdu_stats_info tx_ppdu_info[0]; ++ struct htt_tx_ppdu_stats_info tx_ppdu_info[]; + } __packed; + + struct htt_ppdu_user_stats { +@@ -1427,7 +1427,7 @@ struct htt_ppdu_stats_info { + */ + struct htt_pktlog_msg { + u32 hdr; +- u8 payload[0]; ++ u8 payload[]; + }; + + /** +@@ -1648,7 +1648,7 @@ struct ath11k_htt_extd_stats_msg { + u32 info0; + u64 cookie; + u32 info1; +- u8 data[0]; ++ u8 data[]; + } __packed; + + #define HTT_MAC_ADDR_L32_0 GENMASK(7, 0) +--- a/drivers/net/wireless/ath/ath11k/rx_desc.h ++++ b/drivers/net/wireless/ath/ath11k/rx_desc.h +@@ -1445,7 +1445,7 @@ struct hal_rx_desc_ipq8074 { + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; +- u8 msdu_payload[0]; ++ u8 msdu_payload[]; + } __packed; + + struct hal_rx_desc_qcn9074 { +@@ -1464,7 +1464,7 @@ struct hal_rx_desc_qcn9074 { + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; +- u8 msdu_payload[0]; ++ u8 msdu_payload[]; + } __packed; + + struct hal_rx_desc_wcn6855 { +@@ -1483,7 +1483,7 @@ struct hal_rx_desc_wcn6855 { + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; +- u8 msdu_payload[0]; ++ u8 msdu_payload[]; + } __packed; + + struct hal_rx_desc { +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -107,7 +107,7 @@ struct spectral_search_fft_report { + __le32 info1; + __le32 info2; + __le32 reserve0; +- u8 bins[0]; ++ u8 bins[]; + } __packed; + + struct ath11k_spectral_search_report { diff --git a/package/kernel/mac80211/patches/ath11k/0185-ath11k-Invalidate-cached-reo-ring-entry-before-acces.patch b/package/kernel/mac80211/patches/ath11k/0185-ath11k-Invalidate-cached-reo-ring-entry-before-acces.patch new file mode 100644 index 000000000..f491abc74 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0185-ath11k-Invalidate-cached-reo-ring-entry-before-acces.patch @@ -0,0 +1,44 @@ +From f2180ccb52b5fd0876291ad2df37e2898cac18cf Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Wed, 16 Feb 2022 14:02:34 +0530 +Subject: [PATCH] ath11k: Invalidate cached reo ring entry before accessing it + +REO2SW ring descriptor is currently allocated in cacheable memory. +While reaping reo ring entries on second trial after updating head +pointer, first entry is not invalidated before accessing it. + +This results in host reaping and using cached descriptor which is +already overwritten in memory by DMA device (HW). +Since the contents of descriptor(buffer id, peer info and other information +bits) are outdated host throws errors like below while parsing corresponding +MSDU's and drops them. + +[347712.048904] ath11k_pci 0004:01:00.0: msdu_done bit in attention is not set +[349173.355503] ath11k_pci 0004:01:00.0: frame rx with invalid buf_id 962 + +Move the try_again: label above ath11k_hal_srng_access_begin() +so that first entry will be invalidated and prefetched. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Fixes: 6452f0a3d565 ("ath11k: allocate dst ring descriptors from cacheable memory") +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1645000354-32558-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2652,9 +2652,9 @@ int ath11k_dp_process_rx(struct ath11k_b + + spin_lock_bh(&srng->lock); + ++try_again: + ath11k_hal_srng_access_begin(ab, srng); + +-try_again: + while (likely(desc = + (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, + srng))) { diff --git a/package/kernel/mac80211/patches/ath11k/0186-ath11k-Handle-failure-in-qmi-firmware-ready.patch b/package/kernel/mac80211/patches/ath11k/0186-ath11k-Handle-failure-in-qmi-firmware-ready.patch new file mode 100644 index 000000000..2cd2a463c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0186-ath11k-Handle-failure-in-qmi-firmware-ready.patch @@ -0,0 +1,41 @@ +From a19c0e104db95f78540982c64d78217cd9830d72 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Thu, 17 Feb 2022 11:56:35 +0530 +Subject: [PATCH] ath11k: Handle failure in qmi firmware ready + +In some scenarios like firmware crashes during init time +and hardware gets restarted after qmi firmware ready event. +During restart, ath11k_core_qmi_firmware_ready() returns timeout. +But, this failure is not handled and ATH11K_FLAG_REGISTERED is set. + +When hardware restart completed, firmware sends firmware ready event +again. Since ATH11K_FLAG_REGISTERED is already set, ath11k handles +this as core restart. Inits are not done because of previous timeout. +But ath11k_core_restart does deinit's which causes NULL pointer crash. + +Fix this by handling failure from ath11k_core_qmi_firmware_ready(). + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-00881-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1645079195-13564-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2960,7 +2960,11 @@ static void ath11k_qmi_driver_event_work + clear_bit(ATH11K_FLAG_CRASH_FLUSH, + &ab->dev_flags); + clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); +- ath11k_core_qmi_firmware_ready(ab); ++ ret = ath11k_core_qmi_firmware_ready(ab); ++ if (ret) { ++ set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); ++ break; ++ } + set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); + } + diff --git a/package/kernel/mac80211/patches/ath11k/0187-ath11k-Fix-frames-flush-failure-caused-by-deadlock.patch b/package/kernel/mac80211/patches/ath11k/0187-ath11k-Fix-frames-flush-failure-caused-by-deadlock.patch new file mode 100644 index 000000000..003b62406 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0187-ath11k-Fix-frames-flush-failure-caused-by-deadlock.patch @@ -0,0 +1,126 @@ +From 261b07519518bd14cb168b287b17e1d195f8d0c8 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Thu, 17 Feb 2022 16:45:45 +0800 +Subject: [PATCH] ath11k: Fix frames flush failure caused by deadlock + +We are seeing below warnings: + +kernel: [25393.301506] ath11k_pci 0000:01:00.0: failed to flush mgmt transmit queue 0 +kernel: [25398.421509] ath11k_pci 0000:01:00.0: failed to flush mgmt transmit queue 0 +kernel: [25398.421831] ath11k_pci 0000:01:00.0: dropping mgmt frame for vdev 0, is_started 0 + +this means ath11k fails to flush mgmt. frames because wmi_mgmt_tx_work +has no chance to run in 5 seconds. + +By setting /proc/sys/kernel/hung_task_timeout_secs to 20 and increasing +ATH11K_FLUSH_TIMEOUT to 50 we get below warnings: + +kernel: [ 120.763160] INFO: task wpa_supplicant:924 blocked for more than 20 seconds. +kernel: [ 120.763169] Not tainted 5.10.90 #12 +kernel: [ 120.763177] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +kernel: [ 120.763186] task:wpa_supplicant state:D stack: 0 pid: 924 ppid: 1 flags:0x000043a0 +kernel: [ 120.763201] Call Trace: +kernel: [ 120.763214] __schedule+0x785/0x12fa +kernel: [ 120.763224] ? lockdep_hardirqs_on_prepare+0xe2/0x1bb +kernel: [ 120.763242] schedule+0x7e/0xa1 +kernel: [ 120.763253] schedule_timeout+0x98/0xfe +kernel: [ 120.763266] ? run_local_timers+0x4a/0x4a +kernel: [ 120.763291] ath11k_mac_flush_tx_complete+0x197/0x2b1 [ath11k 13c3a9bf37790f4ac8103b3decf7ab4008ac314a] +kernel: [ 120.763306] ? init_wait_entry+0x2e/0x2e +kernel: [ 120.763343] __ieee80211_flush_queues+0x167/0x21f [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763378] __ieee80211_recalc_idle+0x105/0x125 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763411] ieee80211_recalc_idle+0x14/0x27 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763441] ieee80211_free_chanctx+0x77/0xa2 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763473] __ieee80211_vif_release_channel+0x100/0x131 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763540] ieee80211_vif_release_channel+0x66/0x81 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763572] ieee80211_destroy_auth_data+0xa3/0xe6 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763612] ieee80211_mgd_deauth+0x178/0x29b [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763654] cfg80211_mlme_deauth+0x1a8/0x22c [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763697] nl80211_deauthenticate+0xfa/0x123 [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763715] genl_rcv_msg+0x392/0x3c2 +kernel: [ 120.763750] ? nl80211_associate+0x432/0x432 [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763782] ? nl80211_associate+0x432/0x432 [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763802] ? genl_rcv+0x36/0x36 +kernel: [ 120.763814] netlink_rcv_skb+0x89/0xf7 +kernel: [ 120.763829] genl_rcv+0x28/0x36 +kernel: [ 120.763840] netlink_unicast+0x179/0x24b +kernel: [ 120.763854] netlink_sendmsg+0x393/0x401 +kernel: [ 120.763872] sock_sendmsg+0x72/0x76 +kernel: [ 120.763886] ____sys_sendmsg+0x170/0x1e6 +kernel: [ 120.763897] ? copy_msghdr_from_user+0x7a/0xa2 +kernel: [ 120.763914] ___sys_sendmsg+0x95/0xd1 +kernel: [ 120.763940] __sys_sendmsg+0x85/0xbf +kernel: [ 120.763956] do_syscall_64+0x43/0x55 +kernel: [ 120.763966] entry_SYSCALL_64_after_hwframe+0x44/0xa9 +kernel: [ 120.763977] RIP: 0033:0x79089f3fcc83 +kernel: [ 120.763986] RSP: 002b:00007ffe604f0508 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +kernel: [ 120.763997] RAX: ffffffffffffffda RBX: 000059b40e987690 RCX: 000079089f3fcc83 +kernel: [ 120.764006] RDX: 0000000000000000 RSI: 00007ffe604f0558 RDI: 0000000000000009 +kernel: [ 120.764014] RBP: 00007ffe604f0540 R08: 0000000000000004 R09: 0000000000400000 +kernel: [ 120.764023] R10: 00007ffe604f0638 R11: 0000000000000246 R12: 000059b40ea04980 +kernel: [ 120.764032] R13: 00007ffe604f0638 R14: 000059b40e98c360 R15: 00007ffe604f0558 +... +kernel: [ 120.765230] INFO: task kworker/u32:26:4239 blocked for more than 20 seconds. +kernel: [ 120.765238] Not tainted 5.10.90 #12 +kernel: [ 120.765245] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +kernel: [ 120.765253] task:kworker/u32:26 state:D stack: 0 pid: 4239 ppid: 2 flags:0x00004080 +kernel: [ 120.765284] Workqueue: phy0 ieee80211_iface_work [mac80211] +kernel: [ 120.765295] Call Trace: +kernel: [ 120.765306] __schedule+0x785/0x12fa +kernel: [ 120.765316] ? find_held_lock+0x3d/0xb2 +kernel: [ 120.765331] schedule+0x7e/0xa1 +kernel: [ 120.765340] schedule_preempt_disabled+0x15/0x1e +kernel: [ 120.765349] __mutex_lock_common+0x561/0xc0d +kernel: [ 120.765375] ? ieee80211_sta_work+0x3e/0x1232 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.765390] mutex_lock_nested+0x20/0x26 +kernel: [ 120.765416] ieee80211_sta_work+0x3e/0x1232 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.765430] ? skb_dequeue+0x54/0x5e +kernel: [ 120.765456] ? ieee80211_iface_work+0x7b/0x339 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.765485] process_one_work+0x270/0x504 +kernel: [ 120.765501] worker_thread+0x215/0x376 +kernel: [ 120.765514] kthread+0x159/0x168 +kernel: [ 120.765526] ? pr_cont_work+0x5b/0x5b +kernel: [ 120.765536] ? kthread_blkcg+0x31/0x31 +kernel: [ 120.765550] ret_from_fork+0x22/0x30 +... +kernel: [ 120.765867] Showing all locks held in the system: +... +kernel: [ 120.766164] 5 locks held by wpa_supplicant/924: +kernel: [ 120.766172] #0: ffffffffb1e63eb0 (cb_lock){++++}-{3:3}, at: genl_rcv+0x19/0x36 +kernel: [ 120.766197] #1: ffffffffb1e5b1c8 (rtnl_mutex){+.+.}-{3:3}, at: nl80211_pre_doit+0x2a/0x15c [cfg80211] +kernel: [ 120.766238] #2: ffff99f08347cd08 (&wdev->mtx){+.+.}-{3:3}, at: nl80211_deauthenticate+0xde/0x123 [cfg80211] +kernel: [ 120.766279] #3: ffff99f09df12a48 (&local->mtx){+.+.}-{3:3}, at: ieee80211_destroy_auth_data+0x9b/0xe6 [mac80211] +kernel: [ 120.766321] #4: ffff99f09df12ce0 (&local->chanctx_mtx){+.+.}-{3:3}, at: ieee80211_vif_release_channel+0x5e/0x81 [mac80211] +... +kernel: [ 120.766585] 3 locks held by kworker/u32:26/4239: +kernel: [ 120.766593] #0: ffff99f04458f948 ((wq_completion)phy0){+.+.}-{0:0}, at: process_one_work+0x19a/0x504 +kernel: [ 120.766621] #1: ffffbad54b3cfe50 ((work_completion)(&sdata->work)){+.+.}-{0:0}, at: process_one_work+0x1c0/0x504 +kernel: [ 120.766649] #2: ffff99f08347cd08 (&wdev->mtx){+.+.}-{3:3}, at: ieee80211_sta_work+0x3e/0x1232 [mac80211] + +With above info the issue is clear: First wmi_mgmt_tx_work is inserted +to local->workqueue after sdata->work inserted, then wpa_supplicant +acquires wdev->mtx in nl80211_deauthenticate and finally calls +ath11k_mac_op_flush where it waits all mgmt. frames to be sent out by +wmi_mgmt_tx_work. Meanwhile, sdata->work is blocked by wdev->mtx in +ieee80211_sta_work, as a result wmi_mgmt_tx_work has no chance to run. + +Change to use ab->workqueue instead of local->workqueue to fix this issue. + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220217084545.18844-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5579,7 +5579,7 @@ static int ath11k_mac_mgmt_tx(struct ath + + skb_queue_tail(q, skb); + atomic_inc(&ar->num_pending_mgmt_tx); +- ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); ++ queue_work(ar->ab->workqueue, &ar->wmi_mgmt_tx_work); + + return 0; + } diff --git a/package/kernel/mac80211/patches/ath11k/0188-ath11k-switch-to-using-ieee80211_tx_status_ext.patch b/package/kernel/mac80211/patches/ath11k/0188-ath11k-switch-to-using-ieee80211_tx_status_ext.patch new file mode 100644 index 000000000..c97d62553 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0188-ath11k-switch-to-using-ieee80211_tx_status_ext.patch @@ -0,0 +1,65 @@ +From 94739d45c388c5c5be49bb0a5d911f672122d378 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Wed, 16 Feb 2022 17:21:10 -0800 +Subject: [PATCH] ath11k: switch to using ieee80211_tx_status_ext() + +This allows us to pass HE rates down into the stack. + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Signed-off-by: John Crispin +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220217012112.31211-2-pradeepc@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 28 ++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -518,9 +518,13 @@ static void ath11k_dp_tx_complete_msdu(s + struct sk_buff *msdu, + struct hal_tx_status *ts) + { ++ struct ieee80211_tx_status status = { 0 }; + struct ath11k_base *ab = ar->ab; + struct ieee80211_tx_info *info; + struct ath11k_skb_cb *skb_cb; ++ struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; ++ struct rate_info rate; + + if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { + /* Must not happen */ +@@ -583,12 +587,26 @@ static void ath11k_dp_tx_complete_msdu(s + ath11k_dp_tx_cache_peer_stats(ar, msdu, ts); + } + +- /* NOTE: Tx rate status reporting. Tx completion status does not have +- * necessary information (for example nss) to build the tx rate. +- * Might end up reporting it out-of-band from HTT stats. +- */ ++ spin_lock_bh(&ab->base_lock); ++ peer = ath11k_peer_find_by_id(ab, ts->peer_id); ++ if (!peer || !peer->sta) { ++ ath11k_dbg(ab, ATH11K_DBG_DATA, ++ "dp_tx: failed to find the peer with peer_id %d\n", ++ ts->peer_id); ++ spin_unlock_bh(&ab->base_lock); ++ dev_kfree_skb_any(msdu); ++ return; ++ } ++ arsta = (struct ath11k_sta *)peer->sta->drv_priv; ++ status.sta = peer->sta; ++ status.skb = msdu; ++ status.info = info; ++ rate = arsta->last_txrate; ++ status.rate = &rate; ++ ++ spin_unlock_bh(&ab->base_lock); + +- ieee80211_tx_status(ar->hw, msdu); ++ ieee80211_tx_status_ext(ar->hw, &status); + } + + static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, diff --git a/package/kernel/mac80211/patches/ath11k/0189-ath11k-decode-HE-status-tlv.patch b/package/kernel/mac80211/patches/ath11k/0189-ath11k-decode-HE-status-tlv.patch new file mode 100644 index 000000000..ae811bb52 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0189-ath11k-decode-HE-status-tlv.patch @@ -0,0 +1,424 @@ +From 01d2f285e3e5b629df9c61514e7ee07a54d0eed9 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Wed, 16 Feb 2022 17:21:11 -0800 +Subject: [PATCH] ath11k: decode HE status tlv + +Add new bitmasks and macro definitions required for parsing HE +status tlvs. Decode HE status tlvs, which will used in dumping +ppdu stats as well as updating radiotap headers. + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220217012112.31211-3-pradeepc@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 100 ++++++++++++--- + drivers/net/wireless/ath/ath11k/hal_desc.h | 1 + + drivers/net/wireless/ath/ath11k/hal_rx.h | 135 ++++++++++++++++++++- + 3 files changed, 215 insertions(+), 21 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4807,7 +4807,6 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + { + struct ath11k_base *ab = ar->ab; + struct sk_buff *msdu, *prev_buf; +- u32 wifi_hdr_len; + struct hal_rx_desc *rx_desc; + char *hdr_desc; + u8 *dest, decap_format; +@@ -4849,38 +4848,27 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + + skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN); + } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) { +- __le16 qos_field; + u8 qos_pkt = 0; + + rx_desc = (struct hal_rx_desc *)head_msdu->data; + hdr_desc = ath11k_dp_rxdesc_get_80211hdr(ab, rx_desc); + + /* Base size */ +- wifi_hdr_len = sizeof(struct ieee80211_hdr_3addr); + wh = (struct ieee80211_hdr_3addr *)hdr_desc; + +- if (ieee80211_is_data_qos(wh->frame_control)) { +- struct ieee80211_qos_hdr *qwh = +- (struct ieee80211_qos_hdr *)hdr_desc; +- +- qos_field = qwh->qos_ctrl; ++ if (ieee80211_is_data_qos(wh->frame_control)) + qos_pkt = 1; +- } ++ + msdu = head_msdu; + + while (msdu) { +- rx_desc = (struct hal_rx_desc *)msdu->data; +- hdr_desc = ath11k_dp_rxdesc_get_80211hdr(ab, rx_desc); +- ++ ath11k_dp_rx_msdus_set_payload(ar, msdu); + if (qos_pkt) { + dest = skb_push(msdu, sizeof(__le16)); + if (!dest) + goto err_merge_fail; +- memcpy(dest, hdr_desc, wifi_hdr_len); +- memcpy(dest + wifi_hdr_len, +- (u8 *)&qos_field, sizeof(__le16)); ++ memcpy(dest, hdr_desc, sizeof(struct ieee80211_qos_hdr)); + } +- ath11k_dp_rx_msdus_set_payload(ar, msdu); + prev_buf = msdu; + msdu = msdu->next; + } +@@ -4904,8 +4892,83 @@ err_merge_fail: + return NULL; + } + ++static void ++ath11k_dp_rx_update_radiotap_he(struct hal_rx_mon_ppdu_info *rx_status, ++ u8 *rtap_buf) ++{ ++ u32 rtap_len = 0; ++ ++ put_unaligned_le16(rx_status->he_data1, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ put_unaligned_le16(rx_status->he_data2, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ put_unaligned_le16(rx_status->he_data3, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ put_unaligned_le16(rx_status->he_data4, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ put_unaligned_le16(rx_status->he_data5, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ put_unaligned_le16(rx_status->he_data6, &rtap_buf[rtap_len]); ++} ++ ++static void ++ath11k_dp_rx_update_radiotap_he_mu(struct hal_rx_mon_ppdu_info *rx_status, ++ u8 *rtap_buf) ++{ ++ u32 rtap_len = 0; ++ ++ put_unaligned_le16(rx_status->he_flags1, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ put_unaligned_le16(rx_status->he_flags2, &rtap_buf[rtap_len]); ++ rtap_len += 2; ++ ++ rtap_buf[rtap_len] = rx_status->he_RU[0]; ++ rtap_len += 1; ++ ++ rtap_buf[rtap_len] = rx_status->he_RU[1]; ++ rtap_len += 1; ++ ++ rtap_buf[rtap_len] = rx_status->he_RU[2]; ++ rtap_len += 1; ++ ++ rtap_buf[rtap_len] = rx_status->he_RU[3]; ++} ++ ++static void ath11k_update_radiotap(struct hal_rx_mon_ppdu_info *ppduinfo, ++ struct sk_buff *mon_skb, ++ struct ieee80211_rx_status *rxs) ++{ ++ u8 *ptr = NULL; ++ ++ if (ppduinfo->he_mu_flags) { ++ rxs->flag |= RX_FLAG_RADIOTAP_HE_MU; ++ rxs->encoding = RX_ENC_HE; ++ ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he_mu)); ++ ath11k_dp_rx_update_radiotap_he_mu(ppduinfo, ptr); ++ } ++ if (ppduinfo->he_flags) { ++ rxs->flag |= RX_FLAG_RADIOTAP_HE; ++ rxs->encoding = RX_ENC_HE; ++ ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he)); ++ ath11k_dp_rx_update_radiotap_he(ppduinfo, ptr); ++ } ++ ++ rxs->flag |= RX_FLAG_MACTIME_START; ++ rxs->signal = ppduinfo->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; ++ rxs->nss = ppduinfo->nss; ++ ++ rxs->mactime = ppduinfo->tsft; ++} ++ + static int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id, + struct sk_buff *head_msdu, ++ struct hal_rx_mon_ppdu_info *ppduinfo, + struct sk_buff *tail_msdu, + struct napi_struct *napi) + { +@@ -4940,7 +5003,7 @@ static int ath11k_dp_rx_mon_deliver(stru + } else { + rxs->flag |= RX_FLAG_ALLOW_SAME_PN; + } +- rxs->flag |= RX_FLAG_ONLY_MONITOR; ++ ath11k_update_radiotap(ppduinfo, mon_skb, rxs); + + ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb, rxs); + mon_skb = skb_next; +@@ -5045,6 +5108,7 @@ static void ath11k_dp_rx_mon_dest_proces + } + if (head_msdu && tail_msdu) { + ath11k_dp_rx_mon_deliver(ar, dp->mac_id, head_msdu, ++ &pmon->mon_ppdu_info, + tail_msdu, napi); + rx_mon_stats->dest_mpdu_done++; + } +@@ -5114,6 +5178,7 @@ int ath11k_dp_rx_process_mon_status(stru + if (log_type != ATH11K_PKTLOG_TYPE_INVALID) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + ++ memset(ppdu_info, 0, sizeof(struct hal_rx_mon_ppdu_info)); + hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); + + if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && +@@ -5374,6 +5439,7 @@ static int ath11k_dp_rx_full_mon_deliver + tail_msdu = mon_mpdu->tail; + if (head_msdu && tail_msdu) { + ret = ath11k_dp_rx_mon_deliver(ar, mac_id, head_msdu, ++ &pmon->mon_ppdu_info, + tail_msdu, napi); + rx_mon_stats->dest_mpdu_done++; + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, "full mon: deliver ppdu\n"); +--- a/drivers/net/wireless/ath/ath11k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath11k/hal_desc.h +@@ -474,6 +474,7 @@ enum hal_tlv_tag { + + #define HAL_TLV_HDR_TAG GENMASK(9, 1) + #define HAL_TLV_HDR_LEN GENMASK(25, 10) ++#define HAL_TLV_USR_ID GENMASK(31, 26) + + #define HAL_TLV_ALIGN 4 + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -73,6 +73,36 @@ enum hal_rx_mon_status { + HAL_RX_MON_STATUS_BUF_DONE, + }; + ++struct hal_rx_user_status { ++ u32 mcs:4, ++ nss:3, ++ ofdma_info_valid:1, ++ dl_ofdma_ru_start_index:7, ++ dl_ofdma_ru_width:7, ++ dl_ofdma_ru_size:8; ++ u32 ul_ofdma_user_v0_word0; ++ u32 ul_ofdma_user_v0_word1; ++ u32 ast_index; ++ u32 tid; ++ u16 tcp_msdu_count; ++ u16 udp_msdu_count; ++ u16 other_msdu_count; ++ u16 frame_control; ++ u8 frame_control_info_valid; ++ u8 data_sequence_control_info_valid; ++ u16 first_data_seq_ctrl; ++ u32 preamble_type; ++ u16 ht_flags; ++ u16 vht_flags; ++ u16 he_flags; ++ u8 rs_flags; ++ u32 mpdu_cnt_fcs_ok; ++ u32 mpdu_cnt_fcs_err; ++ u32 mpdu_fcs_ok_bitmap[8]; ++ u32 mpdu_ok_byte_count; ++ u32 mpdu_err_byte_count; ++}; ++ + #define HAL_TLV_STATUS_PPDU_NOT_DONE HAL_RX_MON_STATUS_PPDU_NOT_DONE + #define HAL_TLV_STATUS_PPDU_DONE HAL_RX_MON_STATUS_PPDU_DONE + #define HAL_TLV_STATUS_BUF_DONE HAL_RX_MON_STATUS_BUF_DONE +@@ -107,6 +137,12 @@ struct hal_rx_mon_ppdu_info { + u8 mcs; + u8 nss; + u8 bw; ++ u8 vht_flag_values1; ++ u8 vht_flag_values2; ++ u8 vht_flag_values3[4]; ++ u8 vht_flag_values4; ++ u8 vht_flag_values5; ++ u16 vht_flag_values6; + u8 is_stbc; + u8 gi; + u8 ldpc; +@@ -114,10 +150,46 @@ struct hal_rx_mon_ppdu_info { + u8 rssi_comb; + u8 rssi_chain_pri20[HAL_RX_MAX_NSS]; + u8 tid; ++ u16 ht_flags; ++ u16 vht_flags; ++ u16 he_flags; ++ u16 he_mu_flags; + u8 dcm; + u8 ru_alloc; + u8 reception_type; ++ u64 tsft; + u64 rx_duration; ++ u16 frame_control; ++ u32 ast_index; ++ u8 rs_fcs_err; ++ u8 rs_flags; ++ u8 cck_flag; ++ u8 ofdm_flag; ++ u8 ulofdma_flag; ++ u8 frame_control_info_valid; ++ u16 he_per_user_1; ++ u16 he_per_user_2; ++ u8 he_per_user_position; ++ u8 he_per_user_known; ++ u16 he_flags1; ++ u16 he_flags2; ++ u8 he_RU[4]; ++ u16 he_data1; ++ u16 he_data2; ++ u16 he_data3; ++ u16 he_data4; ++ u16 he_data5; ++ u16 he_data6; ++ u32 ppdu_len; ++ u32 prev_ppdu_id; ++ u32 device_id; ++ u16 first_data_seq_ctrl; ++ u8 monitor_direct_used; ++ u8 data_sequence_control_info_valid; ++ u8 ltf_size; ++ u8 rxpcu_filter_pass; ++ char rssi_chain[8][8]; ++ struct hal_rx_user_status userstats; + }; + + #define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0) +@@ -150,6 +222,9 @@ struct hal_rx_ppdu_start { + #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP GENMASK(15, 0) + #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP GENMASK(31, 16) + ++#define HAL_RX_PPDU_END_USER_STATS_RSVD2_6_MPDU_OK_BYTE_COUNT GENMASK(24, 0) ++#define HAL_RX_PPDU_END_USER_STATS_RSVD2_8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0) ++ + struct hal_rx_ppdu_end_user_stats { + __le32 rsvd0[2]; + __le32 info0; +@@ -164,6 +239,16 @@ struct hal_rx_ppdu_end_user_stats { + __le32 rsvd2[11]; + } __packed; + ++struct hal_rx_ppdu_end_user_stats_ext { ++ u32 info0; ++ u32 info1; ++ u32 info2; ++ u32 info3; ++ u32 info4; ++ u32 info5; ++ u32 info6; ++} __packed; ++ + #define HAL_RX_HT_SIG_INFO_INFO0_MCS GENMASK(6, 0) + #define HAL_RX_HT_SIG_INFO_INFO0_BW BIT(7) + +@@ -212,25 +297,62 @@ enum hal_rx_vht_sig_a_gi_setting { + HAL_RX_VHT_SIG_A_SHORT_GI_AMBIGUITY = 3, + }; + ++#define HAL_RX_SU_MU_CODING_LDPC 0x01 ++ ++#define HE_GI_0_8 0 ++#define HE_GI_0_4 1 ++#define HE_GI_1_6 2 ++#define HE_GI_3_2 3 ++ ++#define HE_LTF_1_X 0 ++#define HE_LTF_2_X 1 ++#define HE_LTF_4_X 2 ++#define HE_LTF_UNKNOWN 3 ++ + #define HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS GENMASK(6, 3) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM BIT(7) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW GENMASK(20, 19) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO0_CP_LTF_SIZE GENMASK(22, 21) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS GENMASK(25, 23) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_BSS_COLOR GENMASK(13, 8) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_SPATIAL_REUSE GENMASK(18, 15) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_FORMAT_IND BIT(0) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_BEAM_CHANGE BIT(1) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_DL_UL_FLAG BIT(2) + ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXOP_DURATION GENMASK(6, 0) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING BIT(7) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_LDPC_EXTRA BIT(8) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC BIT(9) + #define HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF BIT(10) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_PKT_EXT_FACTOR GENMASK(12, 11) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_PKT_EXT_PE_DISAM BIT(13) ++#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_DOPPLER_IND BIT(15) + + struct hal_rx_he_sig_a_su_info { + __le32 info0; + __le32 info1; + } __packed; + +-#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW GENMASK(17, 15) +-#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_CP_LTF_SIZE GENMASK(24, 23) +- ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_UL_FLAG BIT(1) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_MCS_OF_SIGB GENMASK(3, 1) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_DCM_OF_SIGB BIT(4) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_BSS_COLOR GENMASK(10, 5) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_SPATIAL_REUSE GENMASK(14, 11) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW GENMASK(17, 15) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_NUM_SIGB_SYMB GENMASK(21, 18) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_COMP_MODE_SIGB BIT(22) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_CP_LTF_SIZE GENMASK(24, 23) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_DOPPLER_INDICATION BIT(25) ++ ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_TXOP_DURATION GENMASK(6, 0) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_CODING BIT(7) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_NUM_LTF_SYMB GENMASK(10, 8) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_LDPC_EXTRA BIT(11) + #define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_STBC BIT(12) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_TXBF BIT(10) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_PKT_EXT_FACTOR GENMASK(14, 13) ++#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_PKT_EXT_PE_DISAM BIT(15) + + struct hal_rx_he_sig_a_mu_dl_info { + __le32 info0; +@@ -243,6 +365,7 @@ struct hal_rx_he_sig_b1_mu_info { + __le32 info0; + } __packed; + ++#define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_ID GENMASK(10, 0) + #define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_MCS GENMASK(18, 15) + #define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_CODING BIT(20) + #define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS GENMASK(31, 29) +@@ -251,6 +374,7 @@ struct hal_rx_he_sig_b2_mu_info { + __le32 info0; + } __packed; + ++#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_ID GENMASK(10, 0) + #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_NSTS GENMASK(13, 11) + #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF BIT(19) + #define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_MCS GENMASK(18, 15) +@@ -279,11 +403,14 @@ struct hal_rx_phyrx_rssi_legacy_info { + + #define HAL_RX_MPDU_INFO_INFO0_PEERID GENMASK(31, 16) + #define HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855 GENMASK(15, 0) ++#define HAL_RX_MPDU_INFO_INFO1_MPDU_LEN GENMASK(13, 0) + + struct hal_rx_mpdu_info { + __le32 rsvd0; + __le32 info0; +- __le32 rsvd1[21]; ++ __le32 rsvd1[11]; ++ __le32 info1; ++ __le32 rsvd2[9]; + } __packed; + + struct hal_rx_mpdu_info_wcn6855 { diff --git a/package/kernel/mac80211/patches/ath11k/0190-ath11k-translate-HE-status-to-radiotap-format.patch b/package/kernel/mac80211/patches/ath11k/0190-ath11k-translate-HE-status-to-radiotap-format.patch new file mode 100644 index 000000000..5212e1315 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0190-ath11k-translate-HE-status-to-radiotap-format.patch @@ -0,0 +1,686 @@ +From ab0a9ef605cf527c9754c2e7b055a391a9f0233c Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Wed, 16 Feb 2022 17:21:12 -0800 +Subject: [PATCH] ath11k: translate HE status to radiotap format + +Translate HE status to radiotap format. This uses HE radiotap +definitions from include/net/ieee80211_radiotap.h. + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Signed-off-by: Anilkumar Kolli +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220217012112.31211-4-pradeepc@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 31 +- + drivers/net/wireless/ath/ath11k/hal_rx.c | 471 ++++++++++++++++++++--- + 2 files changed, 438 insertions(+), 64 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4940,29 +4940,44 @@ ath11k_dp_rx_update_radiotap_he_mu(struc + rtap_buf[rtap_len] = rx_status->he_RU[3]; + } + +-static void ath11k_update_radiotap(struct hal_rx_mon_ppdu_info *ppduinfo, ++static void ath11k_update_radiotap(struct ath11k *ar, ++ struct hal_rx_mon_ppdu_info *ppduinfo, + struct sk_buff *mon_skb, + struct ieee80211_rx_status *rxs) + { ++ struct ieee80211_supported_band *sband; + u8 *ptr = NULL; + ++ rxs->flag |= RX_FLAG_MACTIME_START; ++ rxs->signal = ppduinfo->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; ++ ++ if (ppduinfo->nss) ++ rxs->nss = ppduinfo->nss; ++ + if (ppduinfo->he_mu_flags) { + rxs->flag |= RX_FLAG_RADIOTAP_HE_MU; + rxs->encoding = RX_ENC_HE; + ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he_mu)); + ath11k_dp_rx_update_radiotap_he_mu(ppduinfo, ptr); +- } +- if (ppduinfo->he_flags) { ++ } else if (ppduinfo->he_flags) { + rxs->flag |= RX_FLAG_RADIOTAP_HE; + rxs->encoding = RX_ENC_HE; + ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he)); + ath11k_dp_rx_update_radiotap_he(ppduinfo, ptr); ++ rxs->rate_idx = ppduinfo->rate; ++ } else if (ppduinfo->vht_flags) { ++ rxs->encoding = RX_ENC_VHT; ++ rxs->rate_idx = ppduinfo->rate; ++ } else if (ppduinfo->ht_flags) { ++ rxs->encoding = RX_ENC_HT; ++ rxs->rate_idx = ppduinfo->rate; ++ } else { ++ rxs->encoding = RX_ENC_LEGACY; ++ sband = &ar->mac.sbands[rxs->band]; ++ rxs->rate_idx = ath11k_mac_hw_rate_to_idx(sband, ppduinfo->rate, ++ ppduinfo->cck_flag); + } + +- rxs->flag |= RX_FLAG_MACTIME_START; +- rxs->signal = ppduinfo->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; +- rxs->nss = ppduinfo->nss; +- + rxs->mactime = ppduinfo->tsft; + } + +@@ -5003,7 +5018,7 @@ static int ath11k_dp_rx_mon_deliver(stru + } else { + rxs->flag |= RX_FLAG_ALLOW_SAME_PN; + } +- ath11k_update_radiotap(ppduinfo, mon_skb, rxs); ++ ath11k_update_radiotap(ar, ppduinfo, mon_skb, rxs); + + ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb, rxs); + mon_skb = skb_next; +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -456,10 +456,12 @@ void ath11k_hal_reo_status_queue_stats(s + desc->info0)); + ath11k_dbg(ab, ATH11k_DBG_HAL, "pn = [%08x, %08x, %08x, %08x]\n", + desc->pn[0], desc->pn[1], desc->pn[2], desc->pn[3]); +- ath11k_dbg(ab, ATH11k_DBG_HAL, "last_rx: enqueue_tstamp %08x dequeue_tstamp %08x\n", ++ ath11k_dbg(ab, ATH11k_DBG_HAL, ++ "last_rx: enqueue_tstamp %08x dequeue_tstamp %08x\n", + desc->last_rx_enqueue_timestamp, + desc->last_rx_dequeue_timestamp); +- ath11k_dbg(ab, ATH11k_DBG_HAL, "rx_bitmap [%08x %08x %08x %08x %08x %08x %08x %08x]\n", ++ ath11k_dbg(ab, ATH11k_DBG_HAL, ++ "rx_bitmap [%08x %08x %08x %08x %08x %08x %08x %08x]\n", + desc->rx_bitmap[0], desc->rx_bitmap[1], desc->rx_bitmap[2], + desc->rx_bitmap[3], desc->rx_bitmap[4], desc->rx_bitmap[5], + desc->rx_bitmap[6], desc->rx_bitmap[7]); +@@ -803,12 +805,75 @@ void ath11k_hal_reo_init_cmd_ring(struct + } + } + ++#define HAL_MAX_UL_MU_USERS 37 ++static inline void ++ath11k_hal_rx_handle_ofdma_info(void *rx_tlv, ++ struct hal_rx_user_status *rx_user_status) ++{ ++ struct hal_rx_ppdu_end_user_stats *ppdu_end_user = ++ (struct hal_rx_ppdu_end_user_stats *)rx_tlv; ++ ++ rx_user_status->ul_ofdma_user_v0_word0 = __le32_to_cpu(ppdu_end_user->info6); ++ ++ rx_user_status->ul_ofdma_user_v0_word1 = __le32_to_cpu(ppdu_end_user->rsvd2[10]); ++} ++ ++static inline void ++ath11k_hal_rx_populate_byte_count(void *rx_tlv, void *ppduinfo, ++ struct hal_rx_user_status *rx_user_status) ++{ ++ struct hal_rx_ppdu_end_user_stats *ppdu_end_user = ++ (struct hal_rx_ppdu_end_user_stats *)rx_tlv; ++ ++ rx_user_status->mpdu_ok_byte_count = ++ FIELD_GET(HAL_RX_PPDU_END_USER_STATS_RSVD2_6_MPDU_OK_BYTE_COUNT, ++ __le32_to_cpu(ppdu_end_user->rsvd2[6])); ++ rx_user_status->mpdu_err_byte_count = ++ FIELD_GET(HAL_RX_PPDU_END_USER_STATS_RSVD2_8_MPDU_ERR_BYTE_COUNT, ++ __le32_to_cpu(ppdu_end_user->rsvd2[8])); ++} ++ ++static inline void ++ath11k_hal_rx_populate_mu_user_info(void *rx_tlv, struct hal_rx_mon_ppdu_info *ppdu_info, ++ struct hal_rx_user_status *rx_user_status) ++{ ++ rx_user_status->ast_index = ppdu_info->ast_index; ++ rx_user_status->tid = ppdu_info->tid; ++ rx_user_status->tcp_msdu_count = ++ ppdu_info->tcp_msdu_count; ++ rx_user_status->udp_msdu_count = ++ ppdu_info->udp_msdu_count; ++ rx_user_status->other_msdu_count = ++ ppdu_info->other_msdu_count; ++ rx_user_status->frame_control = ppdu_info->frame_control; ++ rx_user_status->frame_control_info_valid = ++ ppdu_info->frame_control_info_valid; ++ rx_user_status->data_sequence_control_info_valid = ++ ppdu_info->data_sequence_control_info_valid; ++ rx_user_status->first_data_seq_ctrl = ++ ppdu_info->first_data_seq_ctrl; ++ rx_user_status->preamble_type = ppdu_info->preamble_type; ++ rx_user_status->ht_flags = ppdu_info->ht_flags; ++ rx_user_status->vht_flags = ppdu_info->vht_flags; ++ rx_user_status->he_flags = ppdu_info->he_flags; ++ rx_user_status->rs_flags = ppdu_info->rs_flags; ++ ++ rx_user_status->mpdu_cnt_fcs_ok = ++ ppdu_info->num_mpdu_fcs_ok; ++ rx_user_status->mpdu_cnt_fcs_err = ++ ppdu_info->num_mpdu_fcs_err; ++ ++ ath11k_hal_rx_populate_byte_count(rx_tlv, ppdu_info, rx_user_status); ++} ++ + static enum hal_rx_mon_status + ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, + struct hal_rx_mon_ppdu_info *ppdu_info, +- u32 tlv_tag, u8 *tlv_data) ++ u32 tlv_tag, u8 *tlv_data, u32 userid) + { +- u32 info0, info1; ++ u32 info0, info1, value; ++ u8 he_dcm = 0, he_stbc = 0; ++ u16 he_gi = 0, he_ltf = 0; + + switch (tlv_tag) { + case HAL_RX_PPDU_START: { +@@ -829,6 +894,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + info0 = __le32_to_cpu(eu_stats->info0); + info1 = __le32_to_cpu(eu_stats->info1); + ++ ppdu_info->ast_index = ++ FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX, ++ __le32_to_cpu(eu_stats->info2)); + ppdu_info->tid = + ffs(FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP, + __le32_to_cpu(eu_stats->info6))) - 1; +@@ -852,6 +920,44 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + ppdu_info->num_mpdu_fcs_err = + FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR, + info0); ++ switch (ppdu_info->preamble_type) { ++ case HAL_RX_PREAMBLE_11N: ++ ppdu_info->ht_flags = 1; ++ break; ++ case HAL_RX_PREAMBLE_11AC: ++ ppdu_info->vht_flags = 1; ++ break; ++ case HAL_RX_PREAMBLE_11AX: ++ ppdu_info->he_flags = 1; ++ break; ++ default: ++ break; ++ } ++ ++ if (userid < HAL_MAX_UL_MU_USERS) { ++ struct hal_rx_user_status *rxuser_stats = ++ &ppdu_info->userstats; ++ ++ ath11k_hal_rx_handle_ofdma_info(tlv_data, rxuser_stats); ++ ath11k_hal_rx_populate_mu_user_info(tlv_data, ppdu_info, ++ rxuser_stats); ++ } ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[0] = ++ __le32_to_cpu(eu_stats->rsvd1[0]); ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[1] = ++ __le32_to_cpu(eu_stats->rsvd1[1]); ++ ++ break; ++ } ++ case HAL_RX_PPDU_END_USER_STATS_EXT: { ++ struct hal_rx_ppdu_end_user_stats_ext *eu_stats = ++ (struct hal_rx_ppdu_end_user_stats_ext *)tlv_data; ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[2] = eu_stats->info1; ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[3] = eu_stats->info2; ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[4] = eu_stats->info3; ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[5] = eu_stats->info4; ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[6] = eu_stats->info5; ++ ppdu_info->userstats.mpdu_fcs_ok_bitmap[7] = eu_stats->info6; + break; + } + case HAL_PHYRX_HT_SIG: { +@@ -950,50 +1056,151 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + else + ppdu_info->reception_type = + HAL_RX_RECEPTION_TYPE_MU_MIMO; ++ ppdu_info->vht_flag_values5 = group_id; ++ ppdu_info->vht_flag_values3[0] = (((ppdu_info->mcs) << 4) | ++ ppdu_info->nss); ++ ppdu_info->vht_flag_values2 = ppdu_info->bw; ++ ppdu_info->vht_flag_values4 = ++ FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING, info1); + break; + } + case HAL_PHYRX_HE_SIG_A_SU: { + struct hal_rx_he_sig_a_su_info *he_sig_a = + (struct hal_rx_he_sig_a_su_info *)tlv_data; +- u32 nsts, cp_ltf, dcm; + ++ ppdu_info->he_flags = 1; + info0 = __le32_to_cpu(he_sig_a->info0); + info1 = __le32_to_cpu(he_sig_a->info1); + +- ppdu_info->mcs = +- FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS, +- info0); +- ppdu_info->bw = +- FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW, +- info0); +- ppdu_info->ldpc = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING, info0); +- ppdu_info->is_stbc = info1 & +- HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC; +- ppdu_info->beamformed = info1 & +- HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF; +- dcm = info0 & HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM; +- cp_ltf = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_CP_LTF_SIZE, +- info0); +- nsts = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS, info0); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_FORMAT_IND, info0); + +- switch (cp_ltf) { ++ if (value == 0) ++ ppdu_info->he_data1 = IEEE80211_RADIOTAP_HE_DATA1_FORMAT_TRIG; ++ else ++ ppdu_info->he_data1 = IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU; ++ ++ ppdu_info->he_data1 |= ++ IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN; ++ ++ ppdu_info->he_data2 |= ++ IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN; ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_BSS_COLOR, info0); ++ ppdu_info->he_data3 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_BEAM_CHANGE, info0); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_DL_UL_FLAG, info0); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_UL_DL, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS, info0); ++ ppdu_info->mcs = value; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS, value); ++ ++ he_dcm = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM, info0); ++ ppdu_info->dcm = he_dcm; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM, he_dcm); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING, info1); ++ ppdu_info->ldpc = (value == HAL_RX_SU_MU_CODING_LDPC) ? 1 : 0; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_CODING, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_LDPC_EXTRA, info1); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG, value); ++ he_stbc = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC, info1); ++ ppdu_info->is_stbc = he_stbc; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_STBC, he_stbc); ++ ++ /* data4 */ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_SPATIAL_REUSE, info0); ++ ppdu_info->he_data4 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE, value); ++ ++ /* data5 */ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW, info0); ++ ppdu_info->bw = value; ++ ppdu_info->he_data5 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_CP_LTF_SIZE, info0); ++ switch (value) { + case 0: ++ he_gi = HE_GI_0_8; ++ he_ltf = HE_LTF_1_X; ++ break; + case 1: +- ppdu_info->gi = HAL_RX_GI_0_8_US; +- break; ++ he_gi = HE_GI_0_8; ++ he_ltf = HE_LTF_2_X; ++ break; + case 2: +- ppdu_info->gi = HAL_RX_GI_1_6_US; +- break; ++ he_gi = HE_GI_1_6; ++ he_ltf = HE_LTF_2_X; ++ break; + case 3: +- if (dcm && ppdu_info->is_stbc) +- ppdu_info->gi = HAL_RX_GI_0_8_US; +- else +- ppdu_info->gi = HAL_RX_GI_3_2_US; +- break; ++ if (he_dcm && he_stbc) { ++ he_gi = HE_GI_0_8; ++ he_ltf = HE_LTF_4_X; ++ } else { ++ he_gi = HE_GI_3_2; ++ he_ltf = HE_LTF_4_X; ++ } ++ break; + } ++ ppdu_info->gi = he_gi; ++ he_gi = (he_gi != 0) ? he_gi - 1 : 0; ++ ppdu_info->he_data5 |= FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_GI, he_gi); ++ ppdu_info->ltf_size = he_ltf; ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE, ++ (he_ltf == HE_LTF_4_X) ? he_ltf - 1 : he_ltf); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS, info0); ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_PKT_EXT_FACTOR, info1); ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF, info1); ++ ppdu_info->beamformed = value; ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_TXBF, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_PKT_EXT_PE_DISAM, info1); ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG, value); ++ ++ /* data6 */ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS, info0); ++ value++; ++ ppdu_info->nss = value; ++ ppdu_info->he_data6 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA6_NSTS, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_DOPPLER_IND, info1); ++ ppdu_info->he_data6 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA6_DOPPLER, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXOP_DURATION, info1); ++ ppdu_info->he_data6 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA6_TXOP, value); + +- ppdu_info->nss = nsts + 1; +- ppdu_info->dcm = dcm; + ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU; + break; + } +@@ -1001,29 +1208,142 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl = + (struct hal_rx_he_sig_a_mu_dl_info *)tlv_data; + +- u32 cp_ltf; +- + info0 = __le32_to_cpu(he_sig_a_mu_dl->info0); + info1 = __le32_to_cpu(he_sig_a_mu_dl->info1); + +- ppdu_info->bw = +- FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW, +- info0); +- cp_ltf = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_CP_LTF_SIZE, +- info0); ++ ppdu_info->he_mu_flags = 1; + +- switch (cp_ltf) { ++ ppdu_info->he_data1 = IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU; ++ ppdu_info->he_data1 |= ++ IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN; ++ ++ ppdu_info->he_data2 = ++ IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN; ++ ++ /*data3*/ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_BSS_COLOR, info0); ++ ppdu_info->he_data3 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_UL_FLAG, info0); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_UL_DL, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_LDPC_EXTRA, info1); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_STBC, info1); ++ he_stbc = value; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_STBC, value); ++ ++ /*data4*/ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_SPATIAL_REUSE, info0); ++ ppdu_info->he_data4 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE, value); ++ ++ /*data5*/ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW, info0); ++ ppdu_info->bw = value; ++ ppdu_info->he_data5 = ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_CP_LTF_SIZE, info0); ++ switch (value) { + case 0: ++ he_gi = HE_GI_0_8; ++ he_ltf = HE_LTF_4_X; ++ break; + case 1: +- ppdu_info->gi = HAL_RX_GI_0_8_US; ++ he_gi = HE_GI_0_8; ++ he_ltf = HE_LTF_2_X; + break; + case 2: +- ppdu_info->gi = HAL_RX_GI_1_6_US; ++ he_gi = HE_GI_1_6; ++ he_ltf = HE_LTF_2_X; + break; + case 3: +- ppdu_info->gi = HAL_RX_GI_3_2_US; ++ he_gi = HE_GI_3_2; ++ he_ltf = HE_LTF_4_X; + break; + } ++ ppdu_info->gi = he_gi; ++ he_gi = (he_gi != 0) ? he_gi - 1 : 0; ++ ppdu_info->he_data5 |= FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_GI, he_gi); ++ ppdu_info->ltf_size = he_ltf; ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE, ++ (he_ltf == HE_LTF_4_X) ? he_ltf - 1 : he_ltf); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_NUM_LTF_SYMB, info1); ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_PKT_EXT_FACTOR, ++ info1); ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_PKT_EXT_PE_DISAM, ++ info1); ++ ppdu_info->he_data5 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG, value); ++ ++ /*data6*/ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_DOPPLER_INDICATION, ++ info0); ++ ppdu_info->he_data6 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA6_DOPPLER, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_TXOP_DURATION, info1); ++ ppdu_info->he_data6 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA6_TXOP, value); ++ ++ /* HE-MU Flags */ ++ /* HE-MU-flags1 */ ++ ppdu_info->he_flags1 = ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN | ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN | ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN | ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN | ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN; ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_MCS_OF_SIGB, info0); ++ ppdu_info->he_flags1 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN, ++ value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_DCM_OF_SIGB, info0); ++ ppdu_info->he_flags1 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN, ++ value); ++ ++ /* HE-MU-flags2 */ ++ ppdu_info->he_flags2 = ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN; ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW, info0); ++ ppdu_info->he_flags2 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW, ++ value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_COMP_MODE_SIGB, info0); ++ ppdu_info->he_flags2 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP, value); ++ value = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_NUM_SIGB_SYMB, info0); ++ value = value - 1; ++ ppdu_info->he_flags2 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS, ++ value); + + ppdu_info->is_stbc = info1 & + HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_STBC; +@@ -1041,7 +1361,7 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + info0); + ppdu_info->ru_alloc = + ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(ru_tones); +- ++ ppdu_info->he_RU[0] = ru_tones; + ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; + break; + } +@@ -1051,14 +1371,25 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + + info0 = __le32_to_cpu(he_sig_b2_mu->info0); + ++ ppdu_info->he_data1 |= IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN; ++ + ppdu_info->mcs = +- FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_MCS, +- info0); ++ FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_MCS, info0); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS, ppdu_info->mcs); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_CODING, info0); ++ ppdu_info->ldpc = value; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_CODING, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_ID, info0); ++ ppdu_info->he_data4 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID, value); ++ + ppdu_info->nss = +- FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS, +- info0) + 1; +- ppdu_info->ldpc = FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_CODING, +- info0); ++ FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS, info0) + 1; + break; + } + case HAL_PHYRX_HE_SIG_B2_OFDMA: { +@@ -1067,17 +1398,40 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + + info0 = __le32_to_cpu(he_sig_b2_ofdma->info0); + ++ ppdu_info->he_data1 |= ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN; ++ ++ /* HE-data2 */ ++ ppdu_info->he_data2 |= IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN; ++ + ppdu_info->mcs = + FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_MCS, + info0); ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS, ppdu_info->mcs); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_DCM, info0); ++ he_dcm = value; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM, value); ++ ++ value = FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_CODING, info0); ++ ppdu_info->ldpc = value; ++ ppdu_info->he_data3 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA3_CODING, value); ++ ++ /* HE-data4 */ ++ value = FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_ID, info0); ++ ppdu_info->he_data4 |= ++ FIELD_PREP(IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID, value); ++ + ppdu_info->nss = + FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_NSTS, + info0) + 1; + ppdu_info->beamformed = +- info0 & +- HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF; +- ppdu_info->ldpc = FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_CODING, +- info0); ++ info0 & HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF; + ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA; + break; + } +@@ -1119,6 +1473,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + ppdu_info->rx_duration = + FIELD_GET(HAL_RX_PPDU_END_DURATION, + __le32_to_cpu(ppdu_rx_duration->info0)); ++ ppdu_info->tsft = __le32_to_cpu(ppdu_rx_duration->rsvd0[1]); ++ ppdu_info->tsft = (ppdu_info->tsft << 32) | ++ __le32_to_cpu(ppdu_rx_duration->rsvd0[0]); + break; + } + case HAL_DUMMY: +@@ -1142,12 +1499,14 @@ ath11k_hal_rx_parse_mon_status(struct at + enum hal_rx_mon_status hal_status = HAL_RX_MON_STATUS_BUF_DONE; + u16 tlv_tag; + u16 tlv_len; ++ u32 tlv_userid = 0; + u8 *ptr = skb->data; + + do { + tlv = (struct hal_tlv_hdr *)ptr; + tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl); + tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl); ++ tlv_userid = FIELD_GET(HAL_TLV_USR_ID, tlv->tl); + ptr += sizeof(*tlv); + + /* The actual length of PPDU_END is the combined length of many PHY +@@ -1159,7 +1518,7 @@ ath11k_hal_rx_parse_mon_status(struct at + tlv_len = sizeof(struct hal_rx_rxpcu_classification_overview); + + hal_status = ath11k_hal_rx_parse_mon_status_tlv(ab, ppdu_info, +- tlv_tag, ptr); ++ tlv_tag, ptr, tlv_userid); + ptr += tlv_len; + ptr = PTR_ALIGN(ptr, HAL_TLV_ALIGN); + diff --git a/package/kernel/mac80211/patches/ath11k/0191-ath11k-add-dbring-debug-support.patch b/package/kernel/mac80211/patches/ath11k/0191-ath11k-add-dbring-debug-support.patch new file mode 100644 index 000000000..bcece4c98 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0191-ath11k-add-dbring-debug-support.patch @@ -0,0 +1,509 @@ +From 691425b4a41fe5843ea424a93ee373f29b1040a5 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Sun, 20 Feb 2022 19:37:39 +0530 +Subject: [PATCH] ath11k: add dbring debug support + +Target copies spectral report and CFR report through dbring to +host for further processing. This mechanism involves ring and +buffer management in the Host, FW, and uCode, where improper +tail pointer update issues are seen. + +This dbring debug support help to debug such issues by tracking +head and tail pointer movement along with the timestamp at which +each buffer is received and replenished. + +Provide a debugfs interface to enalbe/disable dbring debug +support and dump the dbring debug entries. + +Also introduced a new hardware param to add dbring debugfs support +for few hardwares which are using dbings. + +Usage: + +echo > /sys/kernel/debug/ath11k/ipq8074_2/ +mac0/enable_dbr_debug + +dbr_id: 0 for spectral and 1 for CFR +val: 0 - disable, 1 - enable. + +Tested-on: IPQ8074 WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1645366059-11798-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 + + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/dbring.c | 19 +- + drivers/net/wireless/ath/ath11k/debugfs.c | 221 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 41 ++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 6 files changed, 283 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -99,6 +99,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, ++ .dbr_debug_support = true, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -164,6 +165,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, ++ .dbr_debug_support = true, + }, + { + .name = "qca6390 hw2.0", +@@ -228,6 +230,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, ++ .dbr_debug_support = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -292,6 +295,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, ++ .dbr_debug_support = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -356,6 +360,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, ++ .dbr_debug_support = false, + }, + { + .name = "wcn6855 hw2.1", +@@ -419,6 +424,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, ++ .dbr_debug_support = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -461,6 +461,7 @@ struct ath11k_debug { + u32 rx_filter; + u32 mem_offset; + u32 module_id_bitmap[MAX_MODULE_ID_BITMAP_WORDS]; ++ struct ath11k_debug_dbr *dbr_debug[WMI_DIRECT_BUF_MAX]; + }; + + struct ath11k_per_peer_tx_stats { +--- a/drivers/net/wireless/ath/ath11k/dbring.c ++++ b/drivers/net/wireless/ath/ath11k/dbring.c +@@ -37,7 +37,8 @@ static void ath11k_dbring_fill_magic_val + + static int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, +- struct ath11k_dbring_element *buff) ++ struct ath11k_dbring_element *buff, ++ enum wmi_direct_buffer_module id) + { + struct ath11k_base *ab = ar->ab; + struct hal_srng *srng; +@@ -84,6 +85,7 @@ static int ath11k_dbring_bufs_replenish( + + ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0); + ++ ath11k_debugfs_add_dbring_entry(ar, id, ATH11K_DBG_DBR_EVENT_REPLENISH, srng); + ath11k_hal_srng_access_end(ab, srng); + + return 0; +@@ -101,7 +103,8 @@ err: + } + + static int ath11k_dbring_fill_bufs(struct ath11k *ar, +- struct ath11k_dbring *ring) ++ struct ath11k_dbring *ring, ++ enum wmi_direct_buffer_module id) + { + struct ath11k_dbring_element *buff; + struct hal_srng *srng; +@@ -129,7 +132,7 @@ static int ath11k_dbring_fill_bufs(struc + kfree(buff); + break; + } +- ret = ath11k_dbring_bufs_replenish(ar, ring, buff); ++ ret = ath11k_dbring_bufs_replenish(ar, ring, buff, id); + if (ret) { + ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n", + num_remain, req_entries); +@@ -210,7 +213,7 @@ int ath11k_dbring_buf_setup(struct ath11 + ring->hp_addr = ath11k_hal_srng_get_hp_addr(ar->ab, srng); + ring->tp_addr = ath11k_hal_srng_get_tp_addr(ar->ab, srng); + +- ret = ath11k_dbring_fill_bufs(ar, ring); ++ ret = ath11k_dbring_fill_bufs(ar, ring, db_cap->id); + + return ret; + } +@@ -270,7 +273,7 @@ int ath11k_dbring_buffer_release_event(s + struct ath11k_buffer_addr desc; + u8 *vaddr_unalign; + u32 num_entry, num_buff_reaped; +- u8 pdev_idx, rbm; ++ u8 pdev_idx, rbm, module_id; + u32 cookie; + int buf_id; + int size; +@@ -278,6 +281,7 @@ int ath11k_dbring_buffer_release_event(s + int ret = 0; + + pdev_idx = ev->fixed.pdev_id; ++ module_id = ev->fixed.module_id; + + if (pdev_idx >= ab->num_radios) { + ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx); +@@ -346,6 +350,9 @@ int ath11k_dbring_buffer_release_event(s + dma_unmap_single(ab->dev, buff->paddr, ring->buf_sz, + DMA_FROM_DEVICE); + ++ ath11k_debugfs_add_dbring_entry(ar, module_id, ++ ATH11K_DBG_DBR_EVENT_RX, srng); ++ + if (ring->handler) { + vaddr_unalign = buff->payload; + handler_data.data = PTR_ALIGN(vaddr_unalign, +@@ -357,7 +364,7 @@ int ath11k_dbring_buffer_release_event(s + + buff->paddr = 0; + memset(buff->payload, 0, size); +- ath11k_dbring_bufs_replenish(ar, ring, buff); ++ ath11k_dbring_bufs_replenish(ar, ring, buff, module_id); + } + + spin_unlock_bh(&srng->lock); +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -52,6 +52,45 @@ static const char *htt_bp_lmac_ring[HTT_ + "MONITOR_DEST_RING", + }; + ++void ath11k_debugfs_add_dbring_entry(struct ath11k *ar, ++ enum wmi_direct_buffer_module id, ++ enum ath11k_dbg_dbr_event event, ++ struct hal_srng *srng) ++{ ++ struct ath11k_debug_dbr *dbr_debug; ++ struct ath11k_dbg_dbr_data *dbr_data; ++ struct ath11k_dbg_dbr_entry *entry; ++ ++ if (id >= WMI_DIRECT_BUF_MAX || event >= ATH11K_DBG_DBR_EVENT_MAX) ++ return; ++ ++ dbr_debug = ar->debug.dbr_debug[id]; ++ if (!dbr_debug) ++ return; ++ ++ if (!dbr_debug->dbr_debug_enabled) ++ return; ++ ++ dbr_data = &dbr_debug->dbr_dbg_data; ++ ++ spin_lock_bh(&dbr_data->lock); ++ ++ if (dbr_data->entries) { ++ entry = &dbr_data->entries[dbr_data->dbr_debug_idx]; ++ entry->hp = srng->u.src_ring.hp; ++ entry->tp = *srng->u.src_ring.tp_addr; ++ entry->timestamp = jiffies; ++ entry->event = event; ++ ++ dbr_data->dbr_debug_idx++; ++ if (dbr_data->dbr_debug_idx == ++ dbr_data->num_ring_debug_entries) ++ dbr_data->dbr_debug_idx = 0; ++ } ++ ++ spin_unlock_bh(&dbr_data->lock); ++} ++ + static void ath11k_fw_stats_pdevs_free(struct list_head *head) + { + struct ath11k_fw_stats_pdev *i, *tmp; +@@ -1176,6 +1215,169 @@ static const struct file_operations fops + .open = simple_open + }; + ++static ssize_t ath11k_debug_dump_dbr_entries(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_dbg_dbr_data *dbr_dbg_data = file->private_data; ++ static const char * const event_id_to_string[] = {"empty", "Rx", "Replenish"}; ++ int size = ATH11K_DEBUG_DBR_ENTRIES_MAX * 100; ++ char *buf; ++ int i, ret; ++ int len = 0; ++ ++ buf = kzalloc(size, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ len += scnprintf(buf + len, size - len, ++ "-----------------------------------------\n"); ++ len += scnprintf(buf + len, size - len, ++ "| idx | hp | tp | timestamp | event |\n"); ++ len += scnprintf(buf + len, size - len, ++ "-----------------------------------------\n"); ++ ++ spin_lock_bh(&dbr_dbg_data->lock); ++ ++ for (i = 0; i < dbr_dbg_data->num_ring_debug_entries; i++) { ++ len += scnprintf(buf + len, size - len, ++ "|%4u|%8u|%8u|%11llu|%8s|\n", i, ++ dbr_dbg_data->entries[i].hp, ++ dbr_dbg_data->entries[i].tp, ++ dbr_dbg_data->entries[i].timestamp, ++ event_id_to_string[dbr_dbg_data->entries[i].event]); ++ } ++ ++ spin_unlock_bh(&dbr_dbg_data->lock); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ ++ return ret; ++} ++ ++static const struct file_operations fops_debug_dump_dbr_entries = { ++ .read = ath11k_debug_dump_dbr_entries, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++static void ath11k_debugfs_dbr_dbg_destroy(struct ath11k *ar, int dbr_id) ++{ ++ struct ath11k_debug_dbr *dbr_debug; ++ struct ath11k_dbg_dbr_data *dbr_dbg_data; ++ ++ if (!ar->debug.dbr_debug[dbr_id]) ++ return; ++ ++ dbr_debug = ar->debug.dbr_debug[dbr_id]; ++ dbr_dbg_data = &dbr_debug->dbr_dbg_data; ++ ++ debugfs_remove_recursive(dbr_debug->dbr_debugfs); ++ kfree(dbr_dbg_data->entries); ++ kfree(dbr_debug); ++ ar->debug.dbr_debug[dbr_id] = NULL; ++} ++ ++static int ath11k_debugfs_dbr_dbg_init(struct ath11k *ar, int dbr_id) ++{ ++ struct ath11k_debug_dbr *dbr_debug; ++ struct ath11k_dbg_dbr_data *dbr_dbg_data; ++ static const char * const dbr_id_to_str[] = {"spectral", "CFR"}; ++ ++ if (ar->debug.dbr_debug[dbr_id]) ++ return 0; ++ ++ ar->debug.dbr_debug[dbr_id] = kzalloc(sizeof(*dbr_debug), ++ GFP_KERNEL); ++ ++ if (!ar->debug.dbr_debug[dbr_id]) ++ return -ENOMEM; ++ ++ dbr_debug = ar->debug.dbr_debug[dbr_id]; ++ dbr_dbg_data = &dbr_debug->dbr_dbg_data; ++ ++ if (dbr_debug->dbr_debugfs) ++ return 0; ++ ++ dbr_debug->dbr_debugfs = debugfs_create_dir(dbr_id_to_str[dbr_id], ++ ar->debug.debugfs_pdev); ++ if (IS_ERR_OR_NULL(dbr_debug->dbr_debugfs)) { ++ if (IS_ERR(dbr_debug->dbr_debugfs)) ++ return PTR_ERR(dbr_debug->dbr_debugfs); ++ return -ENOMEM; ++ } ++ ++ dbr_debug->dbr_debug_enabled = true; ++ dbr_dbg_data->num_ring_debug_entries = ATH11K_DEBUG_DBR_ENTRIES_MAX; ++ dbr_dbg_data->dbr_debug_idx = 0; ++ dbr_dbg_data->entries = kcalloc(ATH11K_DEBUG_DBR_ENTRIES_MAX, ++ sizeof(struct ath11k_dbg_dbr_entry), ++ GFP_KERNEL); ++ if (!dbr_dbg_data->entries) ++ return -ENOMEM; ++ ++ spin_lock_init(&dbr_dbg_data->lock); ++ ++ debugfs_create_file("dump_dbr_debug", 0444, dbr_debug->dbr_debugfs, ++ dbr_dbg_data, &fops_debug_dump_dbr_entries); ++ ++ return 0; ++} ++ ++static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k *ar = file->private_data; ++ char buf[32] = {0}; ++ u32 dbr_id, enable; ++ int ret; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (ar->state != ATH11K_STATE_ON) { ++ ret = -ENETDOWN; ++ goto out; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ goto out; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%u %u", &dbr_id, &enable); ++ if (ret != 2 || dbr_id > 1 || enable > 1) { ++ ret = -EINVAL; ++ ath11k_warn(ar->ab, "usage: echo dbr_id:0-Spectral 1-CFR val:0-disable 1-enable\n"); ++ goto out; ++ } ++ ++ if (enable) { ++ ret = ath11k_debugfs_dbr_dbg_init(ar, dbr_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "db ring module debugfs init failed: %d\n", ++ ret); ++ goto out; ++ } ++ } else { ++ ath11k_debugfs_dbr_dbg_destroy(ar, dbr_id); ++ } ++ ++ ret = count; ++out: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++} ++ ++static const struct file_operations fops_dbr_debug = { ++ .write = ath11k_debugfs_write_enable_dbr_dbg, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ + int ath11k_debugfs_register(struct ath11k *ar) + { + struct ath11k_base *ab = ar->ab; +@@ -1218,11 +1420,30 @@ int ath11k_debugfs_register(struct ath11 + &ar->dfs_block_radar_events); + } + ++ if (ab->hw_params.dbr_debug_support) ++ debugfs_create_file("enable_dbr_debug", 0200, ar->debug.debugfs_pdev, ++ ar, &fops_dbr_debug); ++ + return 0; + } + + void ath11k_debugfs_unregister(struct ath11k *ar) + { ++ struct ath11k_debug_dbr *dbr_debug; ++ struct ath11k_dbg_dbr_data *dbr_dbg_data; ++ int i; ++ ++ for (i = 0; i < WMI_DIRECT_BUF_MAX; i++) { ++ dbr_debug = ar->debug.dbr_debug[i]; ++ if (!dbr_debug) ++ continue; ++ ++ dbr_dbg_data = &dbr_debug->dbr_dbg_data; ++ kfree(dbr_dbg_data->entries); ++ debugfs_remove_recursive(dbr_debug->dbr_debugfs); ++ kfree(dbr_debug); ++ ar->debug.dbr_debug[i] = NULL; ++ } + } + + static ssize_t ath11k_write_twt_add_dialog(struct file *file, +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -47,6 +47,36 @@ enum ath11k_dbg_htt_ext_stats_type { + ATH11K_DBG_HTT_NUM_EXT_STATS, + }; + ++#define ATH11K_DEBUG_DBR_ENTRIES_MAX 512 ++ ++enum ath11k_dbg_dbr_event { ++ ATH11K_DBG_DBR_EVENT_INVALID, ++ ATH11K_DBG_DBR_EVENT_RX, ++ ATH11K_DBG_DBR_EVENT_REPLENISH, ++ ATH11K_DBG_DBR_EVENT_MAX, ++}; ++ ++struct ath11k_dbg_dbr_entry { ++ u32 hp; ++ u32 tp; ++ u64 timestamp; ++ enum ath11k_dbg_dbr_event event; ++}; ++ ++struct ath11k_dbg_dbr_data { ++ /* protects ath11k_db_ring_debug data */ ++ spinlock_t lock; ++ struct ath11k_dbg_dbr_entry *entries; ++ u32 dbr_debug_idx; ++ u32 num_ring_debug_entries; ++}; ++ ++struct ath11k_debug_dbr { ++ struct ath11k_dbg_dbr_data dbr_dbg_data; ++ struct dentry *dbr_debugfs; ++ bool dbr_debug_enabled; ++}; ++ + struct debug_htt_stats_req { + bool done; + u8 pdev_id; +@@ -278,6 +308,10 @@ static inline int ath11k_debugfs_rx_filt + + int ath11k_debugfs_add_interface(struct ath11k_vif *arvif); + void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif); ++void ath11k_debugfs_add_dbring_entry(struct ath11k *ar, ++ enum wmi_direct_buffer_module id, ++ enum ath11k_dbg_dbr_event event, ++ struct hal_srng *srng); + + #else + static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab) +@@ -361,6 +395,13 @@ static inline void ath11k_debugfs_remove + { + } + ++static inline void ++ath11k_debugfs_add_dbring_entry(struct ath11k *ar, ++ enum wmi_direct_buffer_module id, ++ enum ath11k_dbg_dbr_event event, ++ struct hal_srng *srng) ++{ ++} + #endif /* CPTCFG_ATH11K_DEBUGFS*/ + + #endif /* _ATH11K_DEBUGFS_H_ */ +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -193,6 +193,7 @@ struct ath11k_hw_params { + bool supports_rssi_stats; + bool fw_wmi_diag_event; + bool current_cc_support; ++ bool dbr_debug_support; + }; + + struct ath11k_hw_ops { diff --git a/package/kernel/mac80211/patches/ath11k/0192-ath11k-remove-unneeded-flush_workqueue.patch b/package/kernel/mac80211/patches/ath11k/0192-ath11k-remove-unneeded-flush_workqueue.patch new file mode 100644 index 000000000..d5623f722 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0192-ath11k-remove-unneeded-flush_workqueue.patch @@ -0,0 +1,26 @@ +From 57fe207f752a95e1929e242dfdb21c6dac741e0d Mon Sep 17 00:00:00 2001 +From: "Lv Ruyi (CGEL ZTE)" +Date: Tue, 1 Mar 2022 01:32:46 +0000 +Subject: [PATCH] ath11k: remove unneeded flush_workqueue + +All work currently pending will be done first by calling destroy_workqueue, +so there is no need to flush it explicitly. + +Reported-by: Zeal Robot +Signed-off-by: Lv Ruyi (CGEL ZTE) +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220301013246.2052570-1-lv.ruyi@zte.com.cn +--- + drivers/net/wireless/ath/ath11k/core.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1417,7 +1417,6 @@ EXPORT_SYMBOL(ath11k_core_deinit); + + void ath11k_core_free(struct ath11k_base *ab) + { +- flush_workqueue(ab->workqueue); + destroy_workqueue(ab->workqueue); + + kfree(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0193-ath11k-Add-basic-WoW-functionalities.patch b/package/kernel/mac80211/patches/ath11k/0193-ath11k-Add-basic-WoW-functionalities.patch new file mode 100644 index 000000000..7185b0cf7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0193-ath11k-Add-basic-WoW-functionalities.patch @@ -0,0 +1,1021 @@ +From ba9177fcef21fa98406e73c472b5ac2eb4ec5f31 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Mar 2022 07:18:15 +0200 +Subject: [PATCH] ath11k: Add basic WoW functionalities + +Implement basic WoW functionalities such as magic-packet, disconnect +and pattern. The logic is very similar to ath10k. + +When WoW is configured, ath11k_core_suspend and ath11k_core_resume +are skipped as WoW configuration and hif suspend/resume are done in +ath11k_wow_op_suspend() and ath11k_wow_op_resume(). + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Baochen Qiang +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644308006-22784-2-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/Makefile | 4 +- + drivers/net/wireless/ath/ath11k/core.c | 33 ++ + drivers/net/wireless/ath/ath11k/core.h | 4 + + drivers/net/wireless/ath/ath11k/htc.c | 6 + + drivers/net/wireless/ath/ath11k/mac.c | 59 +++- + drivers/net/wireless/ath/ath11k/mac.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 158 +++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 76 ++++- + drivers/net/wireless/ath/ath11k/wow.c | 414 +++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wow.h | 45 +++ + 10 files changed, 781 insertions(+), 19 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/Makefile ++++ b/drivers/net/wireless/ath/ath11k/Makefile +@@ -16,14 +16,14 @@ ath11k-y += core.o \ + ce.o \ + peer.o \ + dbring.o \ +- hw.o \ +- wow.o ++ hw.o + + ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o + ath11k-$(CPTCFG_NL80211_TESTMODE) += testmode.o + ath11k-$(CPTCFG_ATH11K_TRACING) += trace.o + ath11k-$(CONFIG_THERMAL) += thermal.o + ath11k-$(CPTCFG_ATH11K_SPECTRAL) += spectral.o ++ath11k-$(CONFIG_PM) += wow.o + + obj-$(CPTCFG_ATH11K_AHB) += ath11k_ahb.o + ath11k_ahb-y += ahb.o +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -428,13 +428,30 @@ static const struct ath11k_hw_params ath + }, + }; + ++static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab) ++{ ++ WARN_ON(!ab->hw_params.single_pdev_only); ++ ++ return &ab->pdevs[0]; ++} ++ + int ath11k_core_suspend(struct ath11k_base *ab) + { + int ret; ++ struct ath11k_pdev *pdev; ++ struct ath11k *ar; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + ++ /* so far single_pdev_only chips have supports_suspend as true ++ * and only the first pdev is valid. ++ */ ++ pdev = ath11k_core_get_single_pdev(ab); ++ ar = pdev->ar; ++ if (!ar || ar->state != ATH11K_STATE_OFF) ++ return 0; ++ + /* TODO: there can frames in queues so for now add delay as a hack. + * Need to implement to handle and remove this delay. + */ +@@ -447,6 +464,12 @@ int ath11k_core_suspend(struct ath11k_ba + return ret; + } + ++ ret = ath11k_mac_wait_tx_complete(ar); ++ if (ret) { ++ ath11k_warn(ab, "failed to wait tx complete: %d\n", ret); ++ return ret; ++ } ++ + ret = ath11k_wow_enable(ab); + if (ret) { + ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret); +@@ -479,10 +502,20 @@ EXPORT_SYMBOL(ath11k_core_suspend); + int ath11k_core_resume(struct ath11k_base *ab) + { + int ret; ++ struct ath11k_pdev *pdev; ++ struct ath11k *ar; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + ++ /* so far signle_pdev_only chips have supports_suspend as true ++ * and only the first pdev is valid. ++ */ ++ pdev = ath11k_core_get_single_pdev(ab); ++ ar = pdev->ar; ++ if (!ar || ar->state != ATH11K_STATE_OFF) ++ return 0; ++ + ret = ath11k_hif_resume(ab); + if (ret) { + ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -23,6 +23,7 @@ + #include "thermal.h" + #include "dbring.h" + #include "spectral.h" ++#include "wow.h" + + #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) + +@@ -590,6 +591,9 @@ struct ath11k { + struct work_struct wmi_mgmt_tx_work; + struct sk_buff_head wmi_mgmt_tx_queue; + ++ struct ath11k_wow wow; ++ struct completion target_suspend; ++ bool target_suspend_ack; + struct ath11k_per_peer_tx_stats peer_tx_stats; + struct list_head ppdu_stats_info; + u32 ppdu_stat_list_depth; +--- a/drivers/net/wireless/ath/ath11k/htc.c ++++ b/drivers/net/wireless/ath/ath11k/htc.c +@@ -272,6 +272,11 @@ void ath11k_htc_tx_completion_handler(st + ep_tx_complete(htc->ab, skb); + } + ++static void ath11k_htc_wakeup_from_suspend(struct ath11k_base *ab) ++{ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot wakeup from suspend is received\n"); ++} ++ + void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, + struct sk_buff *skb) + { +@@ -376,6 +381,7 @@ void ath11k_htc_rx_completion_handler(st + ath11k_htc_suspend_complete(ab, false); + break; + case ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID: ++ ath11k_htc_wakeup_from_suspend(ab); + break; + default: + ath11k_warn(ab, "ignoring unsolicited htc ep0 event %ld\n", +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -16,6 +16,8 @@ + #include "testmode.h" + #include "peer.h" + #include "debugfs_sta.h" ++#include "hif.h" ++#include "wow.h" + + #define CHAN2G(_channel, _freq, _flags) { \ + .band = NL80211_BAND_2GHZ, \ +@@ -7258,31 +7260,47 @@ static int ath11k_mac_op_set_frag_thresh + return -EOPNOTSUPP; + } + +-static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- u32 queues, bool drop) ++static int ath11k_mac_flush_tx_complete(struct ath11k *ar) + { +- struct ath11k *ar = hw->priv; + long time_left; +- +- if (drop) +- return; ++ int ret = 0; + + time_left = wait_event_timeout(ar->dp.tx_empty_waitq, + (atomic_read(&ar->dp.num_tx_pending) == 0), + ATH11K_FLUSH_TIMEOUT); +- if (time_left == 0) +- ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); ++ if (time_left == 0) { ++ ath11k_warn(ar->ab, "failed to flush transmit queue, data pkts pending %d\n", ++ atomic_read(&ar->dp.num_tx_pending)); ++ ret = -ETIMEDOUT; ++ } + + time_left = wait_event_timeout(ar->txmgmt_empty_waitq, + (atomic_read(&ar->num_pending_mgmt_tx) == 0), + ATH11K_FLUSH_TIMEOUT); +- if (time_left == 0) +- ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", +- time_left); ++ if (time_left == 0) { ++ ath11k_warn(ar->ab, "failed to flush mgmt transmit queue, mgmt pkts pending %d\n", ++ atomic_read(&ar->num_pending_mgmt_tx)); ++ ret = -ETIMEDOUT; ++ } + +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "mac mgmt tx flush mgmt pending %d\n", +- atomic_read(&ar->num_pending_mgmt_tx)); ++ return ret; ++} ++ ++int ath11k_mac_wait_tx_complete(struct ath11k *ar) ++{ ++ ath11k_mac_drain_tx(ar); ++ return ath11k_mac_flush_tx_complete(ar); ++} ++ ++static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ u32 queues, bool drop) ++{ ++ struct ath11k *ar = hw->priv; ++ ++ if (drop) ++ return; ++ ++ ath11k_mac_flush_tx_complete(ar); + } + + static int +@@ -8104,6 +8122,13 @@ static const struct ieee80211_ops ath11k + .flush = ath11k_mac_op_flush, + .sta_statistics = ath11k_mac_op_sta_statistics, + CFG80211_TESTMODE_CMD(ath11k_tm_cmd) ++ ++#ifdef CONFIG_PM ++ .suspend = ath11k_wow_op_suspend, ++ .resume = ath11k_wow_op_resume, ++ .set_wakeup = ath11k_wow_op_set_wakeup, ++#endif ++ + #ifdef CPTCFG_ATH11K_DEBUGFS + .sta_add_debugfs = ath11k_debugfs_sta_op_add, + #endif +@@ -8473,6 +8498,12 @@ static int __ath11k_mac_register(struct + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + } + ++ ret = ath11k_wow_init(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to init wow: %d\n", ret); ++ goto err_free_if_combs; ++ } ++ + ar->hw->queues = ATH11K_HW_MAX_QUEUES; + ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; + ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -172,4 +172,5 @@ enum hal_encrypt_type ath11k_dp_tx_get_e + void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); + void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id); + void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif); ++int ath11k_mac_wait_tx_complete(struct ath11k *ar); + #endif +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -8235,3 +8235,161 @@ int ath11k_wmi_scan_prob_req_oui(struct + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID); + } ++ ++int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id, ++ enum wmi_wow_wakeup_event event, ++ u32 enable) ++{ ++ struct wmi_wow_add_del_event_cmd *cmd; ++ struct sk_buff *skb; ++ size_t len; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_wow_add_del_event_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_WOW_ADD_DEL_EVT_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ cmd->is_add = enable; ++ cmd->event_bitmap = (1 << event); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow add wakeup event %s enable %d vdev_id %d\n", ++ wow_wakeup_event(event), enable, vdev_id); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); ++} ++ ++int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id, ++ const u8 *pattern, const u8 *mask, ++ int pattern_len, int pattern_offset) ++{ ++ struct wmi_wow_add_pattern_cmd *cmd; ++ struct wmi_wow_bitmap_pattern *bitmap; ++ struct wmi_tlv *tlv; ++ struct sk_buff *skb; ++ u8 *ptr; ++ size_t len; ++ ++ len = sizeof(*cmd) + ++ sizeof(*tlv) + /* array struct */ ++ sizeof(*bitmap) + /* bitmap */ ++ sizeof(*tlv) + /* empty ipv4 sync */ ++ sizeof(*tlv) + /* empty ipv6 sync */ ++ sizeof(*tlv) + /* empty magic */ ++ sizeof(*tlv) + /* empty info timeout */ ++ sizeof(*tlv) + sizeof(u32); /* ratelimit interval */ ++ ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ /* cmd */ ++ ptr = (u8 *)skb->data; ++ cmd = (struct wmi_wow_add_pattern_cmd *)ptr; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_WOW_ADD_PATTERN_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ cmd->pattern_id = pattern_id; ++ cmd->pattern_type = WOW_BITMAP_PATTERN; ++ ++ ptr += sizeof(*cmd); ++ ++ /* bitmap */ ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*bitmap)); ++ ++ ptr += sizeof(*tlv); ++ ++ bitmap = (struct wmi_wow_bitmap_pattern *)ptr; ++ bitmap->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_WOW_BITMAP_PATTERN_T) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*bitmap) - TLV_HDR_SIZE); ++ ++ memcpy(bitmap->patternbuf, pattern, pattern_len); ++ ath11k_ce_byte_swap(bitmap->patternbuf, roundup(pattern_len, 4)); ++ memcpy(bitmap->bitmaskbuf, mask, pattern_len); ++ ath11k_ce_byte_swap(bitmap->bitmaskbuf, roundup(pattern_len, 4)); ++ bitmap->pattern_offset = pattern_offset; ++ bitmap->pattern_len = pattern_len; ++ bitmap->bitmask_len = pattern_len; ++ bitmap->pattern_id = pattern_id; ++ ++ ptr += sizeof(*bitmap); ++ ++ /* ipv4 sync */ ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, 0); ++ ++ ptr += sizeof(*tlv); ++ ++ /* ipv6 sync */ ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, 0); ++ ++ ptr += sizeof(*tlv); ++ ++ /* magic */ ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, 0); ++ ++ ptr += sizeof(*tlv); ++ ++ /* pattern info timeout */ ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_UINT32) | ++ FIELD_PREP(WMI_TLV_LEN, 0); ++ ++ ptr += sizeof(*tlv); ++ ++ /* ratelimit interval */ ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_UINT32) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(u32)); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow add pattern vdev_id %d pattern_id %d pattern_offset %d\n", ++ vdev_id, pattern_id, pattern_offset); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ADD_WAKE_PATTERN_CMDID); ++} ++ ++int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id) ++{ ++ struct wmi_wow_del_pattern_cmd *cmd; ++ struct sk_buff *skb; ++ size_t len; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_wow_del_pattern_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_WOW_DEL_PATTERN_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ cmd->pattern_id = pattern_id; ++ cmd->pattern_type = WOW_BITMAP_PATTERN; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow del pattern vdev_id %d pattern_id %d\n", ++ vdev_id, pattern_id); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID); ++} +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5534,6 +5534,45 @@ static inline const char *wow_reason(enu + + #undef C2S + ++struct wmi_wow_ev_arg { ++ u32 vdev_id; ++ u32 flag; ++ enum wmi_wow_wake_reason wake_reason; ++ u32 data_len; ++}; ++ ++enum wmi_tlv_pattern_type { ++ WOW_PATTERN_MIN = 0, ++ WOW_BITMAP_PATTERN = WOW_PATTERN_MIN, ++ WOW_IPV4_SYNC_PATTERN, ++ WOW_IPV6_SYNC_PATTERN, ++ WOW_WILD_CARD_PATTERN, ++ WOW_TIMER_PATTERN, ++ WOW_MAGIC_PATTERN, ++ WOW_IPV6_RA_PATTERN, ++ WOW_IOAC_PKT_PATTERN, ++ WOW_IOAC_TMR_PATTERN, ++ WOW_PATTERN_MAX ++}; ++ ++#define WOW_DEFAULT_BITMAP_PATTERN_SIZE 148 ++#define WOW_DEFAULT_BITMASK_SIZE 148 ++ ++#define WOW_MIN_PATTERN_SIZE 1 ++#define WOW_MAX_PATTERN_SIZE 148 ++#define WOW_MAX_PKT_OFFSET 128 ++#define WOW_HDR_LEN (sizeof(struct ieee80211_hdr_3addr) + \ ++ sizeof(struct rfc1042_hdr)) ++#define WOW_MAX_REDUCE (WOW_HDR_LEN - sizeof(struct ethhdr) - \ ++ offsetof(struct ieee80211_hdr_3addr, addr1)) ++ ++struct wmi_wow_add_del_event_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 is_add; ++ u32 event_bitmap; ++} __packed; ++ + struct wmi_wow_enable_cmd { + u32 tlv_header; + u32 enable; +@@ -5546,12 +5585,36 @@ struct wmi_wow_host_wakeup_ind { + u32 reserved; + } __packed; + +-struct wmi_wow_ev_arg { ++struct wmi_tlv_wow_event_info { + u32 vdev_id; + u32 flag; +- enum wmi_wow_wake_reason wake_reason; ++ u32 wake_reason; + u32 data_len; +-}; ++} __packed; ++ ++struct wmi_wow_bitmap_pattern { ++ u32 tlv_header; ++ u8 patternbuf[WOW_DEFAULT_BITMAP_PATTERN_SIZE]; ++ u8 bitmaskbuf[WOW_DEFAULT_BITMASK_SIZE]; ++ u32 pattern_offset; ++ u32 pattern_len; ++ u32 bitmask_len; ++ u32 pattern_id; ++} __packed; ++ ++struct wmi_wow_add_pattern_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 pattern_id; ++ u32 pattern_type; ++} __packed; ++ ++struct wmi_wow_del_pattern_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 pattern_id; ++ u32 pattern_type; ++} __packed; + + int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, + u32 cmd_id); +@@ -5714,4 +5777,11 @@ int ath11k_wmi_scan_prob_req_oui(struct + const u8 mac_addr[ETH_ALEN]); + int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, + struct ath11k_fw_dbglog *dbglog); ++int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id); ++int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id, ++ const u8 *pattern, const u8 *mask, ++ int pattern_len, int pattern_offset); ++int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id, ++ enum wmi_wow_wakeup_event event, ++ u32 enable); + #endif +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -6,12 +6,22 @@ + #include + + #include "mac.h" ++ ++#include + #include "core.h" + #include "hif.h" + #include "debug.h" + #include "wmi.h" + #include "wow.h" + ++static const struct wiphy_wowlan_support ath11k_wowlan_support = { ++ .flags = WIPHY_WOWLAN_DISCONNECT | ++ WIPHY_WOWLAN_MAGIC_PKT, ++ .pattern_min_len = WOW_MIN_PATTERN_SIZE, ++ .pattern_max_len = WOW_MAX_PATTERN_SIZE, ++ .max_pkt_offset = WOW_MAX_PKT_OFFSET, ++}; ++ + int ath11k_wow_enable(struct ath11k_base *ab) + { + struct ath11k *ar = ath11k_ab_to_ar(ab, 0); +@@ -71,3 +81,407 @@ int ath11k_wow_wakeup(struct ath11k_base + + return 0; + } ++ ++static int ath11k_wow_vif_cleanup(struct ath11k_vif *arvif) ++{ ++ struct ath11k *ar = arvif->ar; ++ int i, ret; ++ ++ for (i = 0; i < WOW_EVENT_MAX; i++) { ++ ret = ath11k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to issue wow wakeup for event %s on vdev %i: %d\n", ++ wow_wakeup_event(i), arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ for (i = 0; i < ar->wow.max_num_patterns; i++) { ++ ret = ath11k_wmi_wow_del_pattern(ar, arvif->vdev_id, i); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to delete wow pattern %d for vdev %i: %d\n", ++ i, arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ath11k_wow_cleanup(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath11k_wow_vif_cleanup(arvif); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Convert a 802.3 format to a 802.11 format. ++ * +------------+-----------+--------+----------------+ ++ * 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... | ++ * +------------+-----------+--------+----------------+ ++ * |__ |_______ |____________ |________ ++ * | | | | ++ * +--+------------+----+-----------+---------------+-----------+ ++ * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... | ++ * +--+------------+----+-----------+---------------+-----------+ ++ */ ++static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, ++ const struct cfg80211_pkt_pattern *old) ++{ ++ u8 hdr_8023_pattern[ETH_HLEN] = {}; ++ u8 hdr_8023_bit_mask[ETH_HLEN] = {}; ++ u8 hdr_80211_pattern[WOW_HDR_LEN] = {}; ++ u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {}; ++ ++ int total_len = old->pkt_offset + old->pattern_len; ++ int hdr_80211_end_offset; ++ ++ struct ieee80211_hdr_3addr *new_hdr_pattern = ++ (struct ieee80211_hdr_3addr *)hdr_80211_pattern; ++ struct ieee80211_hdr_3addr *new_hdr_mask = ++ (struct ieee80211_hdr_3addr *)hdr_80211_bit_mask; ++ struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern; ++ struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask; ++ int hdr_len = sizeof(*new_hdr_pattern); ++ ++ struct rfc1042_hdr *new_rfc_pattern = ++ (struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len); ++ struct rfc1042_hdr *new_rfc_mask = ++ (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len); ++ int rfc_len = sizeof(*new_rfc_pattern); ++ ++ memcpy(hdr_8023_pattern + old->pkt_offset, ++ old->pattern, ETH_HLEN - old->pkt_offset); ++ memcpy(hdr_8023_bit_mask + old->pkt_offset, ++ old->mask, ETH_HLEN - old->pkt_offset); ++ ++ /* Copy destination address */ ++ memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN); ++ memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN); ++ ++ /* Copy source address */ ++ memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN); ++ memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN); ++ ++ /* Copy logic link type */ ++ memcpy(&new_rfc_pattern->snap_type, ++ &old_hdr_pattern->h_proto, ++ sizeof(old_hdr_pattern->h_proto)); ++ memcpy(&new_rfc_mask->snap_type, ++ &old_hdr_mask->h_proto, ++ sizeof(old_hdr_mask->h_proto)); ++ ++ /* Compute new pkt_offset */ ++ if (old->pkt_offset < ETH_ALEN) ++ new->pkt_offset = old->pkt_offset + ++ offsetof(struct ieee80211_hdr_3addr, addr1); ++ else if (old->pkt_offset < offsetof(struct ethhdr, h_proto)) ++ new->pkt_offset = old->pkt_offset + ++ offsetof(struct ieee80211_hdr_3addr, addr3) - ++ offsetof(struct ethhdr, h_source); ++ else ++ new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN; ++ ++ /* Compute new hdr end offset */ ++ if (total_len > ETH_HLEN) ++ hdr_80211_end_offset = hdr_len + rfc_len; ++ else if (total_len > offsetof(struct ethhdr, h_proto)) ++ hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN; ++ else if (total_len > ETH_ALEN) ++ hdr_80211_end_offset = total_len - ETH_ALEN + ++ offsetof(struct ieee80211_hdr_3addr, addr3); ++ else ++ hdr_80211_end_offset = total_len + ++ offsetof(struct ieee80211_hdr_3addr, addr1); ++ ++ new->pattern_len = hdr_80211_end_offset - new->pkt_offset; ++ ++ memcpy((u8 *)new->pattern, ++ hdr_80211_pattern + new->pkt_offset, ++ new->pattern_len); ++ memcpy((u8 *)new->mask, ++ hdr_80211_bit_mask + new->pkt_offset, ++ new->pattern_len); ++ ++ if (total_len > ETH_HLEN) { ++ /* Copy frame body */ ++ memcpy((u8 *)new->pattern + new->pattern_len, ++ (void *)old->pattern + ETH_HLEN - old->pkt_offset, ++ total_len - ETH_HLEN); ++ memcpy((u8 *)new->mask + new->pattern_len, ++ (void *)old->mask + ETH_HLEN - old->pkt_offset, ++ total_len - ETH_HLEN); ++ ++ new->pattern_len += total_len - ETH_HLEN; ++ } ++} ++ ++static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif, ++ struct cfg80211_wowlan *wowlan) ++{ ++ int ret, i; ++ unsigned long wow_mask = 0; ++ struct ath11k *ar = arvif->ar; ++ const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; ++ int pattern_id = 0; ++ ++ /* Setup requested WOW features */ ++ switch (arvif->vdev_type) { ++ case WMI_VDEV_TYPE_IBSS: ++ __set_bit(WOW_BEACON_EVENT, &wow_mask); ++ fallthrough; ++ case WMI_VDEV_TYPE_AP: ++ __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); ++ __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); ++ __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask); ++ __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask); ++ __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask); ++ __set_bit(WOW_HTT_EVENT, &wow_mask); ++ __set_bit(WOW_RA_MATCH_EVENT, &wow_mask); ++ break; ++ case WMI_VDEV_TYPE_STA: ++ if (wowlan->disconnect) { ++ __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); ++ __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); ++ __set_bit(WOW_BMISS_EVENT, &wow_mask); ++ __set_bit(WOW_CSA_IE_EVENT, &wow_mask); ++ } ++ ++ if (wowlan->magic_pkt) ++ __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); ++ break; ++ default: ++ break; ++ } ++ ++ for (i = 0; i < wowlan->n_patterns; i++) { ++ u8 bitmask[WOW_MAX_PATTERN_SIZE] = {}; ++ u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {}; ++ u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {}; ++ struct cfg80211_pkt_pattern new_pattern = {}; ++ struct cfg80211_pkt_pattern old_pattern = patterns[i]; ++ int j; ++ ++ new_pattern.pattern = ath_pattern; ++ new_pattern.mask = ath_bitmask; ++ if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE) ++ continue; ++ /* convert bytemask to bitmask */ ++ for (j = 0; j < patterns[i].pattern_len; j++) ++ if (patterns[i].mask[j / 8] & BIT(j % 8)) ++ bitmask[j] = 0xff; ++ old_pattern.mask = bitmask; ++ ++ if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode == ++ ATH11K_HW_TXRX_NATIVE_WIFI) { ++ if (patterns[i].pkt_offset < ETH_HLEN) { ++ u8 pattern_ext[WOW_MAX_PATTERN_SIZE] = {}; ++ ++ memcpy(pattern_ext, old_pattern.pattern, ++ old_pattern.pattern_len); ++ old_pattern.pattern = pattern_ext; ++ ath11k_wow_convert_8023_to_80211(&new_pattern, ++ &old_pattern); ++ } else { ++ new_pattern = old_pattern; ++ new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; ++ } ++ } ++ ++ if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) ++ return -EINVAL; ++ ++ ret = ath11k_wmi_wow_add_pattern(ar, arvif->vdev_id, ++ pattern_id, ++ new_pattern.pattern, ++ new_pattern.mask, ++ new_pattern.pattern_len, ++ new_pattern.pkt_offset); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to add pattern %i to vdev %i: %d\n", ++ pattern_id, ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ ++ pattern_id++; ++ __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask); ++ } ++ ++ for (i = 0; i < WOW_EVENT_MAX; i++) { ++ if (!test_bit(i, &wow_mask)) ++ continue; ++ ret = ath11k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to enable wakeup event %s on vdev %i: %d\n", ++ wow_wakeup_event(i), arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ath11k_wow_set_wakeups(struct ath11k *ar, ++ struct cfg80211_wowlan *wowlan) ++{ ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath11k_vif_wow_set_wakeups(arvif, wowlan); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++int ath11k_wow_op_suspend(struct ieee80211_hw *hw, ++ struct cfg80211_wowlan *wowlan) ++{ ++ struct ath11k *ar = hw->priv; ++ int ret; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ ret = ath11k_wow_cleanup(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to clear wow wakeup events: %d\n", ++ ret); ++ goto exit; ++ } ++ ++ ret = ath11k_wow_set_wakeups(ar, wowlan); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set wow wakeup events: %d\n", ++ ret); ++ goto cleanup; ++ } ++ ++ ret = ath11k_mac_wait_tx_complete(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to wait tx complete: %d\n", ret); ++ goto cleanup; ++ } ++ ++ ret = ath11k_wow_enable(ar->ab); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start wow: %d\n", ret); ++ goto cleanup; ++ } ++ ++ ath11k_ce_stop_shadow_timers(ar->ab); ++ ath11k_dp_stop_shadow_timers(ar->ab); ++ ++ ath11k_hif_irq_disable(ar->ab); ++ ath11k_hif_ce_irq_disable(ar->ab); ++ ++ ret = ath11k_hif_suspend(ar->ab); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to suspend hif: %d\n", ret); ++ goto wakeup; ++ } ++ ++ goto exit; ++ ++wakeup: ++ ath11k_wow_wakeup(ar->ab); ++ ++cleanup: ++ ath11k_wow_cleanup(ar); ++ ++exit: ++ mutex_unlock(&ar->conf_mutex); ++ return ret ? 1 : 0; ++} ++ ++void ath11k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) ++{ ++ struct ath11k *ar = hw->priv; ++ ++ mutex_lock(&ar->conf_mutex); ++ device_set_wakeup_enable(ar->ab->dev, enabled); ++ mutex_unlock(&ar->conf_mutex); ++} ++ ++int ath11k_wow_op_resume(struct ieee80211_hw *hw) ++{ ++ struct ath11k *ar = hw->priv; ++ int ret; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ ret = ath11k_hif_resume(ar->ab); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to resume hif: %d\n", ret); ++ goto exit; ++ } ++ ++ ath11k_hif_ce_irq_enable(ar->ab); ++ ath11k_hif_irq_enable(ar->ab); ++ ++ ret = ath11k_wow_wakeup(ar->ab); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret); ++ ++exit: ++ if (ret) { ++ switch (ar->state) { ++ case ATH11K_STATE_ON: ++ ar->state = ATH11K_STATE_RESTARTING; ++ ret = 1; ++ break; ++ case ATH11K_STATE_OFF: ++ case ATH11K_STATE_RESTARTING: ++ case ATH11K_STATE_RESTARTED: ++ case ATH11K_STATE_WEDGED: ++ ath11k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n", ++ ar->state); ++ ret = -EIO; ++ break; ++ } ++ } ++ ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++} ++ ++int ath11k_wow_init(struct ath11k *ar) ++{ ++ if (WARN_ON(!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map))) ++ return -EINVAL; ++ ++ ar->wow.wowlan_support = ath11k_wowlan_support; ++ ++ if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode == ++ ATH11K_HW_TXRX_NATIVE_WIFI) { ++ ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE; ++ ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; ++ } ++ ++ ar->wow.max_num_patterns = ATH11K_WOW_PATTERNS; ++ ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ++ ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; ++ ++ device_set_wakeup_capable(ar->ab->dev, true); ++ ++ return 0; ++} +--- a/drivers/net/wireless/ath/ath11k/wow.h ++++ b/drivers/net/wireless/ath/ath11k/wow.h +@@ -3,8 +3,53 @@ + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ + ++#ifndef _WOW_H_ ++#define _WOW_H_ ++ ++struct ath11k_wow { ++ u32 max_num_patterns; ++ struct completion wakeup_completed; ++ struct wiphy_wowlan_support wowlan_support; ++}; ++ ++struct rfc1042_hdr { ++ u8 llc_dsap; ++ u8 llc_ssap; ++ u8 llc_ctrl; ++ u8 snap_oui[3]; ++ __be16 snap_type; ++} __packed; ++ + #define ATH11K_WOW_RETRY_NUM 3 + #define ATH11K_WOW_RETRY_WAIT_MS 200 ++#define ATH11K_WOW_PATTERNS 22 + ++#ifdef CONFIG_PM ++ ++int ath11k_wow_init(struct ath11k *ar); ++int ath11k_wow_op_suspend(struct ieee80211_hw *hw, ++ struct cfg80211_wowlan *wowlan); ++int ath11k_wow_op_resume(struct ieee80211_hw *hw); ++void ath11k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled); + int ath11k_wow_enable(struct ath11k_base *ab); + int ath11k_wow_wakeup(struct ath11k_base *ab); ++ ++#else ++ ++static inline int ath11k_wow_init(struct ath11k *ar) ++{ ++ return 0; ++} ++ ++static inline int ath11k_wow_enable(struct ath11k_base *ab) ++{ ++ return 0; ++} ++ ++static inline int ath11k_wow_wakeup(struct ath11k_base *ab) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_PM */ ++#endif /* _WOW_H_ */ diff --git a/package/kernel/mac80211/patches/ath11k/0194-ath11k-Add-WoW-net-detect-functionality.patch b/package/kernel/mac80211/patches/ath11k/0194-ath11k-Add-WoW-net-detect-functionality.patch new file mode 100644 index 000000000..8ba83227e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0194-ath11k-Add-WoW-net-detect-functionality.patch @@ -0,0 +1,614 @@ +From fec4b898f369a9b9d516f7bfc459eb4a8c5ceb2c Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Mar 2022 07:18:16 +0200 +Subject: [PATCH] ath11k: Add WoW net-detect functionality + +Implement net-detect feature by setting flag +WIPHY_WOWLAN_NET_DETECT if firmware supports this +feature. Driver sets the related PNO configuration +to firmware before entering WoW and firmware then +scans periodically and wakes up host if a specific +SSID is found. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644308006-22784-3-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 12 ++ + drivers/net/wireless/ath/ath11k/wmi.c | 154 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 169 ++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wow.c | 175 ++++++++++++++++++++++++- + 5 files changed, 510 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -617,6 +617,7 @@ struct ath11k { + bool regdom_set_by_user; + int hw_rate_code; + u8 twt_enabled; ++ bool nlo_enabled; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -8498,6 +8498,18 @@ static int __ath11k_mac_register(struct + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + } + ++ if (test_bit(WMI_TLV_SERVICE_NLO, ar->wmi->wmi_ab->svc_map)) { ++ ar->hw->wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS; ++ ar->hw->wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; ++ ar->hw->wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH; ++ ar->hw->wiphy->max_sched_scan_plans = WMI_PNO_MAX_SCHED_SCAN_PLANS; ++ ar->hw->wiphy->max_sched_scan_plan_interval = ++ WMI_PNO_MAX_SCHED_SCAN_PLAN_INT; ++ ar->hw->wiphy->max_sched_scan_plan_iterations = ++ WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS; ++ ar->hw->wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR; ++ } ++ + ret = ath11k_wow_init(ar); + if (ret) { + ath11k_warn(ar->ab, "failed to init wow: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -8393,3 +8393,157 @@ int ath11k_wmi_wow_del_pattern(struct at + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID); + } ++ ++static struct sk_buff * ++ath11k_wmi_op_gen_config_pno_start(struct ath11k *ar, ++ u32 vdev_id, ++ struct wmi_pno_scan_req *pno) ++{ ++ struct nlo_configured_parameters *nlo_list; ++ struct wmi_wow_nlo_config_cmd *cmd; ++ struct wmi_tlv *tlv; ++ struct sk_buff *skb; ++ u32 *channel_list; ++ size_t len, nlo_list_len, channel_list_len; ++ u8 *ptr; ++ u32 i; ++ ++ len = sizeof(*cmd) + ++ sizeof(*tlv) + ++ /* TLV place holder for array of structures ++ * nlo_configured_parameters(nlo_list) ++ */ ++ sizeof(*tlv); ++ /* TLV place holder for array of uint32 channel_list */ ++ ++ channel_list_len = sizeof(u32) * pno->a_networks[0].channel_count; ++ len += channel_list_len; ++ ++ nlo_list_len = sizeof(*nlo_list) * pno->uc_networks_count; ++ len += nlo_list_len; ++ ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return ERR_PTR(-ENOMEM); ++ ++ ptr = (u8 *)skb->data; ++ cmd = (struct wmi_wow_nlo_config_cmd *)ptr; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_NLO_CONFIG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = pno->vdev_id; ++ cmd->flags = WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN; ++ ++ /* current FW does not support min-max range for dwell time */ ++ cmd->active_dwell_time = pno->active_max_time; ++ cmd->passive_dwell_time = pno->passive_max_time; ++ ++ if (pno->do_passive_scan) ++ cmd->flags |= WMI_NLO_CONFIG_SCAN_PASSIVE; ++ ++ cmd->fast_scan_period = pno->fast_scan_period; ++ cmd->slow_scan_period = pno->slow_scan_period; ++ cmd->fast_scan_max_cycles = pno->fast_scan_max_cycles; ++ cmd->delay_start_time = pno->delay_start_time; ++ ++ if (pno->enable_pno_scan_randomization) { ++ cmd->flags |= WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ | ++ WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ; ++ ether_addr_copy(cmd->mac_addr.addr, pno->mac_addr); ++ ether_addr_copy(cmd->mac_mask.addr, pno->mac_addr_mask); ++ ath11k_ce_byte_swap(cmd->mac_addr.addr, 8); ++ ath11k_ce_byte_swap(cmd->mac_mask.addr, 8); ++ } ++ ++ ptr += sizeof(*cmd); ++ ++ /* nlo_configured_parameters(nlo_list) */ ++ cmd->no_of_ssids = pno->uc_networks_count; ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, nlo_list_len); ++ ++ ptr += sizeof(*tlv); ++ nlo_list = (struct nlo_configured_parameters *)ptr; ++ for (i = 0; i < cmd->no_of_ssids; i++) { ++ tlv = (struct wmi_tlv *)(&nlo_list[i].tlv_header); ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*nlo_list) - sizeof(*tlv)); ++ ++ nlo_list[i].ssid.valid = true; ++ nlo_list[i].ssid.ssid.ssid_len = pno->a_networks[i].ssid.ssid_len; ++ memcpy(nlo_list[i].ssid.ssid.ssid, ++ pno->a_networks[i].ssid.ssid, ++ nlo_list[i].ssid.ssid.ssid_len); ++ ath11k_ce_byte_swap(nlo_list[i].ssid.ssid.ssid, ++ roundup(nlo_list[i].ssid.ssid.ssid_len, 4)); ++ ++ if (pno->a_networks[i].rssi_threshold && ++ pno->a_networks[i].rssi_threshold > -300) { ++ nlo_list[i].rssi_cond.valid = true; ++ nlo_list[i].rssi_cond.rssi = ++ pno->a_networks[i].rssi_threshold; ++ } ++ ++ nlo_list[i].bcast_nw_type.valid = true; ++ nlo_list[i].bcast_nw_type.bcast_nw_type = ++ pno->a_networks[i].bcast_nw_type; ++ } ++ ++ ptr += nlo_list_len; ++ cmd->num_of_channels = pno->a_networks[0].channel_count; ++ tlv = (struct wmi_tlv *)ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) | ++ FIELD_PREP(WMI_TLV_LEN, channel_list_len); ++ ptr += sizeof(*tlv); ++ channel_list = (u32 *)ptr; ++ for (i = 0; i < cmd->num_of_channels; i++) ++ channel_list[i] = pno->a_networks[0].channels[i]; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv start pno config vdev_id %d\n", ++ vdev_id); ++ ++ return skb; ++} ++ ++static struct sk_buff *ath11k_wmi_op_gen_config_pno_stop(struct ath11k *ar, ++ u32 vdev_id) ++{ ++ struct wmi_wow_nlo_config_cmd *cmd; ++ struct sk_buff *skb; ++ size_t len; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_wow_nlo_config_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_NLO_CONFIG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ cmd->flags = WMI_NLO_CONFIG_STOP; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi tlv stop pno config vdev_id %d\n", vdev_id); ++ return skb; ++} ++ ++int ath11k_wmi_wow_config_pno(struct ath11k *ar, u32 vdev_id, ++ struct wmi_pno_scan_req *pno_scan) ++{ ++ struct sk_buff *skb; ++ ++ if (pno_scan->enable) ++ skb = ath11k_wmi_op_gen_config_pno_start(ar, vdev_id, pno_scan); ++ else ++ skb = ath11k_wmi_op_gen_config_pno_stop(ar, vdev_id); ++ ++ if (IS_ERR_OR_NULL(skb)) ++ return -ENOMEM; ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); ++} ++ +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5616,6 +5616,173 @@ struct wmi_wow_del_pattern_cmd { + u32 pattern_type; + } __packed; + ++#define WMI_PNO_MAX_SCHED_SCAN_PLANS 2 ++#define WMI_PNO_MAX_SCHED_SCAN_PLAN_INT 7200 ++#define WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS 100 ++#define WMI_PNO_MAX_NETW_CHANNELS 26 ++#define WMI_PNO_MAX_NETW_CHANNELS_EX 60 ++#define WMI_PNO_MAX_SUPP_NETWORKS WLAN_SCAN_PARAMS_MAX_SSID ++#define WMI_PNO_MAX_IE_LENGTH WLAN_SCAN_PARAMS_MAX_IE_LEN ++ ++/* size based of dot11 declaration without extra IEs as we will not carry those for PNO */ ++#define WMI_PNO_MAX_PB_REQ_SIZE 450 ++ ++#define WMI_PNO_24G_DEFAULT_CH 1 ++#define WMI_PNO_5G_DEFAULT_CH 36 ++ ++#define WMI_ACTIVE_MAX_CHANNEL_TIME 40 ++#define WMI_PASSIVE_MAX_CHANNEL_TIME 110 ++ ++/* SSID broadcast type */ ++enum wmi_ssid_bcast_type { ++ BCAST_UNKNOWN = 0, ++ BCAST_NORMAL = 1, ++ BCAST_HIDDEN = 2, ++}; ++ ++#define WMI_NLO_MAX_SSIDS 16 ++#define WMI_NLO_MAX_CHAN 48 ++ ++#define WMI_NLO_CONFIG_STOP BIT(0) ++#define WMI_NLO_CONFIG_START BIT(1) ++#define WMI_NLO_CONFIG_RESET BIT(2) ++#define WMI_NLO_CONFIG_SLOW_SCAN BIT(4) ++#define WMI_NLO_CONFIG_FAST_SCAN BIT(5) ++#define WMI_NLO_CONFIG_SSID_HIDE_EN BIT(6) ++ ++/* This bit is used to indicate if EPNO or supplicant PNO is enabled. ++ * Only one of them can be enabled at a given time ++ */ ++#define WMI_NLO_CONFIG_ENLO BIT(7) ++#define WMI_NLO_CONFIG_SCAN_PASSIVE BIT(8) ++#define WMI_NLO_CONFIG_ENLO_RESET BIT(9) ++#define WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ BIT(10) ++#define WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ BIT(11) ++#define WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ BIT(12) ++#define WMI_NLO_CONFIG_ENABLE_CNLO_RSSI_CONFIG BIT(13) ++ ++struct wmi_nlo_ssid_param { ++ u32 valid; ++ struct wmi_ssid ssid; ++} __packed; ++ ++struct wmi_nlo_enc_param { ++ u32 valid; ++ u32 enc_type; ++} __packed; ++ ++struct wmi_nlo_auth_param { ++ u32 valid; ++ u32 auth_type; ++} __packed; ++ ++struct wmi_nlo_bcast_nw_param { ++ u32 valid; ++ u32 bcast_nw_type; ++} __packed; ++ ++struct wmi_nlo_rssi_param { ++ u32 valid; ++ s32 rssi; ++} __packed; ++ ++struct nlo_configured_parameters { ++ /* TLV tag and len;*/ ++ u32 tlv_header; ++ struct wmi_nlo_ssid_param ssid; ++ struct wmi_nlo_enc_param enc_type; ++ struct wmi_nlo_auth_param auth_type; ++ struct wmi_nlo_rssi_param rssi_cond; ++ ++ /* indicates if the SSID is hidden or not */ ++ struct wmi_nlo_bcast_nw_param bcast_nw_type; ++} __packed; ++ ++struct wmi_network_type { ++ struct wmi_ssid ssid; ++ u32 authentication; ++ u32 encryption; ++ u32 bcast_nw_type; ++ u8 channel_count; ++ u16 channels[WMI_PNO_MAX_NETW_CHANNELS_EX]; ++ s32 rssi_threshold; ++}; ++ ++struct wmi_pno_scan_req { ++ u8 enable; ++ u8 vdev_id; ++ u8 uc_networks_count; ++ struct wmi_network_type a_networks[WMI_PNO_MAX_SUPP_NETWORKS]; ++ u32 fast_scan_period; ++ u32 slow_scan_period; ++ u8 fast_scan_max_cycles; ++ ++ bool do_passive_scan; ++ ++ u32 delay_start_time; ++ u32 active_min_time; ++ u32 active_max_time; ++ u32 passive_min_time; ++ u32 passive_max_time; ++ ++ /* mac address randomization attributes */ ++ u32 enable_pno_scan_randomization; ++ u8 mac_addr[ETH_ALEN]; ++ u8 mac_addr_mask[ETH_ALEN]; ++}; ++ ++struct wmi_wow_nlo_config_cmd { ++ u32 tlv_header; ++ u32 flags; ++ u32 vdev_id; ++ u32 fast_scan_max_cycles; ++ u32 active_dwell_time; ++ u32 passive_dwell_time; ++ u32 probe_bundle_size; ++ ++ /* ART = IRT */ ++ u32 rest_time; ++ ++ /* Max value that can be reached after SBM */ ++ u32 max_rest_time; ++ ++ /* SBM */ ++ u32 scan_backoff_multiplier; ++ ++ /* SCBM */ ++ u32 fast_scan_period; ++ ++ /* specific to windows */ ++ u32 slow_scan_period; ++ ++ u32 no_of_ssids; ++ ++ u32 num_of_channels; ++ ++ /* NLO scan start delay time in milliseconds */ ++ u32 delay_start_time; ++ ++ /* MAC Address to use in Probe Req as SA */ ++ struct wmi_mac_addr mac_addr; ++ ++ /* Mask on which MAC has to be randomized */ ++ struct wmi_mac_addr mac_mask; ++ ++ /* IE bitmap to use in Probe Req */ ++ u32 ie_bitmap[8]; ++ ++ /* Number of vendor OUIs. In the TLV vendor_oui[] */ ++ u32 num_vendor_oui; ++ ++ /* Number of connected NLO band preferences */ ++ u32 num_cnlo_band_pref; ++ ++ /* The TLVs will follow. ++ * nlo_configured_parameters nlo_list[]; ++ * u32 channel_list[num_of_channels]; ++ */ ++} __packed; ++ + int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, + u32 cmd_id); + struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); +@@ -5777,6 +5944,8 @@ int ath11k_wmi_scan_prob_req_oui(struct + const u8 mac_addr[ETH_ALEN]); + int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, + struct ath11k_fw_dbglog *dbglog); ++int ath11k_wmi_wow_config_pno(struct ath11k *ar, u32 vdev_id, ++ struct wmi_pno_scan_req *pno_scan); + int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id); + int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id, + const u8 *pattern, const u8 *mask, +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -228,6 +228,101 @@ static void ath11k_wow_convert_8023_to_8 + } + } + ++static int ath11k_wmi_pno_check_and_convert(struct ath11k *ar, u32 vdev_id, ++ struct cfg80211_sched_scan_request *nd_config, ++ struct wmi_pno_scan_req *pno) ++{ ++ int i, j; ++ u8 ssid_len; ++ ++ pno->enable = 1; ++ pno->vdev_id = vdev_id; ++ pno->uc_networks_count = nd_config->n_match_sets; ++ ++ if (!pno->uc_networks_count || ++ pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS) ++ return -EINVAL; ++ ++ if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX) ++ return -EINVAL; ++ ++ /* Filling per profile params */ ++ for (i = 0; i < pno->uc_networks_count; i++) { ++ ssid_len = nd_config->match_sets[i].ssid.ssid_len; ++ ++ if (ssid_len == 0 || ssid_len > 32) ++ return -EINVAL; ++ ++ pno->a_networks[i].ssid.ssid_len = ssid_len; ++ ++ memcpy(pno->a_networks[i].ssid.ssid, ++ nd_config->match_sets[i].ssid.ssid, ++ nd_config->match_sets[i].ssid.ssid_len); ++ pno->a_networks[i].authentication = 0; ++ pno->a_networks[i].encryption = 0; ++ pno->a_networks[i].bcast_nw_type = 0; ++ ++ /* Copying list of valid channel into request */ ++ pno->a_networks[i].channel_count = nd_config->n_channels; ++ pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold; ++ ++ for (j = 0; j < nd_config->n_channels; j++) { ++ pno->a_networks[i].channels[j] = ++ nd_config->channels[j]->center_freq; ++ } ++ } ++ ++ /* set scan to passive if no SSIDs are specified in the request */ ++ if (nd_config->n_ssids == 0) ++ pno->do_passive_scan = true; ++ else ++ pno->do_passive_scan = false; ++ ++ for (i = 0; i < nd_config->n_ssids; i++) { ++ j = 0; ++ while (j < pno->uc_networks_count) { ++ if (pno->a_networks[j].ssid.ssid_len == ++ nd_config->ssids[i].ssid_len && ++ (memcmp(pno->a_networks[j].ssid.ssid, ++ nd_config->ssids[i].ssid, ++ pno->a_networks[j].ssid.ssid_len) == 0)) { ++ pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN; ++ break; ++ } ++ j++; ++ } ++ } ++ ++ if (nd_config->n_scan_plans == 2) { ++ pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; ++ pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations; ++ pno->slow_scan_period = ++ nd_config->scan_plans[1].interval * MSEC_PER_SEC; ++ } else if (nd_config->n_scan_plans == 1) { ++ pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; ++ pno->fast_scan_max_cycles = 1; ++ pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC; ++ } else { ++ ath11k_warn(ar->ab, "Invalid number of scan plans %d !!", ++ nd_config->n_scan_plans); ++ } ++ ++ if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { ++ /* enable mac randomization */ ++ pno->enable_pno_scan_randomization = 1; ++ memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN); ++ memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN); ++ } ++ ++ pno->delay_start_time = nd_config->delay; ++ ++ /* Current FW does not support min-max range for dwell time */ ++ pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME; ++ pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME; ++ ++ return 0; ++} ++ + static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif, + struct cfg80211_wowlan *wowlan) + { +@@ -261,6 +356,26 @@ static int ath11k_vif_wow_set_wakeups(st + + if (wowlan->magic_pkt) + __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask); ++ ++ if (wowlan->nd_config) { ++ struct wmi_pno_scan_req *pno; ++ int ret; ++ ++ pno = kzalloc(sizeof(*pno), GFP_KERNEL); ++ if (!pno) ++ return -ENOMEM; ++ ++ ar->nlo_enabled = true; ++ ++ ret = ath11k_wmi_pno_check_and_convert(ar, arvif->vdev_id, ++ wowlan->nd_config, pno); ++ if (!ret) { ++ ath11k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); ++ __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask); ++ } ++ ++ kfree(pno); ++ } + break; + default: + break; +@@ -354,6 +469,51 @@ static int ath11k_wow_set_wakeups(struct + return 0; + } + ++static int ath11k_vif_wow_clean_nlo(struct ath11k_vif *arvif) ++{ ++ int ret = 0; ++ struct ath11k *ar = arvif->ar; ++ ++ switch (arvif->vdev_type) { ++ case WMI_VDEV_TYPE_STA: ++ if (ar->nlo_enabled) { ++ struct wmi_pno_scan_req *pno; ++ ++ pno = kzalloc(sizeof(*pno), GFP_KERNEL); ++ if (!pno) ++ return -ENOMEM; ++ ++ pno->enable = 0; ++ ar->nlo_enabled = false; ++ ret = ath11k_wmi_wow_config_pno(ar, arvif->vdev_id, pno); ++ kfree(pno); ++ } ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int ath11k_wow_nlo_cleanup(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath11k_vif_wow_clean_nlo(arvif); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to clean nlo settings on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + int ath11k_wow_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) + { +@@ -439,8 +599,16 @@ int ath11k_wow_op_resume(struct ieee8021 + ath11k_hif_irq_enable(ar->ab); + + ret = ath11k_wow_wakeup(ar->ab); +- if (ret) ++ if (ret) { + ath11k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret); ++ goto exit; ++ } ++ ++ ret = ath11k_wow_nlo_cleanup(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to cleanup nlo: %d\n", ret); ++ goto exit; ++ } + + exit: + if (ret) { +@@ -477,6 +645,11 @@ int ath11k_wow_init(struct ath11k *ar) + ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; + } + ++ if (test_bit(WMI_TLV_SERVICE_NLO, ar->wmi->wmi_ab->svc_map)) { ++ ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT; ++ ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; ++ } ++ + ar->wow.max_num_patterns = ATH11K_WOW_PATTERNS; + ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; + ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; diff --git a/package/kernel/mac80211/patches/ath11k/0195-ath11k-implement-hardware-data-filter.patch b/package/kernel/mac80211/patches/ath11k/0195-ath11k-implement-hardware-data-filter.patch new file mode 100644 index 000000000..1d0ea5641 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0195-ath11k-implement-hardware-data-filter.patch @@ -0,0 +1,171 @@ +From c417b247ba042161ddfb34f26a42ec67edc5c378 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Mar 2022 07:18:16 +0200 +Subject: [PATCH] ath11k: implement hardware data filter + +Host needs to set hardware data filter before entering WoW to +let firmware drop needless broadcast/mulitcast frames to avoid +frequent wakeup. Host clears hardware data filter when leaving WoW. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644308006-22784-4-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 33 ++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 15 +++++++ + drivers/net/wireless/ath/ath11k/wow.c | 57 +++++++++++++++++++++++++++ + 3 files changed, 105 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -8165,6 +8165,39 @@ void ath11k_wmi_detach(struct ath11k_bas + ath11k_wmi_free_dbring_caps(ab); + } + ++int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id, ++ u32 filter_bitmap, bool enable) ++{ ++ struct wmi_hw_data_filter_cmd *cmd; ++ struct sk_buff *skb; ++ int len; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_hw_data_filter_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_HW_DATA_FILTER_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ cmd->enable = enable; ++ ++ /* Set all modes in case of disable */ ++ if (cmd->enable) ++ cmd->hw_filter_bitmap = filter_bitmap; ++ else ++ cmd->hw_filter_bitmap = ((u32)~0U); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi hw data filter enable %d filter_bitmap 0x%x\n", ++ enable, filter_bitmap); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_HW_DATA_FILTER_CMDID); ++} ++ + int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar) + { + struct wmi_wow_host_wakeup_ind *cmd; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5390,6 +5390,19 @@ struct ath11k_wmi_base { + struct ath11k_targ_cap *targ_cap; + }; + ++/* Definition of HW data filtering */ ++enum hw_data_filter_type { ++ WMI_HW_DATA_FILTER_DROP_NON_ARP_BC = BIT(0), ++ WMI_HW_DATA_FILTER_DROP_NON_ICMPV6_MC = BIT(1), ++}; ++ ++struct wmi_hw_data_filter_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 enable; ++ u32 hw_filter_bitmap; ++} __packed; ++ + /* WOW structures */ + enum wmi_wow_wakeup_event { + WOW_BMISS_EVENT = 0, +@@ -5953,4 +5966,6 @@ int ath11k_wmi_wow_add_pattern(struct at + int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id, + enum wmi_wow_wakeup_event event, + u32 enable); ++int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id, ++ u32 filter_bitmap, bool enable); + #endif +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -514,6 +514,50 @@ static int ath11k_wow_nlo_cleanup(struct + return 0; + } + ++static int ath11k_wow_set_hw_filter(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ u32 bitmap; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ bitmap = WMI_HW_DATA_FILTER_DROP_NON_ICMPV6_MC | ++ WMI_HW_DATA_FILTER_DROP_NON_ARP_BC; ++ ret = ath11k_wmi_hw_data_filter_cmd(ar, arvif->vdev_id, ++ bitmap, ++ true); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set hw data filter on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ath11k_wow_clear_hw_filter(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath11k_wmi_hw_data_filter_cmd(ar, arvif->vdev_id, 0, false); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to clear hw data filter on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + int ath11k_wow_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) + { +@@ -542,6 +586,13 @@ int ath11k_wow_op_suspend(struct ieee802 + goto cleanup; + } + ++ ret = ath11k_wow_set_hw_filter(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set hw filter: %d\n", ++ ret); ++ goto cleanup; ++ } ++ + ret = ath11k_wow_enable(ar->ab); + if (ret) { + ath11k_warn(ar->ab, "failed to start wow: %d\n", ret); +@@ -610,6 +661,12 @@ int ath11k_wow_op_resume(struct ieee8021 + goto exit; + } + ++ ret = ath11k_wow_clear_hw_filter(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to clear hw filter: %d\n", ret); ++ goto exit; ++ } ++ + exit: + if (ret) { + switch (ar->state) { diff --git a/package/kernel/mac80211/patches/ath11k/0196-ath11k-purge-rx-pktlog-when-entering-WoW.patch b/package/kernel/mac80211/patches/ath11k/0196-ath11k-purge-rx-pktlog-when-entering-WoW.patch new file mode 100644 index 000000000..f76533cac --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0196-ath11k-purge-rx-pktlog-when-entering-WoW.patch @@ -0,0 +1,72 @@ +From 90bf5c8d0f7ecddf96fc1cd9434af4e157b51970 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Mar 2022 07:18:16 +0200 +Subject: [PATCH] ath11k: purge rx pktlog when entering WoW + +This change is to purge rx pktlog when entering WoW and reap +the mon_status buffer to keep it empty. When leaving WoW, host +restarts the reap timer. In WoW state, it's not allowed to feed +into mon_status rings per firmware team's recommendation. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644308006-22784-5-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wow.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -13,6 +13,7 @@ + #include "debug.h" + #include "wmi.h" + #include "wow.h" ++#include "dp_rx.h" + + static const struct wiphy_wowlan_support ath11k_wowlan_support = { + .flags = WIPHY_WOWLAN_DISCONNECT | +@@ -566,6 +567,14 @@ int ath11k_wow_op_suspend(struct ieee802 + + mutex_lock(&ar->conf_mutex); + ++ ret = ath11k_dp_rx_pktlog_stop(ar->ab, true); ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to stop dp rx (and timer) pktlog during wow suspend: %d\n", ++ ret); ++ goto exit; ++ } ++ + ret = ath11k_wow_cleanup(ar); + if (ret) { + ath11k_warn(ar->ab, "failed to clear wow wakeup events: %d\n", +@@ -599,6 +608,14 @@ int ath11k_wow_op_suspend(struct ieee802 + goto cleanup; + } + ++ ret = ath11k_dp_rx_pktlog_stop(ar->ab, false); ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to stop dp rx pktlog during wow suspend: %d\n", ++ ret); ++ goto cleanup; ++ } ++ + ath11k_ce_stop_shadow_timers(ar->ab); + ath11k_dp_stop_shadow_timers(ar->ab); + +@@ -649,6 +666,12 @@ int ath11k_wow_op_resume(struct ieee8021 + ath11k_hif_ce_irq_enable(ar->ab); + ath11k_hif_irq_enable(ar->ab); + ++ ret = ath11k_dp_rx_pktlog_start(ar->ab); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start rx pktlog from wow: %d\n", ret); ++ return ret; ++ } ++ + ret = ath11k_wow_wakeup(ar->ab); + if (ret) { + ath11k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret); diff --git a/package/kernel/mac80211/patches/ath11k/0197-ath11k-support-ARP-and-NS-offload.patch b/package/kernel/mac80211/patches/ath11k/0197-ath11k-support-ARP-and-NS-offload.patch new file mode 100644 index 000000000..f5fe9a4dd --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0197-ath11k-support-ARP-and-NS-offload.patch @@ -0,0 +1,519 @@ +From c3c36bfe998b3ad14aa87a57037a05d861889ac8 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Mar 2022 07:18:16 +0200 +Subject: [PATCH] ath11k: support ARP and NS offload + +Support ARP and NS offload in WoW state. + +Tested this way: put machine A with QCA6390 to WoW state, +ping/ping6 machine A from another machine B, check sniffer to see +any ARP response and Neighbour advertisement from machine A. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644308006-22784-6-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 19 +++ + drivers/net/wireless/ath/ath11k/mac.c | 118 +++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 155 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 47 ++++++++ + drivers/net/wireless/ath/ath11k/wow.c | 52 +++++++++ + 5 files changed, 391 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -213,6 +213,23 @@ enum ath11k_monitor_flags { + ATH11K_FLAG_MONITOR_VDEV_CREATED, + }; + ++#define ATH11K_IPV6_UC_TYPE 0 ++#define ATH11K_IPV6_AC_TYPE 1 ++ ++#define ATH11K_IPV6_MAX_COUNT 16 ++#define ATH11K_IPV4_MAX_COUNT 2 ++ ++struct ath11k_arp_ns_offload { ++ u8 ipv4_addr[ATH11K_IPV4_MAX_COUNT][4]; ++ u32 ipv4_count; ++ u32 ipv6_count; ++ u8 ipv6_addr[ATH11K_IPV6_MAX_COUNT][16]; ++ u8 self_ipv6_addr[ATH11K_IPV6_MAX_COUNT][16]; ++ u8 ipv6_type[ATH11K_IPV6_MAX_COUNT]; ++ bool ipv6_valid[ATH11K_IPV6_MAX_COUNT]; ++ u8 mac_addr[ETH_ALEN]; ++}; ++ + struct ath11k_vif { + u32 vdev_id; + enum wmi_vdev_type vdev_type; +@@ -264,6 +281,8 @@ struct ath11k_vif { + bool bcca_zero_sent; + bool do_not_send_tmpl; + struct ieee80211_chanctx_conf chanctx; ++ struct ath11k_arp_ns_offload arp_ns_offload; ++ + #ifdef CPTCFG_ATH11K_DEBUGFS + struct dentry *debugfs_twt; + #endif /* CPTCFG_ATH11K_DEBUGFS */ +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6,6 +6,11 @@ + + #include + #include ++#include ++#include ++#include ++#include ++ + #include "mac.h" + #include "core.h" + #include "debug.h" +@@ -3095,6 +3100,7 @@ static void ath11k_mac_op_bss_info_chang + int ret = 0; + u8 rateidx; + u32 rate; ++ u32 ipv4_cnt; + + mutex_lock(&ar->conf_mutex); + +@@ -3387,6 +3393,18 @@ static void ath11k_mac_op_bss_info_chang + changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP) + ath11k_mac_fils_discovery(arvif, info); + ++ if (changed & BSS_CHANGED_ARP_FILTER) { ++ ipv4_cnt = min(info->arp_addr_cnt, ATH11K_IPV4_MAX_COUNT); ++ memcpy(arvif->arp_ns_offload.ipv4_addr, info->arp_addr_list, ++ ipv4_cnt * sizeof(u32)); ++ memcpy(arvif->arp_ns_offload.mac_addr, vif->addr, ETH_ALEN); ++ arvif->arp_ns_offload.ipv4_count = ipv4_cnt; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac arp_addr_cnt %d vif->addr %pM, offload_addr %pI4\n", ++ info->arp_addr_cnt, ++ vif->addr, arvif->arp_ns_offload.ipv4_addr); ++ } ++ + mutex_unlock(&ar->conf_mutex); + } + +@@ -8087,6 +8105,101 @@ static void ath11k_mac_op_sta_statistics + } + } + ++static void ath11k_generate_ns_mc_addr(struct ath11k *ar, ++ struct ath11k_arp_ns_offload *offload) ++{ ++ int i; ++ ++ for (i = 0; i < offload->ipv6_count; i++) { ++ offload->self_ipv6_addr[i][0] = 0xff; ++ offload->self_ipv6_addr[i][1] = 0x02; ++ offload->self_ipv6_addr[i][11] = 0x01; ++ offload->self_ipv6_addr[i][12] = 0xff; ++ offload->self_ipv6_addr[i][13] = ++ offload->ipv6_addr[i][13]; ++ offload->self_ipv6_addr[i][14] = ++ offload->ipv6_addr[i][14]; ++ offload->self_ipv6_addr[i][15] = ++ offload->ipv6_addr[i][15]; ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "NS solicited addr %pI6\n", ++ offload->self_ipv6_addr[i]); ++ } ++} ++ ++static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct inet6_dev *idev) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ath11k_arp_ns_offload *offload; ++ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); ++ struct inet6_ifaddr *ifa6; ++ struct ifacaddr6 *ifaca6; ++ struct list_head *p; ++ u32 count, scope; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac op ipv6 changed\n"); ++ ++ offload = &arvif->arp_ns_offload; ++ count = 0; ++ ++ read_lock_bh(&idev->lock); ++ ++ memset(offload->ipv6_addr, 0, sizeof(offload->ipv6_addr)); ++ memset(offload->self_ipv6_addr, 0, sizeof(offload->self_ipv6_addr)); ++ memcpy(offload->mac_addr, vif->addr, ETH_ALEN); ++ ++ /* get unicast address */ ++ list_for_each(p, &idev->addr_list) { ++ if (count >= ATH11K_IPV6_MAX_COUNT) ++ goto generate; ++ ++ ifa6 = list_entry(p, struct inet6_ifaddr, if_list); ++ if (ifa6->flags & IFA_F_DADFAILED) ++ continue; ++ scope = ipv6_addr_src_scope(&ifa6->addr); ++ if (scope == IPV6_ADDR_SCOPE_LINKLOCAL || ++ scope == IPV6_ADDR_SCOPE_GLOBAL) { ++ memcpy(offload->ipv6_addr[count], &ifa6->addr.s6_addr, ++ sizeof(ifa6->addr.s6_addr)); ++ offload->ipv6_type[count] = ATH11K_IPV6_UC_TYPE; ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac count %d ipv6 uc %pI6 scope %d\n", ++ count, offload->ipv6_addr[count], ++ scope); ++ count++; ++ } else { ++ ath11k_warn(ar->ab, "Unsupported ipv6 scope: %d\n", scope); ++ } ++ } ++ ++ /* get anycast address */ ++ for (ifaca6 = idev->ac_list; ifaca6; ifaca6 = ifaca6->aca_next) { ++ if (count >= ATH11K_IPV6_MAX_COUNT) ++ goto generate; ++ ++ scope = ipv6_addr_src_scope(&ifaca6->aca_addr); ++ if (scope == IPV6_ADDR_SCOPE_LINKLOCAL || ++ scope == IPV6_ADDR_SCOPE_GLOBAL) { ++ memcpy(offload->ipv6_addr[count], &ifaca6->aca_addr, ++ sizeof(ifaca6->aca_addr)); ++ offload->ipv6_type[count] = ATH11K_IPV6_AC_TYPE; ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac count %d ipv6 ac %pI6 scope %d\n", ++ count, offload->ipv6_addr[count], ++ scope); ++ count++; ++ } else { ++ ath11k_warn(ar->ab, "Unsupported ipv scope: %d\n", scope); ++ } ++ } ++ ++generate: ++ offload->ipv6_count = count; ++ read_unlock_bh(&idev->lock); ++ ++ /* generate ns multicast address */ ++ ath11k_generate_ns_mc_addr(ar, offload); ++} ++ + static const struct ieee80211_ops ath11k_ops = { + .tx = ath11k_mac_op_tx, + .start = ath11k_mac_op_start, +@@ -8132,6 +8245,11 @@ static const struct ieee80211_ops ath11k + #ifdef CPTCFG_ATH11K_DEBUGFS + .sta_add_debugfs = ath11k_debugfs_sta_op_add, + #endif ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ .ipv6_addr_change = ath11k_mac_op_ipv6_changed, ++#endif ++ + }; + + static void ath11k_mac_update_ch_list(struct ath11k *ar, +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -8580,3 +8580,158 @@ int ath11k_wmi_wow_config_pno(struct ath + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + } + ++static void ath11k_wmi_fill_ns_offload(struct ath11k *ar, ++ struct ath11k_arp_ns_offload *offload, ++ u8 **ptr, ++ bool enable, ++ bool ext) ++{ ++ struct wmi_ns_offload_tuple *ns; ++ struct wmi_tlv *tlv; ++ u8 *buf_ptr = *ptr; ++ u32 ns_cnt, ns_ext_tuples; ++ int i, max_offloads; ++ ++ ns_cnt = offload->ipv6_count; ++ ++ tlv = (struct wmi_tlv *)buf_ptr; ++ ++ if (ext) { ++ ns_ext_tuples = offload->ipv6_count - WMI_MAX_NS_OFFLOADS; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, ns_ext_tuples * sizeof(*ns)); ++ i = WMI_MAX_NS_OFFLOADS; ++ max_offloads = offload->ipv6_count; ++ } else { ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, WMI_MAX_NS_OFFLOADS * sizeof(*ns)); ++ i = 0; ++ max_offloads = WMI_MAX_NS_OFFLOADS; ++ } ++ ++ buf_ptr += sizeof(*tlv); ++ ++ for (; i < max_offloads; i++) { ++ ns = (struct wmi_ns_offload_tuple *)buf_ptr; ++ ns->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_NS_OFFLOAD_TUPLE) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*ns) - TLV_HDR_SIZE); ++ ++ if (enable) { ++ if (i < ns_cnt) ++ ns->flags |= WMI_NSOL_FLAGS_VALID; ++ ++ memcpy(ns->target_ipaddr[0], offload->ipv6_addr[i], 16); ++ memcpy(ns->solicitation_ipaddr, offload->self_ipv6_addr[i], 16); ++ ath11k_ce_byte_swap(ns->target_ipaddr[0], 16); ++ ath11k_ce_byte_swap(ns->solicitation_ipaddr, 16); ++ ++ if (offload->ipv6_type[i]) ++ ns->flags |= WMI_NSOL_FLAGS_IS_IPV6_ANYCAST; ++ ++ memcpy(ns->target_mac.addr, offload->mac_addr, ETH_ALEN); ++ ath11k_ce_byte_swap(ns->target_mac.addr, 8); ++ ++ if (ns->target_mac.word0 != 0 || ++ ns->target_mac.word1 != 0) { ++ ns->flags |= WMI_NSOL_FLAGS_MAC_VALID; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi index %d ns_solicited %pI6 target %pI6", ++ i, ns->solicitation_ipaddr, ++ ns->target_ipaddr[0]); ++ } ++ ++ buf_ptr += sizeof(*ns); ++ } ++ ++ *ptr = buf_ptr; ++} ++ ++static void ath11k_wmi_fill_arp_offload(struct ath11k *ar, ++ struct ath11k_arp_ns_offload *offload, ++ u8 **ptr, ++ bool enable) ++{ ++ struct wmi_arp_offload_tuple *arp; ++ struct wmi_tlv *tlv; ++ u8 *buf_ptr = *ptr; ++ int i; ++ ++ /* fill arp tuple */ ++ tlv = (struct wmi_tlv *)buf_ptr; ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | ++ FIELD_PREP(WMI_TLV_LEN, WMI_MAX_ARP_OFFLOADS * sizeof(*arp)); ++ buf_ptr += sizeof(*tlv); ++ ++ for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { ++ arp = (struct wmi_arp_offload_tuple *)buf_ptr; ++ arp->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARP_OFFLOAD_TUPLE) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*arp) - TLV_HDR_SIZE); ++ ++ if (enable && i < offload->ipv4_count) { ++ /* Copy the target ip addr and flags */ ++ arp->flags = WMI_ARPOL_FLAGS_VALID; ++ memcpy(arp->target_ipaddr, offload->ipv4_addr[i], 4); ++ ath11k_ce_byte_swap(arp->target_ipaddr, 4); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi arp offload address %pI4", ++ arp->target_ipaddr); ++ } ++ ++ buf_ptr += sizeof(*arp); ++ } ++ ++ *ptr = buf_ptr; ++} ++ ++int ath11k_wmi_arp_ns_offload(struct ath11k *ar, ++ struct ath11k_vif *arvif, bool enable) ++{ ++ struct ath11k_arp_ns_offload *offload; ++ struct wmi_set_arp_ns_offload_cmd *cmd; ++ struct wmi_tlv *tlv; ++ struct sk_buff *skb; ++ u8 *buf_ptr; ++ size_t len; ++ u8 ns_cnt, ns_ext_tuples = 0; ++ ++ offload = &arvif->arp_ns_offload; ++ ns_cnt = offload->ipv6_count; ++ ++ len = sizeof(*cmd) + ++ sizeof(*tlv) + ++ WMI_MAX_NS_OFFLOADS * sizeof(struct wmi_ns_offload_tuple) + ++ sizeof(*tlv) + ++ WMI_MAX_ARP_OFFLOADS * sizeof(struct wmi_arp_offload_tuple); ++ ++ if (ns_cnt > WMI_MAX_NS_OFFLOADS) { ++ ns_ext_tuples = ns_cnt - WMI_MAX_NS_OFFLOADS; ++ len += sizeof(*tlv) + ++ ns_ext_tuples * sizeof(struct wmi_ns_offload_tuple); ++ } ++ ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ buf_ptr = skb->data; ++ cmd = (struct wmi_set_arp_ns_offload_cmd *)buf_ptr; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_SET_ARP_NS_OFFLOAD_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->flags = 0; ++ cmd->vdev_id = arvif->vdev_id; ++ cmd->num_ns_ext_tuples = ns_ext_tuples; ++ ++ buf_ptr += sizeof(*cmd); ++ ++ ath11k_wmi_fill_ns_offload(ar, offload, &buf_ptr, enable, 0); ++ ath11k_wmi_fill_arp_offload(ar, offload, &buf_ptr, enable); ++ ++ if (ns_ext_tuples) ++ ath11k_wmi_fill_ns_offload(ar, offload, &buf_ptr, enable, 1); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID); ++} +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -13,6 +13,7 @@ struct ath11k_base; + struct ath11k; + struct ath11k_fw_stats; + struct ath11k_fw_dbglog; ++struct ath11k_vif; + + #define PSOC_HOST_MAX_NUM_SS (8) + +@@ -5796,6 +5797,49 @@ struct wmi_wow_nlo_config_cmd { + */ + } __packed; + ++#define WMI_MAX_NS_OFFLOADS 2 ++#define WMI_MAX_ARP_OFFLOADS 2 ++ ++#define WMI_ARPOL_FLAGS_VALID BIT(0) ++#define WMI_ARPOL_FLAGS_MAC_VALID BIT(1) ++#define WMI_ARPOL_FLAGS_REMOTE_IP_VALID BIT(2) ++ ++struct wmi_arp_offload_tuple { ++ u32 tlv_header; ++ u32 flags; ++ u8 target_ipaddr[4]; ++ u8 remote_ipaddr[4]; ++ struct wmi_mac_addr target_mac; ++} __packed; ++ ++#define WMI_NSOL_FLAGS_VALID BIT(0) ++#define WMI_NSOL_FLAGS_MAC_VALID BIT(1) ++#define WMI_NSOL_FLAGS_REMOTE_IP_VALID BIT(2) ++#define WMI_NSOL_FLAGS_IS_IPV6_ANYCAST BIT(3) ++ ++#define WMI_NSOL_MAX_TARGET_IPS 2 ++ ++struct wmi_ns_offload_tuple { ++ u32 tlv_header; ++ u32 flags; ++ u8 target_ipaddr[WMI_NSOL_MAX_TARGET_IPS][16]; ++ u8 solicitation_ipaddr[16]; ++ u8 remote_ipaddr[16]; ++ struct wmi_mac_addr target_mac; ++} __packed; ++ ++struct wmi_set_arp_ns_offload_cmd { ++ u32 tlv_header; ++ u32 flags; ++ u32 vdev_id; ++ u32 num_ns_ext_tuples; ++ /* The TLVs follow: ++ * wmi_ns_offload_tuple ns_tuples[WMI_MAX_NS_OFFLOADS]; ++ * wmi_arp_offload_tuple arp_tuples[WMI_MAX_ARP_OFFLOADS]; ++ * wmi_ns_offload_tuple ns_ext_tuples[num_ns_ext_tuples]; ++ */ ++} __packed; ++ + int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, + u32 cmd_id); + struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); +@@ -5968,4 +6012,7 @@ int ath11k_wmi_wow_add_wakeup_event(stru + u32 enable); + int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id, + u32 filter_bitmap, bool enable); ++int ath11k_wmi_arp_ns_offload(struct ath11k *ar, ++ struct ath11k_vif *arvif, bool enable); ++ + #endif +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -559,6 +559,43 @@ static int ath11k_wow_clear_hw_filter(st + return 0; + } + ++static int ath11k_wow_arp_ns_offload(struct ath11k *ar, bool enable) ++{ ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif->vdev_type != WMI_VDEV_TYPE_STA) ++ continue; ++ ++ ret = ath11k_wmi_arp_ns_offload(ar, arvif, enable); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set arp ns offload vdev %i: enable %d, ret %d\n", ++ arvif->vdev_id, enable, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ath11k_wow_protocol_offload(struct ath11k *ar, bool enable) ++{ ++ int ret; ++ ++ ret = ath11k_wow_arp_ns_offload(ar, enable); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to offload ARP and NS %d %d\n", ++ enable, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ + int ath11k_wow_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) + { +@@ -589,6 +626,14 @@ int ath11k_wow_op_suspend(struct ieee802 + goto cleanup; + } + ++ ret = ath11k_wow_protocol_offload(ar, true); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set wow protocol offload events: %d\n", ++ ret); ++ goto cleanup; ++ } ++ ++ ath11k_mac_drain_tx(ar); + ret = ath11k_mac_wait_tx_complete(ar); + if (ret) { + ath11k_warn(ar->ab, "failed to wait tx complete: %d\n", ret); +@@ -690,6 +735,13 @@ int ath11k_wow_op_resume(struct ieee8021 + goto exit; + } + ++ ret = ath11k_wow_protocol_offload(ar, false); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to clear wow protocol offload events: %d\n", ++ ret); ++ goto exit; ++ } ++ + exit: + if (ret) { + switch (ar->state) { diff --git a/package/kernel/mac80211/patches/ath11k/0198-ath11k-support-GTK-rekey-offload.patch b/package/kernel/mac80211/patches/ath11k/0198-ath11k-support-GTK-rekey-offload.patch new file mode 100644 index 000000000..7cc33abaf --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0198-ath11k-support-GTK-rekey-offload.patch @@ -0,0 +1,384 @@ +From a16d9b50cfbaf112401b8e5ccfa852709f498cd4 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Mar 2022 07:18:16 +0200 +Subject: [PATCH] ath11k: support GTK rekey offload + +Host sets GTK related info to firmware before WoW is enabled, and +gets rekey replay_count and then disables GTK rekey when WoW quits. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644308006-22784-7-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 8 ++ + drivers/net/wireless/ath/ath11k/mac.c | 37 ++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 119 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 49 ++++++++++ + drivers/net/wireless/ath/ath11k/wow.c | 46 +++++++++- + 5 files changed, 258 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -230,6 +230,13 @@ struct ath11k_arp_ns_offload { + u8 mac_addr[ETH_ALEN]; + }; + ++struct ath11k_rekey_data { ++ u8 kck[NL80211_KCK_LEN]; ++ u8 kek[NL80211_KCK_LEN]; ++ u64 replay_ctr; ++ bool enable_offload; ++}; ++ + struct ath11k_vif { + u32 vdev_id; + enum wmi_vdev_type vdev_type; +@@ -282,6 +289,7 @@ struct ath11k_vif { + bool do_not_send_tmpl; + struct ieee80211_chanctx_conf chanctx; + struct ath11k_arp_ns_offload arp_ns_offload; ++ struct ath11k_rekey_data rekey_data; + + #ifdef CPTCFG_ATH11K_DEBUGFS + struct dentry *debugfs_twt; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2757,6 +2757,7 @@ static void ath11k_bss_assoc(struct ieee + } + + arvif->is_up = true; ++ arvif->rekey_data.enable_offload = false; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac vdev %d up (associated) bssid %pM aid %d\n", +@@ -2814,6 +2815,8 @@ static void ath11k_bss_disassoc(struct i + + arvif->is_up = false; + ++ memset(&arvif->rekey_data, 0, sizeof(arvif->rekey_data)); ++ + cancel_delayed_work_sync(&arvif->connection_loss_work); + } + +@@ -8200,6 +8203,39 @@ generate: + ath11k_generate_ns_mc_addr(ar, offload); + } + ++static void ath11k_mac_op_set_rekey_data(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct cfg80211_gtk_rekey_data *data) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); ++ struct ath11k_rekey_data *rekey_data = &arvif->rekey_data; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set rekey data vdev %d\n", ++ arvif->vdev_id); ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ memcpy(rekey_data->kck, data->kck, NL80211_KCK_LEN); ++ memcpy(rekey_data->kek, data->kek, NL80211_KEK_LEN); ++ ++ /* The supplicant works on big-endian, the firmware expects it on ++ * little endian. ++ */ ++ rekey_data->replay_ctr = get_unaligned_be64(data->replay_ctr); ++ ++ arvif->rekey_data.enable_offload = true; ++ ++ ath11k_dbg_dump(ar->ab, ATH11K_DBG_MAC, "kck", NULL, ++ rekey_data->kck, NL80211_KCK_LEN); ++ ath11k_dbg_dump(ar->ab, ATH11K_DBG_MAC, "kek", NULL, ++ rekey_data->kck, NL80211_KEK_LEN); ++ ath11k_dbg_dump(ar->ab, ATH11K_DBG_MAC, "replay ctr", NULL, ++ &rekey_data->replay_ctr, sizeof(rekey_data->replay_ctr)); ++ ++ mutex_unlock(&ar->conf_mutex); ++} ++ + static const struct ieee80211_ops ath11k_ops = { + .tx = ath11k_mac_op_tx, + .start = ath11k_mac_op_start, +@@ -8214,6 +8250,7 @@ static const struct ieee80211_ops ath11k + .hw_scan = ath11k_mac_op_hw_scan, + .cancel_hw_scan = ath11k_mac_op_cancel_hw_scan, + .set_key = ath11k_mac_op_set_key, ++ .set_rekey_data = ath11k_mac_op_set_rekey_data, + .sta_state = ath11k_mac_op_sta_state, + .sta_set_4addr = ath11k_mac_op_sta_set_4addr, + .sta_set_txpwr = ath11k_mac_op_sta_set_txpwr, +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7765,6 +7765,56 @@ exit: + kfree(tb); + } + ++static void ath11k_wmi_gtk_offload_status_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ const void **tb; ++ const struct wmi_gtk_offload_status_event *ev; ++ struct ath11k_vif *arvif; ++ __be64 replay_ctr_be; ++ u64 replay_ctr; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT]; ++ if (!ev) { ++ ath11k_warn(ab, "failed to fetch gtk offload status ev"); ++ kfree(tb); ++ return; ++ } ++ ++ arvif = ath11k_mac_get_arvif_by_vdev_id(ab, ev->vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "failed to get arvif for vdev_id:%d\n", ++ ev->vdev_id); ++ kfree(tb); ++ return; ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi gtk offload event refresh_cnt %d\n", ++ ev->refresh_cnt); ++ ath11k_dbg_dump(ab, ATH11K_DBG_WMI, "replay_cnt", ++ NULL, ev->replay_ctr.counter, GTK_REPLAY_COUNTER_BYTES); ++ ++ replay_ctr = ev->replay_ctr.word1; ++ replay_ctr = (replay_ctr << 32) | ev->replay_ctr.word0; ++ arvif->rekey_data.replay_ctr = replay_ctr; ++ ++ /* supplicant expects big-endian replay counter */ ++ replay_ctr_be = cpu_to_be64(replay_ctr); ++ ++ ieee80211_gtk_rekey_notify(arvif->vif, arvif->bssid, ++ (void *)&replay_ctr_be, GFP_KERNEL); ++ ++ kfree(tb); ++} ++ + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) + { + struct wmi_cmd_hdr *cmd_hdr; +@@ -7896,6 +7946,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_DIAG_EVENTID: + ath11k_wmi_diag_event(ab, skb); + break; ++ case WMI_GTK_OFFLOAD_STATUS_EVENTID: ++ ath11k_wmi_gtk_offload_status_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); +@@ -8735,3 +8788,69 @@ int ath11k_wmi_arp_ns_offload(struct ath + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID); + } ++ ++int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar, ++ struct ath11k_vif *arvif, bool enable) ++{ ++ struct wmi_gtk_rekey_offload_cmd *cmd; ++ struct ath11k_rekey_data *rekey_data = &arvif->rekey_data; ++ int len; ++ struct sk_buff *skb; ++ __le64 replay_ctr; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_gtk_rekey_offload_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_GTK_OFFLOAD_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = arvif->vdev_id; ++ ++ if (enable) { ++ cmd->flags = GTK_OFFLOAD_ENABLE_OPCODE; ++ ++ /* the length in rekey_data and cmd is equal */ ++ memcpy(cmd->kck, rekey_data->kck, sizeof(cmd->kck)); ++ ath11k_ce_byte_swap(cmd->kck, GTK_OFFLOAD_KEK_BYTES); ++ memcpy(cmd->kek, rekey_data->kek, sizeof(cmd->kek)); ++ ath11k_ce_byte_swap(cmd->kek, GTK_OFFLOAD_KEK_BYTES); ++ ++ replay_ctr = cpu_to_le64(rekey_data->replay_ctr); ++ memcpy(cmd->replay_ctr, &replay_ctr, ++ sizeof(replay_ctr)); ++ ath11k_ce_byte_swap(cmd->replay_ctr, GTK_REPLAY_COUNTER_BYTES); ++ } else { ++ cmd->flags = GTK_OFFLOAD_DISABLE_OPCODE; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "offload gtk rekey vdev: %d %d\n", ++ arvif->vdev_id, enable); ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID); ++} ++ ++int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar, ++ struct ath11k_vif *arvif) ++{ ++ struct wmi_gtk_rekey_offload_cmd *cmd; ++ int len; ++ struct sk_buff *skb; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_gtk_rekey_offload_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_GTK_OFFLOAD_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = arvif->vdev_id; ++ cmd->flags = GTK_OFFLOAD_REQUEST_STATUS_OPCODE; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "get gtk rekey vdev_id: %d\n", ++ arvif->vdev_id); ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID); ++} +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5840,6 +5840,51 @@ struct wmi_set_arp_ns_offload_cmd { + */ + } __packed; + ++#define GTK_OFFLOAD_OPCODE_MASK 0xFF000000 ++#define GTK_OFFLOAD_ENABLE_OPCODE 0x01000000 ++#define GTK_OFFLOAD_DISABLE_OPCODE 0x02000000 ++#define GTK_OFFLOAD_REQUEST_STATUS_OPCODE 0x04000000 ++ ++#define GTK_OFFLOAD_KEK_BYTES 16 ++#define GTK_OFFLOAD_KCK_BYTES 16 ++#define GTK_REPLAY_COUNTER_BYTES 8 ++#define WMI_MAX_KEY_LEN 32 ++#define IGTK_PN_SIZE 6 ++ ++struct wmi_replayc_cnt { ++ union { ++ u8 counter[GTK_REPLAY_COUNTER_BYTES]; ++ struct { ++ u32 word0; ++ u32 word1; ++ } __packed; ++ } __packed; ++} __packed; ++ ++struct wmi_gtk_offload_status_event { ++ u32 vdev_id; ++ u32 flags; ++ u32 refresh_cnt; ++ struct wmi_replayc_cnt replay_ctr; ++ u8 igtk_key_index; ++ u8 igtk_key_length; ++ u8 igtk_key_rsc[IGTK_PN_SIZE]; ++ u8 igtk_key[WMI_MAX_KEY_LEN]; ++ u8 gtk_key_index; ++ u8 gtk_key_length; ++ u8 gtk_key_rsc[GTK_REPLAY_COUNTER_BYTES]; ++ u8 gtk_key[WMI_MAX_KEY_LEN]; ++} __packed; ++ ++struct wmi_gtk_rekey_offload_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 flags; ++ u8 kek[GTK_OFFLOAD_KEK_BYTES]; ++ u8 kck[GTK_OFFLOAD_KCK_BYTES]; ++ u8 replay_ctr[GTK_REPLAY_COUNTER_BYTES]; ++} __packed; ++ + int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, + u32 cmd_id); + struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); +@@ -6014,5 +6059,9 @@ int ath11k_wmi_hw_data_filter_cmd(struct + u32 filter_bitmap, bool enable); + int ath11k_wmi_arp_ns_offload(struct ath11k *ar, + struct ath11k_vif *arvif, bool enable); ++int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar, ++ struct ath11k_vif *arvif, bool enable); ++int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar, ++ struct ath11k_vif *arvif); + + #endif +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -17,7 +17,9 @@ + + static const struct wiphy_wowlan_support ath11k_wowlan_support = { + .flags = WIPHY_WOWLAN_DISCONNECT | +- WIPHY_WOWLAN_MAGIC_PKT, ++ WIPHY_WOWLAN_MAGIC_PKT | ++ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | ++ WIPHY_WOWLAN_GTK_REKEY_FAILURE, + .pattern_min_len = WOW_MIN_PATTERN_SIZE, + .pattern_max_len = WOW_MAX_PATTERN_SIZE, + .max_pkt_offset = WOW_MAX_PKT_OFFSET, +@@ -582,6 +584,41 @@ static int ath11k_wow_arp_ns_offload(str + return 0; + } + ++static int ath11k_gtk_rekey_offload(struct ath11k *ar, bool enable) ++{ ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif->vdev_type != WMI_VDEV_TYPE_STA || ++ !arvif->is_up || ++ !arvif->rekey_data.enable_offload) ++ continue; ++ ++ /* get rekey info before disable rekey offload */ ++ if (!enable) { ++ ret = ath11k_wmi_gtk_rekey_getinfo(ar, arvif); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request rekey info vdev %i, ret %d\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } ++ ++ ret = ath11k_wmi_gtk_rekey_offload(ar, arvif, enable); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to offload gtk reky vdev %i: enable %d, ret %d\n", ++ arvif->vdev_id, enable, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + static int ath11k_wow_protocol_offload(struct ath11k *ar, bool enable) + { + int ret; +@@ -592,6 +629,13 @@ static int ath11k_wow_protocol_offload(s + enable, ret); + return ret; + } ++ ++ ret = ath11k_gtk_rekey_offload(ar, enable); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to offload gtk rekey %d %d\n", ++ enable, ret); ++ return ret; ++ } + + return 0; + } diff --git a/package/kernel/mac80211/patches/ath11k/0199-ath11k-Refactor-the-peer-delete.patch b/package/kernel/mac80211/patches/ath11k/0199-ath11k-Refactor-the-peer-delete.patch new file mode 100644 index 000000000..c86839b09 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0199-ath11k-Refactor-the-peer-delete.patch @@ -0,0 +1,103 @@ +From 997dc60f0855b39aec0400511b37d65781da9255 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Mon, 28 Feb 2022 10:24:39 +0530 +Subject: [PATCH] ath11k: Refactor the peer delete + +Introduce new helper function for peer delete to reuse this logic +in all peer cleanup procedures. Found this in code review. +Also this change is applicable for all the platform. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01067-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1646024079-26391-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 16 +++---------- + drivers/net/wireless/ath/ath11k/peer.c | 31 +++++++++++++------------- + 2 files changed, 19 insertions(+), 28 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6387,22 +6387,12 @@ static int ath11k_mac_op_add_interface(s + + err_peer_del: + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { +- reinit_completion(&ar->peer_delete_done); +- +- fbret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, +- arvif->vdev_id); ++ fbret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); + if (fbret) { +- ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", +- arvif->vdev_id, vif->addr); ++ ath11k_warn(ar->ab, "fallback fail to delete peer addr %pM vdev_id %d ret %d\n", ++ vif->addr, arvif->vdev_id, fbret); + goto err; + } +- +- fbret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, +- vif->addr); +- if (fbret) +- goto err; +- +- ar->num_peers--; + } + + err_vdev_del: +--- a/drivers/net/wireless/ath/ath11k/peer.c ++++ b/drivers/net/wireless/ath/ath11k/peer.c +@@ -217,7 +217,7 @@ int ath11k_wait_for_peer_delete_done(str + return 0; + } + +-int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr) ++static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr) + { + int ret; + +@@ -237,6 +237,19 @@ int ath11k_peer_delete(struct ath11k *ar + if (ret) + return ret; + ++ return 0; ++} ++ ++int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ ret = __ath11k_peer_delete(ar, vdev_id, addr); ++ if (ret) ++ return ret; ++ + ar->num_peers--; + + return 0; +@@ -323,22 +336,10 @@ int ath11k_peer_create(struct ath11k *ar + return 0; + + cleanup: +- reinit_completion(&ar->peer_delete_done); +- +- fbret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, +- param->vdev_id); +- if (fbret) { +- ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", +- param->vdev_id, param->peer_addr); +- goto exit; +- } +- +- fbret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, +- param->peer_addr); ++ fbret = __ath11k_peer_delete(ar, param->vdev_id, param->peer_addr); + if (fbret) +- ath11k_warn(ar->ab, "failed wait for peer %pM delete done id %d fallback ret %d\n", ++ ath11k_warn(ar->ab, "failed peer %pM delete vdev_id %d fallback ret %d\n", + param->peer_addr, param->vdev_id, fbret); + +-exit: + return ret; + } diff --git a/package/kernel/mac80211/patches/ath11k/0200-ath11k-change-fw-build-id-format-in-driver-init-log.patch b/package/kernel/mac80211/patches/ath11k/0200-ath11k-change-fw-build-id-format-in-driver-init-log.patch new file mode 100644 index 000000000..85c138049 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0200-ath11k-change-fw-build-id-format-in-driver-init-log.patch @@ -0,0 +1,65 @@ +From 72a9bff386545d3f8e9c432cb8e036272ad4e1fa Mon Sep 17 00:00:00 2001 +From: Hari Chandrakanthan +Date: Wed, 9 Mar 2022 16:54:25 +0530 +Subject: [PATCH] ath11k: change fw build id format in driver init log + +Currently fw build id is printed during init as follows. + +fw_version 0x250684a5 fw_build_timestamp 2021-07-13 10:57 +fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +The string "QC_IMAGE_VERSION_STRING=" is removed from the log +to improve readability. + +With this patch the fw build id is printed during init as follows. +fw_version 0x250684a5 fw_build_timestamp 2021-07-13 10:57 +fw_build_id WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Hari Chandrakanthan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1646825065-7736-1-git-send-email-quic_haric@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -16,6 +16,8 @@ + #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 + #define HOST_CSTATE_BIT 0x04 + ++#define FW_BUILD_ID_MASK "QC_IMAGE_VERSION_STRING=" ++ + bool ath11k_cold_boot_cal = 1; + EXPORT_SYMBOL(ath11k_cold_boot_cal); + module_param_named(cold_boot_cal, ath11k_cold_boot_cal, bool, 0644); +@@ -2008,6 +2010,8 @@ static int ath11k_qmi_request_target_cap + struct qmi_txn txn; + int ret = 0; + int r; ++ char *fw_build_id; ++ int fw_build_id_mask_len; + + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); +@@ -2073,6 +2077,11 @@ static int ath11k_qmi_request_target_cap + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cal data supported from eeprom\n"); + } + ++ fw_build_id = ab->qmi.target.fw_build_id; ++ fw_build_id_mask_len = strlen(FW_BUILD_ID_MASK); ++ if (!strncmp(fw_build_id, FW_BUILD_ID_MASK, fw_build_id_mask_len)) ++ fw_build_id = fw_build_id + fw_build_id_mask_len; ++ + ath11k_info(ab, "chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x\n", + ab->qmi.target.chip_id, ab->qmi.target.chip_family, + ab->qmi.target.board_id, ab->qmi.target.soc_id); +@@ -2080,7 +2089,7 @@ static int ath11k_qmi_request_target_cap + ath11k_info(ab, "fw_version 0x%x fw_build_timestamp %s fw_build_id %s", + ab->qmi.target.fw_version, + ab->qmi.target.fw_build_timestamp, +- ab->qmi.target.fw_build_id); ++ fw_build_id); + + r = ath11k_core_check_dt(ab); + if (r) diff --git a/package/kernel/mac80211/patches/ath11k/0201-ath11k-acquire-ab-base_lock-in-unassign-when-finding.patch b/package/kernel/mac80211/patches/ath11k/0201-ath11k-acquire-ab-base_lock-in-unassign-when-finding.patch new file mode 100644 index 000000000..98d06d6d6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0201-ath11k-acquire-ab-base_lock-in-unassign-when-finding.patch @@ -0,0 +1,54 @@ +From 2db80f93869d491be57cbc2b36f30d0d3a0e5bde Mon Sep 17 00:00:00 2001 +From: Niels Dossche +Date: Mon, 21 Mar 2022 12:58:23 +0200 +Subject: [PATCH] ath11k: acquire ab->base_lock in unassign when finding the + peer by addr + +ath11k_peer_find_by_addr states via lockdep that ab->base_lock must be +held when calling that function in order to protect the list. All +callers except ath11k_mac_op_unassign_vif_chanctx have that lock +acquired when calling ath11k_peer_find_by_addr. That lock is also not +transitively held by a path towards ath11k_mac_op_unassign_vif_chanctx. +The solution is to acquire the lock when calling +ath11k_peer_find_by_addr inside ath11k_mac_op_unassign_vif_chanctx. + +I am currently working on a static analyser to detect missing locks and +this was a reported case. I manually verified the report by looking at +the code, but I do not have real hardware so this is compile tested +only. + +Fixes: 701e48a43e15 ("ath11k: add packet log support for QCA6390") +Signed-off-by: Niels Dossche +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220314215253.92658-1-dossche.niels@gmail.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7133,6 +7133,7 @@ ath11k_mac_op_unassign_vif_chanctx(struc + struct ath11k *ar = hw->priv; + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = (void *)vif->drv_priv; ++ struct ath11k_peer *peer; + int ret; + + mutex_lock(&ar->conf_mutex); +@@ -7144,9 +7145,13 @@ ath11k_mac_op_unassign_vif_chanctx(struc + WARN_ON(!arvif->is_started); + + if (ab->hw_params.vdev_start_delay && +- arvif->vdev_type == WMI_VDEV_TYPE_MONITOR && +- ath11k_peer_find_by_addr(ab, ar->mac_addr)) +- ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr); ++ arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ spin_lock_bh(&ab->base_lock); ++ peer = ath11k_peer_find_by_addr(ab, ar->mac_addr); ++ spin_unlock_bh(&ab->base_lock); ++ if (peer) ++ ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr); ++ } + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + ret = ath11k_mac_monitor_stop(ar); diff --git a/package/kernel/mac80211/patches/ath11k/0202-ath11k-remove-unused-ATH11K_BD_IE_BOARD_EXT.patch b/package/kernel/mac80211/patches/ath11k/0202-ath11k-remove-unused-ATH11K_BD_IE_BOARD_EXT.patch new file mode 100644 index 000000000..5a8927002 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0202-ath11k-remove-unused-ATH11K_BD_IE_BOARD_EXT.patch @@ -0,0 +1,26 @@ +From 7fb376ad7d3f200575b9f9374e21b39d30b57267 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 21 Mar 2022 13:03:23 +0200 +Subject: [PATCH] ath11k: remove unused ATH11K_BD_IE_BOARD_EXT + +Currently ATH11K_BD_IE_BOARD_EXT is not used, so remove it. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220319023543.14288-2-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/hw.h | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -293,7 +293,6 @@ enum ath11k_bd_ie_board_type { + enum ath11k_bd_ie_type { + /* contains sub IEs of enum ath11k_bd_ie_board_type */ + ATH11K_BD_IE_BOARD = 0, +- ATH11K_BD_IE_BOARD_EXT = 1, + }; + + struct ath11k_hw_regs { diff --git a/package/kernel/mac80211/patches/ath11k/0203-ath11k-disable-regdb-support-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0203-ath11k-disable-regdb-support-for-QCA6390.patch new file mode 100644 index 000000000..174e99284 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0203-ath11k-disable-regdb-support-for-QCA6390.patch @@ -0,0 +1,28 @@ +From 0c104b6163e344e972dbbd255ca2441c171a8a87 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 21 Mar 2022 13:03:29 +0200 +Subject: [PATCH] ath11k: disable regdb support for QCA6390 + +Currently it does not have regdb files for QCA6390, so disable its regdb +support feature now. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-05266-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220319023543.14288-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -219,7 +219,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +- .supports_regdb = true, ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, diff --git a/package/kernel/mac80211/patches/ath11k/0204-ath11k-add-support-for-device-recovery-for-QCA6390-W.patch b/package/kernel/mac80211/patches/ath11k/0204-ath11k-add-support-for-device-recovery-for-QCA6390-W.patch new file mode 100644 index 000000000..ddca64a1c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0204-ath11k-add-support-for-device-recovery-for-QCA6390-W.patch @@ -0,0 +1,280 @@ +From 13da397f884d9c9a3fb6616206eeb6c6ab097287 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 28 Feb 2022 01:46:03 -0500 +Subject: [PATCH] ath11k: add support for device recovery for QCA6390/WCN6855 + +Currently ath11k has device recovery logic, it is introduced by this +patch "ath11k: Add support for subsystem recovery" which is upstream +by https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=ath11k-bringup&id=3a7b4838b6f6f234239f263ef3dc02e612a083ad. + +The patch is for AHB devices such as IPQ8074, it has remote proc module +which is used to download the firmware and boots the processor which +firmware is running on. If firmware crashed, remote proc module will +detect it and download and boot firmware again. Below command will +trigger a firmware crash, and then user can test feature of device +recovery. + +Test command: +echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash +echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash + +Unfortunately, QCA6390 is PCIe bus, it does not have the remote proc +module, it use mhi module to communicate between firmware and ath11k. +So ath11k does not support device recovery for QCA6390 currently. + +This patch is to add the extra logic which is different for QCA6390. +When firmware crashed, MHI_CB_EE_RDDM event will be indicate by +firmware and then ath11k_mhi_op_status_cb which is the callback of +mhi_controller will receive the MHI_CB_EE_RDDM event, then ath11k +will start to do recovery process, ath11k_core_reset() calls +ath11k_hif_power_down()/ath11k_hif_power_up(), then the mhi/ath11k +will start to download and boot firmware. There are some logic to +avoid deadloop recovery and two simultaneous recovery operations. +And because it has muti-radios for the soc, so it add some logic +in ath11k_mac_op_reconfig_complete() to make sure all radios has +reconfig complete and then complete the device recovery. + +Also it add workqueue_aux, because ab->workqueue is used when receive +ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue, +&ab->restart_work)), and ath11k_core_reset will wait for max +ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if +ath11k_core_reset also queued in ab->workqueue, then it will delay +restart_work of previous recovery and lead previous recovery fail. + +ath11k recovery success for QCA6390/WCN6855 after apply this patch. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220228064606.8981-2-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 68 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 13 +++++ + drivers/net/wireless/ath/ath11k/mac.c | 18 +++++++ + drivers/net/wireless/ath/ath11k/mhi.c | 33 +++++++++++++ + 4 files changed, 132 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1381,6 +1381,65 @@ static void ath11k_core_restart(struct w + complete(&ab->driver_recovery); + } + ++static void ath11k_core_reset(struct work_struct *work) ++{ ++ struct ath11k_base *ab = container_of(work, struct ath11k_base, reset_work); ++ int reset_count, fail_cont_count; ++ long time_left; ++ ++ if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))) { ++ ath11k_warn(ab, "ignore reset dev flags 0x%lx\n", ab->dev_flags); ++ return; ++ } ++ ++ /* Sometimes the recovery will fail and then the next all recovery fail, ++ * this is to avoid infinite recovery since it can not recovery success. ++ */ ++ fail_cont_count = atomic_read(&ab->fail_cont_count); ++ ++ if (fail_cont_count >= ATH11K_RESET_MAX_FAIL_COUNT_FINAL) ++ return; ++ ++ if (fail_cont_count >= ATH11K_RESET_MAX_FAIL_COUNT_FIRST && ++ time_before(jiffies, ab->reset_fail_timeout)) ++ return; ++ ++ reset_count = atomic_inc_return(&ab->reset_count); ++ ++ if (reset_count > 1) { ++ /* Sometimes it happened another reset worker before the previous one ++ * completed, then the second reset worker will destroy the previous one, ++ * thus below is to avoid that. ++ */ ++ ath11k_warn(ab, "already reseting count %d\n", reset_count); ++ ++ reinit_completion(&ab->reset_complete); ++ time_left = wait_for_completion_timeout(&ab->reset_complete, ++ ATH11K_RESET_TIMEOUT_HZ); ++ ++ if (time_left) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "to skip reset\n"); ++ atomic_dec(&ab->reset_count); ++ return; ++ } ++ ++ ab->reset_fail_timeout = jiffies + ATH11K_RESET_FAIL_TIMEOUT_HZ; ++ /* Record the continuous recovery fail count when recovery failed*/ ++ atomic_inc(&ab->fail_cont_count); ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset starting\n"); ++ ++ ab->is_reset = true; ++ atomic_set(&ab->recovery_count, 0); ++ ++ ath11k_hif_power_down(ab); ++ ath11k_qmi_free_resource(ab); ++ ath11k_hif_power_up(ab); ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n"); ++} ++ + static int ath11k_init_hw_params(struct ath11k_base *ab) + { + const struct ath11k_hw_params *hw_params = NULL; +@@ -1450,6 +1509,7 @@ EXPORT_SYMBOL(ath11k_core_deinit); + + void ath11k_core_free(struct ath11k_base *ab) + { ++ destroy_workqueue(ab->workqueue_aux); + destroy_workqueue(ab->workqueue); + + kfree(ab); +@@ -1472,9 +1532,14 @@ struct ath11k_base *ath11k_core_alloc(st + if (!ab->workqueue) + goto err_sc_free; + ++ ab->workqueue_aux = create_singlethread_workqueue("ath11k_aux_wq"); ++ if (!ab->workqueue_aux) ++ goto err_free_wq; ++ + mutex_init(&ab->core_lock); + spin_lock_init(&ab->base_lock); + mutex_init(&ab->vdev_id_11d_lock); ++ init_completion(&ab->reset_complete); + + INIT_LIST_HEAD(&ab->peers); + init_waitqueue_head(&ab->peer_mapping_wq); +@@ -1483,6 +1548,7 @@ struct ath11k_base *ath11k_core_alloc(st + INIT_WORK(&ab->restart_work, ath11k_core_restart); + INIT_WORK(&ab->update_11d_work, ath11k_update_11d); + INIT_WORK(&ab->rfkill_work, ath11k_rfkill_work); ++ INIT_WORK(&ab->reset_work, ath11k_core_reset); + timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); + init_completion(&ab->htc_suspend); + init_completion(&ab->wow.wakeup_completed); +@@ -1493,6 +1559,8 @@ struct ath11k_base *ath11k_core_alloc(st + + return ab; + ++err_free_wq: ++ destroy_workqueue(ab->workqueue); + err_sc_free: + kfree(ab); + return NULL; +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -40,6 +40,10 @@ + extern unsigned int ath11k_frame_mode; + + #define ATH11K_MON_TIMER_INTERVAL 10 ++#define ATH11K_RESET_TIMEOUT_HZ (20 * HZ) ++#define ATH11K_RESET_MAX_FAIL_COUNT_FIRST 3 ++#define ATH11K_RESET_MAX_FAIL_COUNT_FINAL 5 ++#define ATH11K_RESET_FAIL_TIMEOUT_HZ (20 * HZ) + + enum ath11k_supported_bw { + ATH11K_BW_20 = 0, +@@ -820,6 +824,15 @@ struct ath11k_base { + struct work_struct restart_work; + struct work_struct update_11d_work; + u8 new_alpha2[3]; ++ struct workqueue_struct *workqueue_aux; ++ struct work_struct reset_work; ++ atomic_t reset_count; ++ atomic_t recovery_count; ++ bool is_reset; ++ struct completion reset_complete; ++ /* continuous recovery fail count */ ++ atomic_t fail_cont_count; ++ unsigned long reset_fail_timeout; + struct { + /* protected by data_lock */ + u32 fw_crash_counter; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7915,6 +7915,8 @@ ath11k_mac_op_reconfig_complete(struct i + enum ieee80211_reconfig_type reconfig_type) + { + struct ath11k *ar = hw->priv; ++ struct ath11k_base *ab = ar->ab; ++ int recovery_count; + + if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) + return; +@@ -7926,6 +7928,22 @@ ath11k_mac_op_reconfig_complete(struct i + ar->pdev->pdev_id); + ar->state = ATH11K_STATE_ON; + ieee80211_wake_queues(ar->hw); ++ ++ if (ab->is_reset) { ++ recovery_count = atomic_inc_return(&ab->recovery_count); ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "recovery count %d\n", recovery_count); ++ /* When there are multiple radios in an SOC, ++ * the recovery has to be done for each radio ++ */ ++ if (recovery_count == ab->num_radios) { ++ atomic_dec(&ab->reset_count); ++ complete(&ab->reset_complete); ++ ab->is_reset = false; ++ atomic_set(&ab->fail_cont_count, 0); ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset success\n"); ++ } ++ } + } + + mutex_unlock(&ar->conf_mutex); +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -292,15 +292,48 @@ static void ath11k_mhi_op_runtime_put(st + { + } + ++static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason) ++{ ++ switch (reason) { ++ case MHI_CB_IDLE: ++ return "MHI_CB_IDLE"; ++ case MHI_CB_PENDING_DATA: ++ return "MHI_CB_PENDING_DATA"; ++ case MHI_CB_LPM_ENTER: ++ return "MHI_CB_LPM_ENTER"; ++ case MHI_CB_LPM_EXIT: ++ return "MHI_CB_LPM_EXIT"; ++ case MHI_CB_EE_RDDM: ++ return "MHI_CB_EE_RDDM"; ++ case MHI_CB_EE_MISSION_MODE: ++ return "MHI_CB_EE_MISSION_MODE"; ++ case MHI_CB_SYS_ERROR: ++ return "MHI_CB_SYS_ERROR"; ++ case MHI_CB_FATAL_ERROR: ++ return "MHI_CB_FATAL_ERROR"; ++ case MHI_CB_BW_REQ: ++ return "MHI_CB_BW_REQ"; ++ default: ++ return "UNKNOWN"; ++ } ++}; ++ + static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, + enum mhi_callback cb) + { + struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); + ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "mhi notify status reason %s\n", ++ ath11k_mhi_op_callback_to_str(cb)); ++ + switch (cb) { + case MHI_CB_SYS_ERROR: + ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n"); + break; ++ case MHI_CB_EE_RDDM: ++ if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))) ++ queue_work(ab->workqueue_aux, &ab->reset_work); ++ break; + default: + break; + } diff --git a/package/kernel/mac80211/patches/ath11k/0205-ath11k-add-synchronization-operation-between-reconfi.patch b/package/kernel/mac80211/patches/ath11k/0205-ath11k-add-synchronization-operation-between-reconfi.patch new file mode 100644 index 000000000..17e417339 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0205-ath11k-add-synchronization-operation-between-reconfi.patch @@ -0,0 +1,182 @@ +From 38194f3a605e4a961f28bc38a73a4f4d43123968 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 21 Mar 2022 13:16:57 +0200 +Subject: [PATCH] ath11k: add synchronization operation between reconfigure of + mac80211 and ath11k_base + +ieee80211_reconfig() of mac80211 is the main function for recovery of +each ieee80211_hw and ath11k, and ath11k_core_reconfigure_on_crash() +is the main function for recovery of ath11k_base, it has more than +one ieee80211_hw and ath11k for each ath11k_base, so it need to add +synchronization between them, otherwise it has many issue. + +For example, when ath11k_core_reconfigure_on_crash() is not complete, +mac80211 send a hw scan request to ath11k, it leads firmware crash, +because firmware has not been initialized at that moment, firmware +is only finished downloaded and loaded, it can not receive scan +command. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220228064606.8981-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 51 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/core.h | 5 +++ + drivers/net/wireless/ath/ath11k/mac.c | 22 +++++++++++ + 3 files changed, 70 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1302,12 +1302,11 @@ static void ath11k_update_11d(struct wor + } + } + +-static void ath11k_core_restart(struct work_struct *work) ++static void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab) + { +- struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); + struct ath11k *ar; + struct ath11k_pdev *pdev; +- int i, ret = 0; ++ int i; + + spin_lock_bh(&ab->base_lock); + ab->stats.fw_crash_counter++; +@@ -1340,12 +1339,13 @@ static void ath11k_core_restart(struct w + + wake_up(&ab->wmi_ab.tx_credits_wq); + wake_up(&ab->peer_mapping_wq); ++} + +- ret = ath11k_core_reconfigure_on_crash(ab); +- if (ret) { +- ath11k_err(ab, "failed to reconfigure driver on crash recovery\n"); +- return; +- } ++static void ath11k_core_post_reconfigure_recovery(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; +@@ -1381,6 +1381,27 @@ static void ath11k_core_restart(struct w + complete(&ab->driver_recovery); + } + ++static void ath11k_core_restart(struct work_struct *work) ++{ ++ struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); ++ int ret; ++ ++ if (!ab->is_reset) ++ ath11k_core_pre_reconfigure_recovery(ab); ++ ++ ret = ath11k_core_reconfigure_on_crash(ab); ++ if (ret) { ++ ath11k_err(ab, "failed to reconfigure driver on crash recovery\n"); ++ return; ++ } ++ ++ if (ab->is_reset) ++ complete_all(&ab->reconfigure_complete); ++ ++ if (!ab->is_reset) ++ ath11k_core_post_reconfigure_recovery(ab); ++} ++ + static void ath11k_core_reset(struct work_struct *work) + { + struct ath11k_base *ab = container_of(work, struct ath11k_base, reset_work); +@@ -1432,6 +1453,18 @@ static void ath11k_core_reset(struct wor + + ab->is_reset = true; + atomic_set(&ab->recovery_count, 0); ++ reinit_completion(&ab->recovery_start); ++ atomic_set(&ab->recovery_start_count, 0); ++ ++ ath11k_core_pre_reconfigure_recovery(ab); ++ ++ reinit_completion(&ab->reconfigure_complete); ++ ath11k_core_post_reconfigure_recovery(ab); ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "waiting recovery start...\n"); ++ ++ time_left = wait_for_completion_timeout(&ab->recovery_start, ++ ATH11K_RECOVER_START_TIMEOUT_HZ); + + ath11k_hif_power_down(ab); + ath11k_qmi_free_resource(ab); +@@ -1540,6 +1573,8 @@ struct ath11k_base *ath11k_core_alloc(st + spin_lock_init(&ab->base_lock); + mutex_init(&ab->vdev_id_11d_lock); + init_completion(&ab->reset_complete); ++ init_completion(&ab->reconfigure_complete); ++ init_completion(&ab->recovery_start); + + INIT_LIST_HEAD(&ab->peers); + init_waitqueue_head(&ab->peer_mapping_wq); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -44,6 +44,8 @@ extern unsigned int ath11k_frame_mode; + #define ATH11K_RESET_MAX_FAIL_COUNT_FIRST 3 + #define ATH11K_RESET_MAX_FAIL_COUNT_FINAL 5 + #define ATH11K_RESET_FAIL_TIMEOUT_HZ (20 * HZ) ++#define ATH11K_RECONFIGURE_TIMEOUT_HZ (10 * HZ) ++#define ATH11K_RECOVER_START_TIMEOUT_HZ (20 * HZ) + + enum ath11k_supported_bw { + ATH11K_BW_20 = 0, +@@ -828,8 +830,11 @@ struct ath11k_base { + struct work_struct reset_work; + atomic_t reset_count; + atomic_t recovery_count; ++ atomic_t recovery_start_count; + bool is_reset; + struct completion reset_complete; ++ struct completion reconfigure_complete; ++ struct completion recovery_start; + /* continuous recovery fail count */ + atomic_t fail_cont_count; + unsigned long reset_fail_timeout; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5749,6 +5749,27 @@ static int ath11k_mac_config_mon_status_ + return ret; + } + ++static void ath11k_mac_wait_reconfigure(struct ath11k_base *ab) ++{ ++ int recovery_start_count; ++ ++ if (!ab->is_reset) ++ return; ++ ++ recovery_start_count = atomic_inc_return(&ab->recovery_start_count); ++ ath11k_dbg(ab, ATH11K_DBG_MAC, "recovery start count %d\n", recovery_start_count); ++ ++ if (recovery_start_count == ab->num_radios) { ++ complete(&ab->recovery_start); ++ ath11k_dbg(ab, ATH11K_DBG_MAC, "recovery started success\n"); ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, "waiting reconfigure...\n"); ++ ++ wait_for_completion_timeout(&ab->reconfigure_complete, ++ ATH11K_RECONFIGURE_TIMEOUT_HZ); ++} ++ + static int ath11k_mac_op_start(struct ieee80211_hw *hw) + { + struct ath11k *ar = hw->priv; +@@ -5765,6 +5786,7 @@ static int ath11k_mac_op_start(struct ie + break; + case ATH11K_STATE_RESTARTING: + ar->state = ATH11K_STATE_RESTARTED; ++ ath11k_mac_wait_reconfigure(ab); + break; + case ATH11K_STATE_RESTARTED: + case ATH11K_STATE_WEDGED: diff --git a/package/kernel/mac80211/patches/ath11k/0206-ath11k-Add-hw-restart-option-to-simulate_fw_crash.patch b/package/kernel/mac80211/patches/ath11k/0206-ath11k-Add-hw-restart-option-to-simulate_fw_crash.patch new file mode 100644 index 000000000..886261d1d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0206-ath11k-Add-hw-restart-option-to-simulate_fw_crash.patch @@ -0,0 +1,36 @@ +From 78e3e6094220a71504e7136c42b49fc8ed3a72b4 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 21 Mar 2022 13:17:03 +0200 +Subject: [PATCH] ath11k: Add hw-restart option to simulate_fw_crash + +Add hw-restart to directly restart wlan. Like UTF mode start it will +restart hardware and download firmware again. + +Usage: +1. Run command: + echo hw-restart > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash + echo hw-restart > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash +2. wlan will be restart and do recovery process and success. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220228064606.8981-4-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -596,6 +596,10 @@ static ssize_t ath11k_write_simulate_fw_ + ret = ath11k_wmi_force_fw_hang_cmd(ar, + ATH11K_WMI_FW_HANG_ASSERT_TYPE, + ATH11K_WMI_FW_HANG_DELAY); ++ } else if (!strcmp(buf, "hw-restart")) { ++ ath11k_info(ab, "user requested hw restart\n"); ++ queue_work(ab->workqueue_aux, &ab->reset_work); ++ ret = 0; + } else { + ret = -EINVAL; + goto exit; diff --git a/package/kernel/mac80211/patches/ath11k/0207-ath11k-fix-the-warning-of-dev_wake-in-mhi_pm_disable.patch b/package/kernel/mac80211/patches/ath11k/0207-ath11k-fix-the-warning-of-dev_wake-in-mhi_pm_disable.patch new file mode 100644 index 000000000..b583cf74d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0207-ath11k-fix-the-warning-of-dev_wake-in-mhi_pm_disable.patch @@ -0,0 +1,124 @@ +From 0d7a8a6204ea9271f1d0a8c66a9fd2f54d2e3cbc Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 21 Mar 2022 13:17:08 +0200 +Subject: [PATCH] ath11k: fix the warning of dev_wake in + mhi_pm_disable_transition() + +When test device recovery with below command, it has warning in message +as below. +echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash +echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash + +warning message: +[ 1965.642121] ath11k_pci 0000:06:00.0: simulating firmware assert crash +[ 1968.471364] ieee80211 phy0: Hardware restart was requested +[ 1968.511305] ------------[ cut here ]------------ +[ 1968.511368] WARNING: CPU: 3 PID: 1546 at drivers/bus/mhi/core/pm.c:505 mhi_pm_disable_transition+0xb37/0xda0 [mhi] +[ 1968.511443] Modules linked in: ath11k_pci ath11k mac80211 libarc4 cfg80211 qmi_helpers qrtr_mhi mhi qrtr nvme nvme_core +[ 1968.511563] CPU: 3 PID: 1546 Comm: kworker/u17:0 Kdump: loaded Tainted: G W 5.17.0-rc3-wt-ath+ #579 +[ 1968.511629] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 1968.511704] Workqueue: mhi_hiprio_wq mhi_pm_st_worker [mhi] +[ 1968.511787] RIP: 0010:mhi_pm_disable_transition+0xb37/0xda0 [mhi] +[ 1968.511870] Code: a9 fe ff ff 4c 89 ff 44 89 04 24 e8 03 46 f6 e5 44 8b 04 24 41 83 f8 01 0f 84 21 fe ff ff e9 4c fd ff ff 0f 0b e9 af f8 ff ff <0f> 0b e9 5c f8 ff ff 48 89 df e8 da 9e ee e3 e9 12 fd ff ff 4c 89 +[ 1968.511923] RSP: 0018:ffffc900024efbf0 EFLAGS: 00010286 +[ 1968.511969] RAX: 00000000ffffffff RBX: ffff88811d241250 RCX: ffffffffc0176922 +[ 1968.512014] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff888118a90a24 +[ 1968.512059] RBP: ffff888118a90800 R08: 0000000000000000 R09: ffff888118a90a27 +[ 1968.512102] R10: ffffed1023152144 R11: 0000000000000001 R12: ffff888118a908ac +[ 1968.512229] R13: ffff888118a90928 R14: dffffc0000000000 R15: ffff888118a90a24 +[ 1968.512310] FS: 0000000000000000(0000) GS:ffff888234200000(0000) knlGS:0000000000000000 +[ 1968.512405] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 1968.512493] CR2: 00007f5538f443a8 CR3: 000000016dc28001 CR4: 00000000003706e0 +[ 1968.512587] Call Trace: +[ 1968.512672] +[ 1968.512751] ? _raw_spin_unlock_irq+0x1f/0x40 +[ 1968.512859] mhi_pm_st_worker+0x3ac/0x790 [mhi] +[ 1968.512959] ? mhi_pm_mission_mode_transition.isra.0+0x7d0/0x7d0 [mhi] +[ 1968.513063] process_one_work+0x86a/0x1400 +[ 1968.513184] ? pwq_dec_nr_in_flight+0x230/0x230 +[ 1968.513312] ? move_linked_works+0x125/0x290 +[ 1968.513416] worker_thread+0x6db/0xf60 +[ 1968.513536] ? process_one_work+0x1400/0x1400 +[ 1968.513627] kthread+0x241/0x2d0 +[ 1968.513733] ? kthread_complete_and_exit+0x20/0x20 +[ 1968.513821] ret_from_fork+0x22/0x30 +[ 1968.513924] + +Reason is mhi_deassert_dev_wake() from mhi_device_put() is called +but mhi_assert_dev_wake() from __mhi_device_get_sync() is not called +in progress of recovery. Commit 8e0559921f9a ("bus: mhi: core: +Skip device wake in error or shutdown state") add check for the +pm_state of mhi in __mhi_device_get_sync(), and the pm_state is not +the normal state untill recovery is completed, so it leads the +dev_wake is not 0 and above warning print in mhi_pm_disable_transition() +while checking mhi_cntrl->dev_wake. + +Add check in ath11k_pci_write32()/ath11k_pci_read32() to skip call +mhi_device_put() if mhi_device_get_sync() does not really do wake, +then the warning gone. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220228064606.8981-5-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/pci.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -191,6 +191,7 @@ void ath11k_pci_write32(struct ath11k_ba + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 window_start; ++ int ret = 0; + + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. +@@ -198,7 +199,7 @@ void ath11k_pci_write32(struct ath11k_ba + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) +- mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++ ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + + if (offset < WINDOW_START) { + iowrite32(value, ab->mem + offset); +@@ -222,7 +223,8 @@ void ath11k_pci_write32(struct ath11k_ba + + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ACCESS_ALWAYS_OFF) ++ offset >= ACCESS_ALWAYS_OFF && ++ !ret) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + } + +@@ -230,6 +232,7 @@ u32 ath11k_pci_read32(struct ath11k_base + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 val, window_start; ++ int ret = 0; + + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. +@@ -237,7 +240,7 @@ u32 ath11k_pci_read32(struct ath11k_base + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) +- mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++ ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + + if (offset < WINDOW_START) { + val = ioread32(ab->mem + offset); +@@ -261,7 +264,8 @@ u32 ath11k_pci_read32(struct ath11k_base + + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ACCESS_ALWAYS_OFF) ++ offset >= ACCESS_ALWAYS_OFF && ++ !ret) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + + return val; diff --git a/package/kernel/mac80211/patches/ath11k/0208-ath11k-enable-PLATFORM_CAP_PCIE_GLOBAL_RESET-QMI-hos.patch b/package/kernel/mac80211/patches/ath11k/0208-ath11k-enable-PLATFORM_CAP_PCIE_GLOBAL_RESET-QMI-hos.patch new file mode 100644 index 000000000..a48141722 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0208-ath11k-enable-PLATFORM_CAP_PCIE_GLOBAL_RESET-QMI-hos.patch @@ -0,0 +1,115 @@ +From 1e4ac7173c9394de7f54a4a861377ac3f030c614 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 13:56:02 +0800 +Subject: [PATCH] ath11k: enable PLATFORM_CAP_PCIE_GLOBAL_RESET QMI host + capability + +In Qualcomm ARM platforms there is WL_EN pin and other power regulators +which can be controlled at platform side to completely reset the chip. +For most of x86 and other platforms, the chip is connected via PCIe M.2 +interface, and there is no way to control WL_EN pin. Instead the host +driver needs to reset the chip via PCIE_SOC_GLOBAL_RESET hardware +register, just like ath11k does currently. + +But when using PCIE_SOC_GLOBAL_RESET there are some hardware registers +which are not cleared/restored. To handle those cases we can enable +PLATFORM_CAP_PCIE_GLOBAL_RESET QMI host capability to tell the firmware +to do some platform specific operations after firmware download. + +This does not fix any known issues, but is recommended by the firmware +team, so enable the capability on QCA6390 and WCN6855 PCI devices. It is +currently unclear if this should be enabled also on QCN9074, so leave it +disabled for now. On AHB devices this is not needed as they don't use +PCIE_SOC_GLOBAL_RESET. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211011055602.77342-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 6 ++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++++ + 3 files changed, 11 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -100,6 +100,7 @@ static const struct ath11k_hw_params ath + .fw_wmi_diag_event = false, + .current_cc_support = false, + .dbr_debug_support = true, ++ .global_reset = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -166,6 +167,7 @@ static const struct ath11k_hw_params ath + .fw_wmi_diag_event = false, + .current_cc_support = false, + .dbr_debug_support = true, ++ .global_reset = false, + }, + { + .name = "qca6390 hw2.0", +@@ -231,6 +233,7 @@ static const struct ath11k_hw_params ath + .fw_wmi_diag_event = true, + .current_cc_support = true, + .dbr_debug_support = false, ++ .global_reset = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -296,6 +299,7 @@ static const struct ath11k_hw_params ath + .fw_wmi_diag_event = false, + .current_cc_support = false, + .dbr_debug_support = true, ++ .global_reset = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -361,6 +365,7 @@ static const struct ath11k_hw_params ath + .fw_wmi_diag_event = true, + .current_cc_support = true, + .dbr_debug_support = false, ++ .global_reset = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -425,6 +430,7 @@ static const struct ath11k_hw_params ath + .fw_wmi_diag_event = true, + .current_cc_support = true, + .dbr_debug_support = false, ++ .global_reset = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -194,6 +194,7 @@ struct ath11k_hw_params { + bool fw_wmi_diag_event; + bool current_cc_support; + bool dbr_debug_support; ++ bool global_reset; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -15,6 +15,7 @@ + + #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 + #define HOST_CSTATE_BIT 0x04 ++#define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08 + + #define FW_BUILD_ID_MASK "QC_IMAGE_VERSION_STRING=" + +@@ -1676,6 +1677,9 @@ static int ath11k_qmi_host_cap_send(stru + req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT; + } + ++ if (ab->hw_params.global_reset) ++ req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET; ++ + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi host cap request\n"); + + ret = qmi_txn_init(&ab->qmi.handle, &txn, diff --git a/package/kernel/mac80211/patches/ath11k/0209-ath11k-add-fallback-board-name-without-variant-while.patch b/package/kernel/mac80211/patches/ath11k/0209-ath11k-add-fallback-board-name-without-variant-while.patch new file mode 100644 index 000000000..67377e793 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0209-ath11k-add-fallback-board-name-without-variant-while.patch @@ -0,0 +1,159 @@ +From 62abdc06c50eb18e3fa62f7136e66842a96f6b58 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 23 Mar 2022 11:14:16 +0200 +Subject: [PATCH] ath11k: add fallback board name without variant while + searching board-2.bin + +Sometimes it has a variant value which read from DT or SMBIOS by +ath11k, and meanwhile it does not have the matched board name in +board-2.bin, then it will failed at boot up phase. + +Add fallback board name which removed variant value and search again +in board-2.bin when failed with variant and try to load the board +data again to increase boot up success rate. + +dmesg log after this patch: +[169547.248472] ath11k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262,variant=test' +[169547.248565] ath11k_pci 0000:05:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 180324 +[169547.248568] ath11k_pci 0000:05:00.0: board name +[169547.248570] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[169547.248571] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[169547.248572] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[169547.248574] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[169547.248575] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[169547.248576] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo +[169547.248577] ath11k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 +[169547.248578] ath11k_pci 0000:05:00.0: board name +[169547.248579] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[169547.248581] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[169547.248582] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[169547.248583] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[169547.248584] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[169547.248585] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo +[169547.248587] ath11k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 ard-id=266 +[169547.248588] ath11k_pci 0000:05:00.0: board name +[169547.248589] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[169547.248590] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[169547.248591] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[169547.248592] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[169547.248594] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[169547.248595] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 31 38 2c 71 6d 69 2d 62 chip-id=18,qmi-b +[169547.248596] ath11k_pci 0000:05:00.0: 00000060: 6f 61 72 64 2d 69 64 3d 32 36 36 oard-id=266 +[169547.248597] ath11k_pci 0000:05:00.0: failed to fetch board data for bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262,variant=test from ath11k/WCN6855/hw2.0/board-2.bin +[169547.248476] ath11k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' +[169547.248634] ath11k_pci 0000:05:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 180324 +[169547.248636] ath11k_pci 0000:05:00.0: board name +[169547.248637] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[169547.248638] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[169547.248639] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[169547.248641] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[169547.248642] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[169547.248643] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo +[169547.248645] ath11k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 +[169547.248646] ath11k_pci 0000:05:00.0: boot found match for name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' +[169547.248647] ath11k_pci 0000:05:00.0: boot found board data for 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' +[169547.248649] ath11k_pci 0000:05:00.0: using board api 2 + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220315104721.26649-2-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 48 ++++++++++++++++++++++---- + 1 file changed, 41 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -571,13 +571,13 @@ int ath11k_core_check_dt(struct ath11k_b + return 0; + } + +-static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, +- size_t name_len) ++static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, ++ size_t name_len, bool with_variant) + { + /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ + char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; + +- if (ab->qmi.target.bdf_ext[0] != '\0') ++ if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') + scnprintf(variant, sizeof(variant), ",variant=%s", + ab->qmi.target.bdf_ext); + +@@ -607,6 +607,18 @@ static int ath11k_core_create_board_name + return 0; + } + ++static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, ++ size_t name_len) ++{ ++ return __ath11k_core_create_board_name(ab, name, name_len, true); ++} ++ ++static int ath11k_core_create_fallback_board_name(struct ath11k_base *ab, char *name, ++ size_t name_len) ++{ ++ return __ath11k_core_create_board_name(ab, name, name_len, false); ++} ++ + const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, + const char *file) + { +@@ -810,7 +822,7 @@ static int ath11k_core_fetch_board_data_ + + out: + if (!bd->data || !bd->len) { +- ath11k_err(ab, ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, + "failed to fetch board data for %s from %s\n", + boardname, filepath); + ret = -ENODATA; +@@ -842,10 +854,13 @@ int ath11k_core_fetch_board_data_api_1(s + #define BOARD_NAME_SIZE 200 + int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd) + { +- char boardname[BOARD_NAME_SIZE]; ++ char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE]; ++ char *filename, filepath[100]; + int ret; + +- ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); ++ filename = ATH11K_BOARD_API2_FILE; ++ ++ ret = ath11k_core_create_board_name(ab, boardname, sizeof(boardname)); + if (ret) { + ath11k_err(ab, "failed to create board name: %d", ret); + return ret; +@@ -856,10 +871,29 @@ int ath11k_core_fetch_bdf(struct ath11k_ + if (!ret) + goto success; + ++ ret = ath11k_core_create_fallback_board_name(ab, fallback_boardname, ++ sizeof(fallback_boardname)); ++ if (ret) { ++ ath11k_err(ab, "failed to create fallback board name: %d", ret); ++ return ret; ++ } ++ ++ ret = ath11k_core_fetch_board_data_api_n(ab, bd, fallback_boardname); ++ if (!ret) ++ goto success; ++ + ab->bd_api = 1; + ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_DEFAULT_BOARD_FILE); + if (ret) { +- ath11k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n", ++ ath11k_core_create_firmware_path(ab, filename, ++ filepath, sizeof(filepath)); ++ ath11k_err(ab, "failed to fetch board data for %s from %s\n", ++ boardname, filepath); ++ if (memcmp(boardname, fallback_boardname, strlen(boardname))) ++ ath11k_err(ab, "failed to fetch board data for %s from %s\n", ++ fallback_boardname, filepath); ++ ++ ath11k_err(ab, "failed to fetch board.bin from %s\n", + ab->hw_params.fw.dir); + return ret; + } diff --git a/package/kernel/mac80211/patches/ath11k/0210-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch b/package/kernel/mac80211/patches/ath11k/0210-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch new file mode 100644 index 000000000..86e52113e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0210-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch @@ -0,0 +1,169 @@ +From 9d97114d222047c0699bbdbf8f128907f423bbe6 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 23 Mar 2022 11:14:17 +0200 +Subject: [PATCH] ath11k: add read variant from SMBIOS for download board data + +This is to read variant from SMBIOS such as read from DT, the variant +string will be used to one part of string which used to search board +data from board-2.bin. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220315104721.26649-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 70 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 20 +++++++- + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++ + 3 files changed, 93 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++ + #include "core.h" + #include "dp_tx.h" + #include "dp_rx.h" +@@ -548,6 +549,75 @@ int ath11k_core_resume(struct ath11k_bas + } + EXPORT_SYMBOL(ath11k_core_resume); + ++static void ath11k_core_check_bdfext(const struct dmi_header *hdr, void *data) ++{ ++ struct ath11k_base *ab = data; ++ const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC; ++ struct ath11k_smbios_bdf *smbios = (struct ath11k_smbios_bdf *)hdr; ++ ssize_t copied; ++ size_t len; ++ int i; ++ ++ if (ab->qmi.target.bdf_ext[0] != '\0') ++ return; ++ ++ if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE) ++ return; ++ ++ if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "wrong smbios bdf ext type length (%d).\n", ++ hdr->length); ++ return; ++ } ++ ++ if (!smbios->bdf_enabled) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n"); ++ return; ++ } ++ ++ /* Only one string exists (per spec) */ ++ if (memcmp(smbios->bdf_ext, magic, strlen(magic)) != 0) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant magic does not match.\n"); ++ return; ++ } ++ ++ len = min_t(size_t, ++ strlen(smbios->bdf_ext), sizeof(ab->qmi.target.bdf_ext)); ++ for (i = 0; i < len; i++) { ++ if (!isascii(smbios->bdf_ext[i]) || !isprint(smbios->bdf_ext[i])) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant name contains non ascii chars.\n"); ++ return; ++ } ++ } ++ ++ /* Copy extension name without magic prefix */ ++ copied = strscpy(ab->qmi.target.bdf_ext, smbios->bdf_ext + strlen(magic), ++ sizeof(ab->qmi.target.bdf_ext)); ++ if (copied < 0) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant string is longer than the buffer can accommodate\n"); ++ return; ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "found and validated bdf variant smbios_type 0x%x bdf %s\n", ++ ATH11K_SMBIOS_BDF_EXT_TYPE, ab->qmi.target.bdf_ext); ++} ++ ++int ath11k_core_check_smbios(struct ath11k_base *ab) ++{ ++ ab->qmi.target.bdf_ext[0] = '\0'; ++ dmi_walk(ath11k_core_check_bdfext, ab); ++ ++ if (ab->qmi.target.bdf_ext[0] == '\0') ++ return -ENODATA; ++ ++ return 0; ++} ++ + int ath11k_core_check_dt(struct ath11k_base *ab) + { + size_t max_len = sizeof(ab->qmi.target.bdf_ext); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + #include "qmi.h" + #include "htc.h" + #include "wmi.h" +@@ -37,6 +39,15 @@ + #define ATH11K_INVALID_HW_MAC_ID 0xFF + #define ATH11K_CONNECTION_LOSS_HZ (3 * HZ) + ++/* SMBIOS type containing Board Data File Name Extension */ ++#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8 ++ ++/* SMBIOS type structure length (excluding strings-set) */ ++#define ATH11K_SMBIOS_BDF_EXT_LENGTH 0x9 ++ ++/* The magic used by QCA spec */ ++#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_" ++ + extern unsigned int ath11k_frame_mode; + + #define ATH11K_MON_TIMER_INTERVAL 10 +@@ -154,6 +165,13 @@ struct ath11k_ext_irq_grp { + struct net_device napi_ndev; + }; + ++struct ath11k_smbios_bdf { ++ struct dmi_header hdr; ++ u32 padding; ++ u8 bdf_enabled; ++ u8 bdf_ext[]; ++}; ++ + #define HEHANDLE_CAP_PHYINFO_SIZE 3 + #define HECAP_PHYINFO_SIZE 9 + #define HECAP_MACINFO_SIZE 5 +@@ -1046,7 +1064,7 @@ int ath11k_core_fetch_board_data_api_1(s + const char *name); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); +- ++int ath11k_core_check_smbios(struct ath11k_base *ab); + void ath11k_core_halt(struct ath11k *ar); + int ath11k_core_resume(struct ath11k_base *ab); + int ath11k_core_suspend(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2095,6 +2095,10 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.fw_build_timestamp, + fw_build_id); + ++ r = ath11k_core_check_smbios(ab); ++ if (r) ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "SMBIOS bdf variant name not set.\n"); ++ + r = ath11k_core_check_dt(ab); + if (r) + ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0211-ath11k-Add-peer-rhash-table-support.patch b/package/kernel/mac80211/patches/ath11k/0211-ath11k-Add-peer-rhash-table-support.patch new file mode 100644 index 000000000..ffaecc1ae --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0211-ath11k-Add-peer-rhash-table-support.patch @@ -0,0 +1,678 @@ +From 7b0c70d92a435913f6e11d6a248b935697e8a3eb Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 23 Mar 2022 11:14:17 +0200 +Subject: [PATCH] ath11k: Add peer rhash table support + +When more clients (128) are connected, the UL data traffic +KPI measurement is low compared to single client. This issue +is due to more CPU cycles spent on the peer lookup operation +with more clients. So reduce the peer lookup operation by +modifying the linear based lookup operation into the rhash +based lookup operation. This improve the peak throughput +measurement. Since this is a software algorithm change, it is +applicable for all the platforms. + +TCP UL 128 Clients test case Observation (64bit system): +Previous: ~550 Mbps +Now : ~860 Mbps + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01067-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644036628-5334-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 3 +- + drivers/net/wireless/ath/ath11k/core.h | 14 + + drivers/net/wireless/ath/ath11k/mac.c | 16 +- + drivers/net/wireless/ath/ath11k/peer.c | 344 +++++++++++++++++++++++-- + drivers/net/wireless/ath/ath11k/peer.h | 10 +- + 5 files changed, 363 insertions(+), 24 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -1680,6 +1680,7 @@ struct ath11k_base *ath11k_core_alloc(st + goto err_free_wq; + + mutex_init(&ab->core_lock); ++ mutex_init(&ab->tbl_mtx_lock); + spin_lock_init(&ab->base_lock); + mutex_init(&ab->vdev_id_11d_lock); + init_completion(&ab->reset_complete); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: BSD-3-Clause-Clear */ + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #ifndef ATH11K_CORE_H +@@ -12,6 +13,7 @@ + #include + #include + #include ++#include + #include "qmi.h" + #include "htc.h" + #include "wmi.h" +@@ -803,6 +805,18 @@ struct ath11k_base { + struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS]; + struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS]; + unsigned long long free_vdev_map; ++ ++ /* To synchronize rhash tbl write operation */ ++ struct mutex tbl_mtx_lock; ++ ++ /* The rhashtable containing struct ath11k_peer keyed by mac addr */ ++ struct rhashtable *rhead_peer_addr; ++ struct rhashtable_params rhash_peer_addr_param; ++ ++ /* The rhashtable containing struct ath11k_peer keyed by id */ ++ struct rhashtable *rhead_peer_id; ++ struct rhashtable_params rhash_peer_id_param; ++ + struct list_head peers; + wait_queue_head_t peer_mapping_wq; + u8 mac_addr[ETH_ALEN]; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -875,13 +875,16 @@ void ath11k_mac_peer_cleanup_all(struct + + lockdep_assert_held(&ar->conf_mutex); + ++ mutex_lock(&ab->tbl_mtx_lock); + spin_lock_bh(&ab->base_lock); + list_for_each_entry_safe(peer, tmp, &ab->peers, list) { + ath11k_peer_rx_tid_cleanup(ar, peer); ++ ath11k_peer_rhash_delete(ab, peer); + list_del(&peer->list); + kfree(peer); + } + spin_unlock_bh(&ab->base_lock); ++ mutex_unlock(&ab->tbl_mtx_lock); + + ar->num_peers = 0; + ar->num_stations = 0; +@@ -4554,6 +4557,7 @@ static int ath11k_mac_op_sta_state(struc + } + + ath11k_mac_dec_num_stations(arvif, sta); ++ mutex_lock(&ar->ab->tbl_mtx_lock); + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); + if (skip_peer_delete && peer) { +@@ -4561,12 +4565,14 @@ static int ath11k_mac_op_sta_state(struc + } else if (peer && peer->sta == sta) { + ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", + vif->addr, arvif->vdev_id); ++ ath11k_peer_rhash_delete(ar->ab, peer); + peer->sta = NULL; + list_del(&peer->list); + kfree(peer); + ar->num_peers--; + } + spin_unlock_bh(&ar->ab->base_lock); ++ mutex_unlock(&ar->ab->tbl_mtx_lock); + + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; +@@ -8574,6 +8580,8 @@ void ath11k_mac_unregister(struct ath11k + + __ath11k_mac_unregister(ar); + } ++ ++ ath11k_peer_rhash_tbl_destroy(ab); + } + + static int __ath11k_mac_register(struct ath11k *ar) +@@ -8802,6 +8810,10 @@ int ath11k_mac_register(struct ath11k_ba + ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; + ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; + ++ ret = ath11k_peer_rhash_tbl_init(ab); ++ if (ret) ++ return ret; ++ + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; +@@ -8831,6 +8843,8 @@ err_cleanup: + __ath11k_mac_unregister(ar); + } + ++ ath11k_peer_rhash_tbl_destroy(ab); ++ + return ret; + } + +--- a/drivers/net/wireless/ath/ath11k/peer.c ++++ b/drivers/net/wireless/ath/ath11k/peer.c +@@ -1,23 +1,22 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include "core.h" + #include "peer.h" + #include "debug.h" + +-struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id, +- const u8 *addr) ++static struct ath11k_peer *ath11k_peer_find_list_by_id(struct ath11k_base *ab, ++ int peer_id) + { + struct ath11k_peer *peer; + + lockdep_assert_held(&ab->base_lock); + + list_for_each_entry(peer, &ab->peers, list) { +- if (peer->vdev_id != vdev_id) +- continue; +- if (!ether_addr_equal(peer->addr, addr)) ++ if (peer->peer_id != peer_id) + continue; + + return peer; +@@ -26,15 +25,15 @@ struct ath11k_peer *ath11k_peer_find(str + return NULL; + } + +-static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab, +- u8 pdev_idx, const u8 *addr) ++struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id, ++ const u8 *addr) + { + struct ath11k_peer *peer; + + lockdep_assert_held(&ab->base_lock); + + list_for_each_entry(peer, &ab->peers, list) { +- if (peer->pdev_idx != pdev_idx) ++ if (peer->vdev_id != vdev_id) + continue; + if (!ether_addr_equal(peer->addr, addr)) + continue; +@@ -52,14 +51,13 @@ struct ath11k_peer *ath11k_peer_find_by_ + + lockdep_assert_held(&ab->base_lock); + +- list_for_each_entry(peer, &ab->peers, list) { +- if (!ether_addr_equal(peer->addr, addr)) +- continue; ++ if (!ab->rhead_peer_addr) ++ return NULL; + +- return peer; +- } ++ peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr, ++ ab->rhash_peer_addr_param); + +- return NULL; ++ return peer; + } + + struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, +@@ -69,11 +67,13 @@ struct ath11k_peer *ath11k_peer_find_by_ + + lockdep_assert_held(&ab->base_lock); + +- list_for_each_entry(peer, &ab->peers, list) +- if (peer_id == peer->peer_id) +- return peer; ++ if (!ab->rhead_peer_id) ++ return NULL; + +- return NULL; ++ peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id, ++ ab->rhash_peer_id_param); ++ ++ return peer; + } + + struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab, +@@ -99,7 +99,7 @@ void ath11k_peer_unmap_event(struct ath1 + + spin_lock_bh(&ab->base_lock); + +- peer = ath11k_peer_find_by_id(ab, peer_id); ++ peer = ath11k_peer_find_list_by_id(ab, peer_id); + if (!peer) { + ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n", + peer_id); +@@ -167,6 +167,76 @@ static int ath11k_wait_for_peer_common(s + return 0; + } + ++static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab, ++ struct rhashtable *rtbl, ++ struct rhash_head *rhead, ++ struct rhashtable_params *params, ++ void *key) ++{ ++ struct ath11k_peer *tmp; ++ ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params); ++ ++ if (!tmp) ++ return 0; ++ else if (IS_ERR(tmp)) ++ return PTR_ERR(tmp); ++ else ++ return -EEXIST; ++} ++ ++static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab, ++ struct rhashtable *rtbl, ++ struct rhash_head *rhead, ++ struct rhashtable_params *params) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ ret = rhashtable_remove_fast(rtbl, rhead, *params); ++ if (ret && ret != -ENOENT) ++ return ret; ++ ++ return 0; ++} ++ ++static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ab->base_lock); ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ if (!ab->rhead_peer_id || !ab->rhead_peer_addr) ++ return -EPERM; ++ ++ ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id, ++ &ab->rhash_peer_id_param, &peer->peer_id); ++ if (ret) { ++ ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n", ++ peer->addr, peer->peer_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr, ++ &ab->rhash_peer_addr_param, &peer->addr); ++ if (ret) { ++ ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n", ++ peer->addr, peer->peer_id, ret); ++ goto err_clean; ++ } ++ ++ return 0; ++ ++err_clean: ++ ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id, ++ &ab->rhash_peer_id_param); ++ return ret; ++} ++ + void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id) + { + struct ath11k_peer *peer, *tmp; +@@ -174,6 +244,7 @@ void ath11k_peer_cleanup(struct ath11k * + + lockdep_assert_held(&ar->conf_mutex); + ++ mutex_lock(&ab->tbl_mtx_lock); + spin_lock_bh(&ab->base_lock); + list_for_each_entry_safe(peer, tmp, &ab->peers, list) { + if (peer->vdev_id != vdev_id) +@@ -182,12 +253,14 @@ void ath11k_peer_cleanup(struct ath11k * + ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n", + peer->addr, vdev_id); + ++ ath11k_peer_rhash_delete(ab, peer); + list_del(&peer->list); + kfree(peer); + ar->num_peers--; + } + + spin_unlock_bh(&ab->base_lock); ++ mutex_unlock(&ab->tbl_mtx_lock); + } + + static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr) +@@ -220,14 +293,35 @@ int ath11k_wait_for_peer_delete_done(str + static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr) + { + int ret; ++ struct ath11k_peer *peer; ++ struct ath11k_base *ab = ar->ab; + + lockdep_assert_held(&ar->conf_mutex); + ++ mutex_lock(&ab->tbl_mtx_lock); ++ spin_lock_bh(&ab->base_lock); ++ ++ peer = ath11k_peer_find_by_addr(ab, addr); ++ if (!peer) { ++ spin_unlock_bh(&ab->base_lock); ++ mutex_unlock(&ab->tbl_mtx_lock); ++ ++ ath11k_warn(ab, ++ "failed to find peer vdev_id %d addr %pM in delete\n", ++ vdev_id, addr); ++ return -EINVAL; ++ } ++ ++ ath11k_peer_rhash_delete(ab, peer); ++ ++ spin_unlock_bh(&ab->base_lock); ++ mutex_unlock(&ab->tbl_mtx_lock); ++ + reinit_completion(&ar->peer_delete_done); + + ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id); + if (ret) { +- ath11k_warn(ar->ab, ++ ath11k_warn(ab, + "failed to delete peer vdev_id %d addr %pM ret %d\n", + vdev_id, addr, ret); + return ret; +@@ -276,7 +370,7 @@ int ath11k_peer_create(struct ath11k *ar + } + + spin_lock_bh(&ar->ab->base_lock); +- peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr); ++ peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr); + if (peer) { + spin_unlock_bh(&ar->ab->base_lock); + return -EINVAL; +@@ -296,11 +390,13 @@ int ath11k_peer_create(struct ath11k *ar + if (ret) + return ret; + ++ mutex_lock(&ar->ab->tbl_mtx_lock); + spin_lock_bh(&ar->ab->base_lock); + + peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr); + if (!peer) { + spin_unlock_bh(&ar->ab->base_lock); ++ mutex_unlock(&ar->ab->tbl_mtx_lock); + ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n", + param->peer_addr, param->vdev_id); + +@@ -308,6 +404,13 @@ int ath11k_peer_create(struct ath11k *ar + goto cleanup; + } + ++ ret = ath11k_peer_rhash_add(ar->ab, peer); ++ if (ret) { ++ spin_unlock_bh(&ar->ab->base_lock); ++ mutex_unlock(&ar->ab->tbl_mtx_lock); ++ goto cleanup; ++ } ++ + peer->pdev_idx = ar->pdev_idx; + peer->sta = sta; + +@@ -332,6 +435,7 @@ int ath11k_peer_create(struct ath11k *ar + ar->num_peers++; + + spin_unlock_bh(&ar->ab->base_lock); ++ mutex_unlock(&ar->ab->tbl_mtx_lock); + + return 0; + +@@ -343,3 +447,201 @@ cleanup: + + return ret; + } ++ ++int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ab->base_lock); ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ if (!ab->rhead_peer_id || !ab->rhead_peer_addr) ++ return -EPERM; ++ ++ ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr, ++ &ab->rhash_peer_addr_param); ++ if (ret) { ++ ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n", ++ peer->addr, peer->peer_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id, ++ &ab->rhash_peer_id_param); ++ if (ret) { ++ ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n", ++ peer->addr, peer->peer_id, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab) ++{ ++ struct rhashtable_params *param; ++ struct rhashtable *rhash_id_tbl; ++ int ret; ++ size_t size; ++ ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ if (ab->rhead_peer_id) ++ return 0; ++ ++ size = sizeof(*ab->rhead_peer_id); ++ rhash_id_tbl = kzalloc(size, GFP_KERNEL); ++ if (!rhash_id_tbl) { ++ ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n", ++ size); ++ return -ENOMEM; ++ } ++ ++ param = &ab->rhash_peer_id_param; ++ ++ param->key_offset = offsetof(struct ath11k_peer, peer_id); ++ param->head_offset = offsetof(struct ath11k_peer, rhash_id); ++ param->key_len = sizeof_field(struct ath11k_peer, peer_id); ++ param->automatic_shrinking = true; ++ param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab); ++ ++ ret = rhashtable_init(rhash_id_tbl, param); ++ if (ret) { ++ ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret); ++ goto err_free; ++ } ++ ++ spin_lock_bh(&ab->base_lock); ++ ++ if (!ab->rhead_peer_id) { ++ ab->rhead_peer_id = rhash_id_tbl; ++ } else { ++ spin_unlock_bh(&ab->base_lock); ++ goto cleanup_tbl; ++ } ++ ++ spin_unlock_bh(&ab->base_lock); ++ ++ return 0; ++ ++cleanup_tbl: ++ rhashtable_destroy(rhash_id_tbl); ++err_free: ++ kfree(rhash_id_tbl); ++ ++ return ret; ++} ++ ++static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab) ++{ ++ struct rhashtable_params *param; ++ struct rhashtable *rhash_addr_tbl; ++ int ret; ++ size_t size; ++ ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ if (ab->rhead_peer_addr) ++ return 0; ++ ++ size = sizeof(*ab->rhead_peer_addr); ++ rhash_addr_tbl = kzalloc(size, GFP_KERNEL); ++ if (!rhash_addr_tbl) { ++ ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n", ++ size); ++ return -ENOMEM; ++ } ++ ++ param = &ab->rhash_peer_addr_param; ++ ++ param->key_offset = offsetof(struct ath11k_peer, addr); ++ param->head_offset = offsetof(struct ath11k_peer, rhash_addr); ++ param->key_len = sizeof_field(struct ath11k_peer, addr); ++ param->automatic_shrinking = true; ++ param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab); ++ ++ ret = rhashtable_init(rhash_addr_tbl, param); ++ if (ret) { ++ ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret); ++ goto err_free; ++ } ++ ++ spin_lock_bh(&ab->base_lock); ++ ++ if (!ab->rhead_peer_addr) { ++ ab->rhead_peer_addr = rhash_addr_tbl; ++ } else { ++ spin_unlock_bh(&ab->base_lock); ++ goto cleanup_tbl; ++ } ++ ++ spin_unlock_bh(&ab->base_lock); ++ ++ return 0; ++ ++cleanup_tbl: ++ rhashtable_destroy(rhash_addr_tbl); ++err_free: ++ kfree(rhash_addr_tbl); ++ ++ return ret; ++} ++ ++static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab) ++{ ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ if (!ab->rhead_peer_id) ++ return; ++ ++ rhashtable_destroy(ab->rhead_peer_id); ++ kfree(ab->rhead_peer_id); ++ ab->rhead_peer_id = NULL; ++} ++ ++static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab) ++{ ++ lockdep_assert_held(&ab->tbl_mtx_lock); ++ ++ if (!ab->rhead_peer_addr) ++ return; ++ ++ rhashtable_destroy(ab->rhead_peer_addr); ++ kfree(ab->rhead_peer_addr); ++ ab->rhead_peer_addr = NULL; ++} ++ ++int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab) ++{ ++ int ret; ++ ++ mutex_lock(&ab->tbl_mtx_lock); ++ ++ ret = ath11k_peer_rhash_id_tbl_init(ab); ++ if (ret) ++ goto out; ++ ++ ret = ath11k_peer_rhash_addr_tbl_init(ab); ++ if (ret) ++ goto cleanup_tbl; ++ ++ mutex_unlock(&ab->tbl_mtx_lock); ++ ++ return 0; ++ ++cleanup_tbl: ++ ath11k_peer_rhash_id_tbl_destroy(ab); ++out: ++ mutex_unlock(&ab->tbl_mtx_lock); ++ return ret; ++} ++ ++void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab) ++{ ++ mutex_lock(&ab->tbl_mtx_lock); ++ ++ ath11k_peer_rhash_addr_tbl_destroy(ab); ++ ath11k_peer_rhash_id_tbl_destroy(ab); ++ ++ mutex_unlock(&ab->tbl_mtx_lock); ++} +--- a/drivers/net/wireless/ath/ath11k/peer.h ++++ b/drivers/net/wireless/ath/ath11k/peer.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: BSD-3-Clause-Clear */ + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #ifndef ATH11K_PEER_H +@@ -20,6 +21,11 @@ struct ath11k_peer { + struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; + struct dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1]; + ++ /* peer id based rhashtable list pointer */ ++ struct rhash_head rhash_id; ++ /* peer addr based rhashtable list pointer */ ++ struct rhash_head rhash_addr; ++ + /* Info used in MMIC verification of + * RX fragments + */ +@@ -47,5 +53,7 @@ int ath11k_wait_for_peer_delete_done(str + const u8 *addr); + struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab, + int vdev_id); +- ++int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab); ++void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab); ++int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer); + #endif /* _PEER_H_ */ diff --git a/package/kernel/mac80211/patches/ath11k/0212-ath11k-store-and-send-country-code-to-firmware-after.patch b/package/kernel/mac80211/patches/ath11k/0212-ath11k-store-and-send-country-code-to-firmware-after.patch new file mode 100644 index 000000000..3d7f8909b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0212-ath11k-store-and-send-country-code-to-firmware-after.patch @@ -0,0 +1,70 @@ +From b2beae327e039736299f3c6559f3467323fe68c5 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 23 Mar 2022 21:18:56 -0400 +Subject: [PATCH] ath11k: store and send country code to firmware after + recovery + +Currently ath11k does not send the country code to firmware after device +recovery, as a result the regdomain info is reported from firmware by +default. Regdomain info is important, so ath11k also need to restore +it to the value which was used before recovery. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220324011856.11014-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 1 + + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 8 ++++++++ + drivers/net/wireless/ath/ath11k/reg.c | 1 + + 4 files changed, 11 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1404,6 +1404,7 @@ static void ath11k_update_11d(struct wor + pdev = &ab->pdevs[i]; + ar = pdev->ar; + ++ memcpy(&ar->alpha2, &set_current_param.alpha2, 2); + ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + if (ret) + ath11k_warn(ar->ab, +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -671,6 +671,7 @@ struct ath11k { + int hw_rate_code; + u8 twt_enabled; + bool nlo_enabled; ++ u8 alpha2[REG_ALPHA2_LEN + 1]; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7957,6 +7957,14 @@ ath11k_mac_op_reconfig_complete(struct i + ar->state = ATH11K_STATE_ON; + ieee80211_wake_queues(ar->hw); + ++ if (ar->ab->hw_params.current_cc_support && ++ ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { ++ struct wmi_set_current_country_params set_current_param = {}; ++ ++ memcpy(&set_current_param.alpha2, ar->alpha2, 2); ++ ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); ++ } ++ + if (ab->is_reset) { + recovery_count = atomic_inc_return(&ab->recovery_count); + ath11k_dbg(ab, ATH11K_DBG_BOOT, +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -83,6 +83,7 @@ ath11k_reg_notifier(struct wiphy *wiphy, + */ + if (ar->ab->hw_params.current_cc_support) { + memcpy(&set_current_param.alpha2, request->alpha2, 2); ++ memcpy(&ar->alpha2, &set_current_param.alpha2, 2); + ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + if (ret) + ath11k_warn(ar->ab, diff --git a/package/kernel/mac80211/patches/ath11k/0213-ath11k-add-support-to-search-regdb-data-in-board-2.b.patch b/package/kernel/mac80211/patches/ath11k/0213-ath11k-add-support-to-search-regdb-data-in-board-2.b.patch new file mode 100644 index 000000000..720a6f2b7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0213-ath11k-add-support-to-search-regdb-data-in-board-2.b.patch @@ -0,0 +1,316 @@ +From 801cb1d234288d9bc2afeaa98c7e98f8038b7a6c Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 28 Mar 2022 14:57:19 +0300 +Subject: [PATCH] ath11k: add support to search regdb data in board-2.bin for + WCN6855 + +Currently ath11k only download the same regdb.bin file for all WCN6855 +chips, actually ath11k needs to distinguish all different WCN6855 chips. + +This is to re-use the string type which include bus, chip id, board id, +vendor, device, subsystem-vendor, subsystem-device and variant for +WCN6855 to distinguish different regdb in board-2.bin. + +ath11k will first load board-2.bin and search in it for the regdb data +with the above parameters, if matched one regdb data, then download it +to firmware, if not matched any one, then ath11k will download the file +regdb.bin to firmware. + +Add enum value ATH11K_BD_IE_REGDB and enum type ath11k_bd_ie_regdb_type +to distinguish regdb data and board data since they are in the same file +board-2.bin. + +This only take effect for WCN6855 which supports regdb in hardware parameters. + +Test log: +[ 3833.091948] ath11k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' +[ 3833.092072] ath11k_pci 0000:05:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 205316 +[ 3833.092079] ath11k_pci 0000:05:00.0: board name +[ 3833.092083] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip +[ 3833.092088] ath11k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 31 -id=1 +[ 3833.092091] ath11k_pci 0000:05:00.0: board name +[ 3833.092095] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip +[ 3833.092099] ath11k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 32 -id=2 +[ 3833.092102] ath11k_pci 0000:05:00.0: board name +[ 3833.092105] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip +[ 3833.092109] ath11k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 33 -id=3 +[ 3833.092112] ath11k_pci 0000:05:00.0: board name +[ 3833.092116] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[ 3833.092119] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[ 3833.092123] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[ 3833.092126] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[ 3833.092130] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[ 3833.092133] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo +[ 3833.092137] ath11k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 2c 76 61 72 69 61 ard-id=266,varia +[ 3833.092140] ath11k_pci 0000:05:00.0: 00000070: 6e 74 3d 48 50 5f 47 38 5f 4c 61 6e 63 69 61 31 nt=HP_G8_Lancia1 +[ 3833.092144] ath11k_pci 0000:05:00.0: 00000080: 35 5 +[ 3833.092147] ath11k_pci 0000:05:00.0: board name +[ 3833.092150] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[ 3833.092154] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[ 3833.092157] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[ 3833.092161] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[ 3833.092165] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[ 3833.092168] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo +[ 3833.092172] ath11k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 ard-id=266 +[ 3833.092206] ath11k_pci 0000:05:00.0: board name +[ 3833.092209] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 +[ 3833.092213] ath11k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, +[ 3833.092216] ath11k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor +[ 3833.092220] ath11k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- +[ 3833.092223] ath11k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- +[ 3833.092227] ath11k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo +[ 3833.092230] ath11k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 +[ 3833.092234] ath11k_pci 0000:05:00.0: boot found match regdb data for name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' +[ 3833.092238] ath11k_pci 0000:05:00.0: board name +[ 3833.092241] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip +[ 3833.092245] ath11k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 31 31 -id=11 +[ 3833.092248] ath11k_pci 0000:05:00.0: board name +[ 3833.092251] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip +[ 3833.092255] ath11k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 32 32 -id=22 +[ 3833.092258] ath11k_pci 0000:05:00.0: board name +[ 3833.092261] ath11k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip +[ 3833.092265] ath11k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 33 33 -id=33 +[ 3833.092268] ath11k_pci 0000:05:00.0: boot found regdb data for 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' +[ 3833.092272] ath11k_pci 0000:05:00.0: fetched regdb + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220319023543.14288-4-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 84 ++++++++++++++++++-------- + drivers/net/wireless/ath/ath11k/hw.h | 19 ++++++ + 2 files changed, 78 insertions(+), 25 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -723,7 +723,9 @@ static int ath11k_core_parse_bd_ie_board + struct ath11k_board_data *bd, + const void *buf, size_t buf_len, + const char *boardname, +- int bd_ie_type) ++ int ie_id, ++ int name_id, ++ int data_id) + { + const struct ath11k_fw_ie *hdr; + bool name_match_found; +@@ -733,7 +735,7 @@ static int ath11k_core_parse_bd_ie_board + + name_match_found = false; + +- /* go through ATH11K_BD_IE_BOARD_ elements */ ++ /* go through ATH11K_BD_IE_BOARD_/ATH11K_BD_IE_REGDB_ elements */ + while (buf_len > sizeof(struct ath11k_fw_ie)) { + hdr = buf; + board_ie_id = le32_to_cpu(hdr->id); +@@ -744,48 +746,50 @@ static int ath11k_core_parse_bd_ie_board + buf += sizeof(*hdr); + + if (buf_len < ALIGN(board_ie_len, 4)) { +- ath11k_err(ab, "invalid ATH11K_BD_IE_BOARD length: %zu < %zu\n", ++ ath11k_err(ab, "invalid %s length: %zu < %zu\n", ++ ath11k_bd_ie_type_str(ie_id), + buf_len, ALIGN(board_ie_len, 4)); + ret = -EINVAL; + goto out; + } + +- switch (board_ie_id) { +- case ATH11K_BD_IE_BOARD_NAME: ++ if (board_ie_id == name_id) { + ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "board name", "", + board_ie_data, board_ie_len); + + if (board_ie_len != strlen(boardname)) +- break; ++ goto next; + + ret = memcmp(board_ie_data, boardname, strlen(boardname)); + if (ret) +- break; ++ goto next; + + name_match_found = true; + ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "boot found match for name '%s'", ++ "boot found match %s for name '%s'", ++ ath11k_bd_ie_type_str(ie_id), + boardname); +- break; +- case ATH11K_BD_IE_BOARD_DATA: ++ } else if (board_ie_id == data_id) { + if (!name_match_found) + /* no match found */ +- break; ++ goto next; + + ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "boot found board data for '%s'", boardname); ++ "boot found %s for '%s'", ++ ath11k_bd_ie_type_str(ie_id), ++ boardname); + + bd->data = board_ie_data; + bd->len = board_ie_len; + + ret = 0; + goto out; +- default: +- ath11k_warn(ab, "unknown ATH11K_BD_IE_BOARD found: %d\n", ++ } else { ++ ath11k_warn(ab, "unknown %s id found: %d\n", ++ ath11k_bd_ie_type_str(ie_id), + board_ie_id); +- break; + } +- ++next: + /* jump over the padding */ + board_ie_len = ALIGN(board_ie_len, 4); + +@@ -802,7 +806,10 @@ out: + + static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, + struct ath11k_board_data *bd, +- const char *boardname) ++ const char *boardname, ++ int ie_id_match, ++ int name_id, ++ int data_id) + { + size_t len, magic_len; + const u8 *data; +@@ -867,22 +874,23 @@ static int ath11k_core_fetch_board_data_ + goto err; + } + +- switch (ie_id) { +- case ATH11K_BD_IE_BOARD: ++ if (ie_id == ie_id_match) { + ret = ath11k_core_parse_bd_ie_board(ab, bd, data, + ie_len, + boardname, +- ATH11K_BD_IE_BOARD); ++ ie_id_match, ++ name_id, ++ data_id); + if (ret == -ENOENT) + /* no match found, continue */ +- break; ++ goto next; + else if (ret) + /* there was an error, bail out */ + goto err; + /* either found or error, so stop searching */ + goto out; + } +- ++next: + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + +@@ -893,7 +901,8 @@ static int ath11k_core_fetch_board_data_ + out: + if (!bd->data || !bd->len) { + ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "failed to fetch board data for %s from %s\n", ++ "failed to fetch %s for %s from %s\n", ++ ath11k_bd_ie_type_str(ie_id_match), + boardname, filepath); + ret = -ENODATA; + goto err; +@@ -937,7 +946,10 @@ int ath11k_core_fetch_bdf(struct ath11k_ + } + + ab->bd_api = 2; +- ret = ath11k_core_fetch_board_data_api_n(ab, bd, boardname); ++ ret = ath11k_core_fetch_board_data_api_n(ab, bd, boardname, ++ ATH11K_BD_IE_BOARD, ++ ATH11K_BD_IE_BOARD_NAME, ++ ATH11K_BD_IE_BOARD_DATA); + if (!ret) + goto success; + +@@ -948,7 +960,10 @@ int ath11k_core_fetch_bdf(struct ath11k_ + return ret; + } + +- ret = ath11k_core_fetch_board_data_api_n(ab, bd, fallback_boardname); ++ ret = ath11k_core_fetch_board_data_api_n(ab, bd, fallback_boardname, ++ ATH11K_BD_IE_BOARD, ++ ATH11K_BD_IE_BOARD_NAME, ++ ATH11K_BD_IE_BOARD_DATA); + if (!ret) + goto success; + +@@ -975,13 +990,32 @@ success: + + int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd) + { ++ char boardname[BOARD_NAME_SIZE]; + int ret; + ++ ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); ++ if (ret) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "failed to create board name for regdb: %d", ret); ++ goto exit; ++ } ++ ++ ret = ath11k_core_fetch_board_data_api_n(ab, bd, boardname, ++ ATH11K_BD_IE_REGDB, ++ ATH11K_BD_IE_REGDB_NAME, ++ ATH11K_BD_IE_REGDB_DATA); ++ if (!ret) ++ goto exit; ++ + ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_REGDB_FILE_NAME); + if (ret) + ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to fetch %s from %s\n", + ATH11K_REGDB_FILE_NAME, ab->hw_params.fw.dir); + ++exit: ++ if (!ret) ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "fetched regdb\n"); ++ + return ret; + } + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -291,9 +291,16 @@ enum ath11k_bd_ie_board_type { + ATH11K_BD_IE_BOARD_DATA = 1, + }; + ++enum ath11k_bd_ie_regdb_type { ++ ATH11K_BD_IE_REGDB_NAME = 0, ++ ATH11K_BD_IE_REGDB_DATA = 1, ++}; ++ + enum ath11k_bd_ie_type { + /* contains sub IEs of enum ath11k_bd_ie_board_type */ + ATH11K_BD_IE_BOARD = 0, ++ /* contains sub IEs of enum ath11k_bd_ie_regdb_type */ ++ ATH11K_BD_IE_REGDB = 1, + }; + + struct ath11k_hw_regs { +@@ -361,4 +368,16 @@ extern const struct ath11k_hw_regs qca63 + extern const struct ath11k_hw_regs qcn9074_regs; + extern const struct ath11k_hw_regs wcn6855_regs; + ++static inline const char *ath11k_bd_ie_type_str(enum ath11k_bd_ie_type type) ++{ ++ switch (type) { ++ case ATH11K_BD_IE_BOARD: ++ return "board data"; ++ case ATH11K_BD_IE_REGDB: ++ return "regdb data"; ++ } ++ ++ return "unknown"; ++} ++ + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0214-ath11k-reduce-the-wait-time-of-11d-scan-and-hw-scan-.patch b/package/kernel/mac80211/patches/ath11k/0214-ath11k-reduce-the-wait-time-of-11d-scan-and-hw-scan-.patch new file mode 100644 index 000000000..5baf0c021 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0214-ath11k-reduce-the-wait-time-of-11d-scan-and-hw-scan-.patch @@ -0,0 +1,400 @@ +From 1f682dc9fb3790aa7ec27d3d122ff32b1eda1365 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Sun, 27 Mar 2022 23:58:32 -0400 +Subject: [PATCH] ath11k: reduce the wait time of 11d scan and hw scan while + add interface + +Currently ath11k will wait 11d scan complete while add interface in +ath11k_mac_op_add_interface(), when system resume without enable +wowlan, ath11k_mac_op_add_interface() is called for each resume, thus +it increase the resume time of system. And ath11k_mac_op_hw_scan() +after ath11k_mac_op_add_interface() also needs some time cost because +the previous 11d scan need more than 5 seconds when 6 GHz is enabled, +then the scan started event will indicated to ath11k after the 11d +scan completed. + +While 11d scan/hw scan is running in firmware, if ath11k update channel +list to firmware by WMI_SCAN_CHAN_LIST_CMDID, then firmware will cancel +the current scan which is running, it lead the scan failed. The patch +commit 9dcf6808b253 ("ath11k: add 11d scan offload support") used +finish_11d_scan/finish_11d_ch_list/pending_11d to synchronize the 11d +scan/hw scan/channel list between ath11k/firmware/mac80211 and to avoid +the scan fail. + +Add wait operation before ath11k update channel list, function +ath11k_reg_update_chan_list() will wait until the current 11d scan/hw +scan completed. And remove the wait operation of start 11d scan and +waiting channel list complete in hw scan. After these changes, resume +time cost reduce about 5 seconds and also hw scan time cost reduced +obviously, and scan failed not seen. + +The 11d scan is sent to firmware only one time for each interface added +in mac.c, and it is moved after the 1st hw scan because 11d scan will +cost some time and thus leads the AP scan result update to UI delay. +Currently priority of ath11k's hw scan is WMI_SCAN_PRIORITY_LOW, and +priority of 11d scan in firmware is WMI_SCAN_PRIORITY_MEDIUM, then the +11d scan which sent after hw scan will cancel the hw scan in firmware, +so change the priority to WMI_SCAN_PRIORITY_MEDIUM for the hw scan which +is in front of the 11d scan, thus it will not happen scan cancel in +firmware. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 + +Fixes: 9dcf6808b253 ("ath11k: add 11d scan offload support") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220328035832.14122-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 1 + + drivers/net/wireless/ath/ath11k/core.h | 13 +++-- + drivers/net/wireless/ath/ath11k/mac.c | 71 +++++++++++--------------- + drivers/net/wireless/ath/ath11k/mac.h | 2 +- + drivers/net/wireless/ath/ath11k/reg.c | 43 ++++++++++------ + drivers/net/wireless/ath/ath11k/reg.h | 2 +- + drivers/net/wireless/ath/ath11k/wmi.c | 16 +++++- + 7 files changed, 84 insertions(+), 64 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1465,6 +1465,7 @@ static void ath11k_core_pre_reconfigure_ + + ieee80211_stop_queues(ar->hw); + ath11k_mac_drain_tx(ar); ++ complete(&ar->completed_11d_scan); + complete(&ar->scan.started); + complete(&ar->scan.completed); + complete(&ar->peer_assoc_done); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -52,6 +52,8 @@ + + extern unsigned int ath11k_frame_mode; + ++#define ATH11K_SCAN_TIMEOUT_HZ (20 * HZ) ++ + #define ATH11K_MON_TIMER_INTERVAL 10 + #define ATH11K_RESET_TIMEOUT_HZ (20 * HZ) + #define ATH11K_RESET_MAX_FAIL_COUNT_FIRST 3 +@@ -216,6 +218,12 @@ enum ath11k_scan_state { + ATH11K_SCAN_ABORTING, + }; + ++enum ath11k_11d_state { ++ ATH11K_11D_IDLE, ++ ATH11K_11D_PREPARING, ++ ATH11K_11D_RUNNING, ++}; ++ + enum ath11k_dev_flags { + ATH11K_CAC_RUNNING, + ATH11K_FLAG_CORE_REGISTERED, +@@ -664,9 +672,8 @@ struct ath11k { + bool dfs_block_radar_events; + struct ath11k_thermal thermal; + u32 vdev_id_11d_scan; +- struct completion finish_11d_scan; +- struct completion finish_11d_ch_list; +- bool pending_11d; ++ struct completion completed_11d_scan; ++ enum ath11k_11d_state state_11d; + bool regdom_set_by_user; + int hw_rate_code; + u8 twt_enabled; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3621,26 +3621,6 @@ static int ath11k_mac_op_hw_scan(struct + if (ret) + goto exit; + +- /* Currently the pending_11d=true only happened 1 time while +- * wlan interface up in ath11k_mac_11d_scan_start(), it is called by +- * ath11k_mac_op_add_interface(), after wlan interface up, +- * pending_11d=false always. +- * If remove below wait, it always happened scan fail and lead connect +- * fail while wlan interface up, because it has a 11d scan which is running +- * in firmware, and lead this scan failed. +- */ +- if (ar->pending_11d) { +- long time_left; +- unsigned long timeout = 5 * HZ; +- +- if (ar->supports_6ghz) +- timeout += 5 * HZ; +- +- time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout); +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "mac wait 11d channel list time left %ld\n", time_left); +- } +- + memset(&arg, 0, sizeof(arg)); + ath11k_wmi_start_scan_init(ar, &arg); + arg.vdev_id = arvif->vdev_id; +@@ -3706,6 +3686,10 @@ exit: + kfree(arg.extraie.ptr); + + mutex_unlock(&ar->conf_mutex); ++ ++ if (ar->state_11d == ATH11K_11D_PREPARING) ++ ath11k_mac_11d_scan_start(ar, arvif->vdev_id); ++ + return ret; + } + +@@ -5859,7 +5843,7 @@ static int ath11k_mac_op_start(struct ie + + /* TODO: Do we need to enable ANI? */ + +- ath11k_reg_update_chan_list(ar); ++ ath11k_reg_update_chan_list(ar, false); + + ar->num_started_vdevs = 0; + ar->num_created_vdevs = 0; +@@ -5926,6 +5910,11 @@ static void ath11k_mac_op_stop(struct ie + cancel_work_sync(&ar->ab->update_11d_work); + cancel_work_sync(&ar->ab->rfkill_work); + ++ if (ar->state_11d == ATH11K_11D_PREPARING) { ++ ar->state_11d = ATH11K_11D_IDLE; ++ complete(&ar->completed_11d_scan); ++ } ++ + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { + list_del(&ppdu_stats->list); +@@ -6096,7 +6085,7 @@ static bool ath11k_mac_vif_ap_active_any + return false; + } + +-void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait) ++void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id) + { + struct wmi_11d_scan_start_params param; + int ret; +@@ -6124,28 +6113,22 @@ void ath11k_mac_11d_scan_start(struct at + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); + +- if (wait) +- reinit_completion(&ar->finish_11d_scan); +- + ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n", + vdev_id, ret); + } else { + ar->vdev_id_11d_scan = vdev_id; +- if (wait) { +- ar->pending_11d = true; +- ret = wait_for_completion_timeout(&ar->finish_11d_scan, +- 5 * HZ); +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "mac 11d scan left time %d\n", ret); +- +- if (!ret) +- ar->pending_11d = false; +- } ++ if (ar->state_11d == ATH11K_11D_PREPARING) ++ ar->state_11d = ATH11K_11D_RUNNING; + } + + fin: ++ if (ar->state_11d == ATH11K_11D_PREPARING) { ++ ar->state_11d = ATH11K_11D_IDLE; ++ complete(&ar->completed_11d_scan); ++ } ++ + mutex_unlock(&ar->ab->vdev_id_11d_lock); + } + +@@ -6168,12 +6151,15 @@ void ath11k_mac_11d_scan_stop(struct ath + vdev_id = ar->vdev_id_11d_scan; + + ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); +- if (ret) ++ if (ret) { + ath11k_warn(ar->ab, + "failed to stopt 11d scan vdev %d ret: %d\n", + vdev_id, ret); +- else ++ } else { + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; ++ ar->state_11d = ATH11K_11D_IDLE; ++ complete(&ar->completed_11d_scan); ++ } + } + mutex_unlock(&ar->ab->vdev_id_11d_lock); + } +@@ -6369,8 +6355,10 @@ static int ath11k_mac_op_add_interface(s + goto err_peer_del; + } + +- ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true); +- ++ if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map)) { ++ reinit_completion(&ar->completed_11d_scan); ++ ar->state_11d = ATH11K_11D_PREPARING; ++ } + break; + case WMI_VDEV_TYPE_MONITOR: + set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); +@@ -7230,7 +7218,7 @@ ath11k_mac_op_unassign_vif_chanctx(struc + } + + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) +- ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false); ++ ath11k_mac_11d_scan_start(ar, arvif->vdev_id); + + mutex_unlock(&ar->conf_mutex); + } +@@ -8920,8 +8908,7 @@ int ath11k_mac_allocate(struct ath11k_ba + ar->monitor_vdev_id = -1; + clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; +- init_completion(&ar->finish_11d_scan); +- init_completion(&ar->finish_11d_ch_list); ++ init_completion(&ar->completed_11d_scan); + } + + return 0; +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -130,7 +130,7 @@ extern const struct htt_rx_ring_tlv_filt + #define ATH11K_SCAN_11D_INTERVAL 600000 + #define ATH11K_11D_INVALID_VDEV_ID 0xFFFF + +-void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait); ++void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id); + void ath11k_mac_11d_scan_stop(struct ath11k *ar); + void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab); + +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -103,7 +103,7 @@ ath11k_reg_notifier(struct wiphy *wiphy, + ar->regdom_set_by_user = true; + } + +-int ath11k_reg_update_chan_list(struct ath11k *ar) ++int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait) + { + struct ieee80211_supported_band **bands; + struct scan_chan_list_params *params; +@@ -112,7 +112,32 @@ int ath11k_reg_update_chan_list(struct a + struct channel_param *ch; + enum nl80211_band band; + int num_channels = 0; +- int i, ret; ++ int i, ret, left; ++ ++ if (wait && ar->state_11d != ATH11K_11D_IDLE) { ++ left = wait_for_completion_timeout(&ar->completed_11d_scan, ++ ATH11K_SCAN_TIMEOUT_HZ); ++ if (!left) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_REG, ++ "failed to receive 11d scan complete: timed out\n"); ++ ar->state_11d = ATH11K_11D_IDLE; ++ } ++ ath11k_dbg(ar->ab, ATH11K_DBG_REG, ++ "reg 11d scan wait left time %d\n", left); ++ } ++ ++ if (wait && ++ (ar->scan.state == ATH11K_SCAN_STARTING || ++ ar->scan.state == ATH11K_SCAN_RUNNING)) { ++ left = wait_for_completion_timeout(&ar->scan.completed, ++ ATH11K_SCAN_TIMEOUT_HZ); ++ if (!left) ++ ath11k_dbg(ar->ab, ATH11K_DBG_REG, ++ "failed to receive hw scan complete: timed out\n"); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_REG, ++ "reg hw scan wait left time %d\n", left); ++ } + + bands = hw->wiphy->bands; + for (band = 0; band < NUM_NL80211_BANDS; band++) { +@@ -194,11 +219,6 @@ int ath11k_reg_update_chan_list(struct a + ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); + kfree(params); + +- if (ar->pending_11d) { +- complete(&ar->finish_11d_ch_list); +- ar->pending_11d = false; +- } +- + return ret; + } + +@@ -264,15 +284,8 @@ int ath11k_regd_update(struct ath11k *ar + goto err; + } + +- if (ar->pending_11d) +- complete(&ar->finish_11d_scan); +- + rtnl_lock(); + wiphy_lock(ar->hw->wiphy); +- +- if (ar->pending_11d) +- reinit_completion(&ar->finish_11d_ch_list); +- + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); + wiphy_unlock(ar->hw->wiphy); + rtnl_unlock(); +@@ -283,7 +296,7 @@ int ath11k_regd_update(struct ath11k *ar + goto err; + + if (ar->state == ATH11K_STATE_ON) { +- ret = ath11k_reg_update_chan_list(ar); ++ ret = ath11k_reg_update_chan_list(ar, true); + if (ret) + goto err; + } +--- a/drivers/net/wireless/ath/ath11k/reg.h ++++ b/drivers/net/wireless/ath/ath11k/reg.h +@@ -32,5 +32,5 @@ struct ieee80211_regdomain * + ath11k_reg_build_regd(struct ath11k_base *ab, + struct cur_regulatory_info *reg_info, bool intersect); + int ath11k_regd_update(struct ath11k *ar); +-int ath11k_reg_update_chan_list(struct ath11k *ar); ++int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait); + #endif +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2015,7 +2015,10 @@ void ath11k_wmi_start_scan_init(struct a + { + /* setup commonly used values */ + arg->scan_req_id = 1; +- arg->scan_priority = WMI_SCAN_PRIORITY_LOW; ++ if (ar->state_11d == ATH11K_11D_PREPARING) ++ arg->scan_priority = WMI_SCAN_PRIORITY_MEDIUM; ++ else ++ arg->scan_priority = WMI_SCAN_PRIORITY_LOW; + arg->dwell_time_active = 50; + arg->dwell_time_active_2g = 0; + arg->dwell_time_passive = 150; +@@ -6350,8 +6353,10 @@ static void ath11k_wmi_op_ep_tx_credits( + static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb) + { + const struct wmi_11d_new_cc_ev *ev; ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; + const void **tb; +- int ret; ++ int ret, i; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { +@@ -6377,6 +6382,13 @@ static int ath11k_reg_11d_new_cc_event(s + + kfree(tb); + ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ ar->state_11d = ATH11K_11D_IDLE; ++ complete(&ar->completed_11d_scan); ++ } ++ + queue_work(ab->workqueue, &ab->update_11d_work); + + return 0; diff --git a/package/kernel/mac80211/patches/ath11k/0215-ath11k-PCI-changes-to-support-WCN6750.patch b/package/kernel/mac80211/patches/ath11k/0215-ath11k-PCI-changes-to-support-WCN6750.patch new file mode 100644 index 000000000..3792748ab --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0215-ath11k-PCI-changes-to-support-WCN6750.patch @@ -0,0 +1,388 @@ +From 948171b5f6fcf11253355bd836e6e8b613bea12f Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Fri, 1 Apr 2022 14:53:08 +0300 +Subject: [PATCH] ath11k: PCI changes to support WCN6750 + +In order to add the support for WCN6750 in ATH11K , it is +required to move certain PCI definitions to the header file. +As a result, add ATH11K_PCI_* prefix to these definitions. + +Also, change the scope of certain PCI APIs that are required +to enable WCN6750 from static to global. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220328055714.6449-2-quic_mpubbise@quicinc.com +--- + drivers/net/wireless/ath/ath11k/pci.c | 110 ++++++++++++-------------- + drivers/net/wireless/ath/ath11k/pci.h | 35 ++++++++ + 2 files changed, 84 insertions(+), 61 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -17,25 +18,10 @@ + #define ATH11K_PCI_BAR_NUM 0 + #define ATH11K_PCI_DMA_MASK 32 + +-#define ATH11K_PCI_IRQ_CE0_OFFSET 3 +-#define ATH11K_PCI_IRQ_DP_OFFSET 14 +- +-#define WINDOW_ENABLE_BIT 0x40000000 +-#define WINDOW_REG_ADDRESS 0x310c +-#define WINDOW_VALUE_MASK GENMASK(24, 19) +-#define WINDOW_START 0x80000 +-#define WINDOW_RANGE_MASK GENMASK(18, 0) +- + #define TCSR_SOC_HW_VERSION 0x0224 + #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) + #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) + +-/* BAR0 + 4k is always accessible, and no +- * need to force wakeup. +- * 4K - 32 = 0xFE0 +- */ +-#define ACCESS_ALWAYS_OFF 0xFE0 +- + #define QCA6390_DEVICE_ID 0x1101 + #define QCN9074_DEVICE_ID 0x1104 + #define WCN6855_DEVICE_ID 0x1103 +@@ -147,27 +133,30 @@ static inline void ath11k_pci_select_win + { + struct ath11k_base *ab = ab_pci->ab; + +- u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); ++ u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); + + lockdep_assert_held(&ab_pci->window_lock); + + if (window != ab_pci->register_window) { +- iowrite32(WINDOW_ENABLE_BIT | window, +- ab->mem + WINDOW_REG_ADDRESS); +- ioread32(ab->mem + WINDOW_REG_ADDRESS); ++ iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, ++ ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); ++ ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + ab_pci->register_window = window; + } + } + + static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) + { +- u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); +- u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); ++ u32 umac_window; ++ u32 ce_window; + u32 window; + ++ umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); ++ ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); + window = (umac_window << 12) | (ce_window << 6); + +- iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); ++ iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, ++ ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + } + + static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, +@@ -176,13 +165,13 @@ static inline u32 ath11k_pci_get_window_ + u32 window_start; + + /* If offset lies within DP register range, use 3rd window */ +- if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK) +- window_start = 3 * WINDOW_START; ++ if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK) ++ window_start = 3 * ATH11K_PCI_WINDOW_START; + /* If offset lies within CE register range, use 2nd window */ +- else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) +- window_start = 2 * WINDOW_START; ++ else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < ATH11K_PCI_WINDOW_RANGE_MASK) ++ window_start = 2 * ATH11K_PCI_WINDOW_START; + else +- window_start = WINDOW_START; ++ window_start = ATH11K_PCI_WINDOW_START; + + return window_start; + } +@@ -198,32 +187,32 @@ void ath11k_pci_write32(struct ath11k_ba + */ + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ACCESS_ALWAYS_OFF) ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) + ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +- if (offset < WINDOW_START) { ++ if (offset < ATH11K_PCI_WINDOW_START) { + iowrite32(value, ab->mem + offset); + } else { + if (ab->bus_params.static_window_map) + window_start = ath11k_pci_get_window_start(ab, offset); + else +- window_start = WINDOW_START; ++ window_start = ATH11K_PCI_WINDOW_START; + +- if (window_start == WINDOW_START) { ++ if (window_start == ATH11K_PCI_WINDOW_START) { + spin_lock_bh(&ab_pci->window_lock); + ath11k_pci_select_window(ab_pci, offset); + iowrite32(value, ab->mem + window_start + +- (offset & WINDOW_RANGE_MASK)); ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); + spin_unlock_bh(&ab_pci->window_lock); + } else { + iowrite32(value, ab->mem + window_start + +- (offset & WINDOW_RANGE_MASK)); ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); + } + } + + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ACCESS_ALWAYS_OFF && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && + !ret) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + } +@@ -239,32 +228,32 @@ u32 ath11k_pci_read32(struct ath11k_base + */ + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ACCESS_ALWAYS_OFF) ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) + ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +- if (offset < WINDOW_START) { ++ if (offset < ATH11K_PCI_WINDOW_START) { + val = ioread32(ab->mem + offset); + } else { + if (ab->bus_params.static_window_map) + window_start = ath11k_pci_get_window_start(ab, offset); + else +- window_start = WINDOW_START; ++ window_start = ATH11K_PCI_WINDOW_START; + +- if (window_start == WINDOW_START) { ++ if (window_start == ATH11K_PCI_WINDOW_START) { + spin_lock_bh(&ab_pci->window_lock); + ath11k_pci_select_window(ab_pci, offset); + val = ioread32(ab->mem + window_start + +- (offset & WINDOW_RANGE_MASK)); ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); + spin_unlock_bh(&ab_pci->window_lock); + } else { + val = ioread32(ab->mem + window_start + +- (offset & WINDOW_RANGE_MASK)); ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); + } + } + + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ACCESS_ALWAYS_OFF && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && + !ret) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + +@@ -474,8 +463,8 @@ int ath11k_pci_get_msi_irq(struct device + return pci_irq_vector(pci_dev, vector); + } + +-static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, +- u32 *msi_addr_hi) ++void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, ++ u32 *msi_addr_hi) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + struct pci_dev *pci_dev = to_pci_dev(ab->dev); +@@ -519,8 +508,7 @@ int ath11k_pci_get_user_msi_assignment(s + return -EINVAL; + } + +-static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, +- u32 *msi_idx) ++void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx) + { + u32 i, msi_data_idx; + +@@ -536,9 +524,9 @@ static void ath11k_pci_get_ce_msi_idx(st + *msi_idx = msi_data_idx; + } + +-static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector) ++int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, ++ int *num_vectors, u32 *user_base_data, ++ u32 *base_vector) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + +@@ -561,7 +549,7 @@ static void ath11k_pci_free_ext_irq(stru + } + } + +-static void ath11k_pci_free_irq(struct ath11k_base *ab) ++void ath11k_pci_free_irq(struct ath11k_base *ab) + { + int i, irq_idx; + +@@ -710,7 +698,7 @@ static void ath11k_pci_ext_grp_enable(st + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } + +-static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) ++void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) + { + int i; + +@@ -741,7 +729,7 @@ static void ath11k_pci_sync_ext_irqs(str + } + } + +-static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) ++void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) + { + __ath11k_pci_ext_irq_disable(ab); + ath11k_pci_sync_ext_irqs(ab); +@@ -854,8 +842,8 @@ static int ath11k_pci_ext_irq_config(str + return 0; + } + +-static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, +- const struct cpumask *m) ++int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m) + { + if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return 0; +@@ -863,7 +851,7 @@ static int ath11k_pci_set_irq_affinity_h + return irq_set_affinity_hint(ab_pci->pdev->irq, m); + } + +-static int ath11k_pci_config_irq(struct ath11k_base *ab) ++int ath11k_pci_config_irq(struct ath11k_base *ab) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + struct ath11k_ce_pipe *ce_pipe; +@@ -939,7 +927,7 @@ static void ath11k_pci_init_qmi_ce_confi + &cfg->shadow_reg_v2_len); + } + +-static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) ++void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) + { + int i; + +@@ -1151,7 +1139,7 @@ static void ath11k_pci_aspm_disable(stru + set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); + } + +-static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) ++void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) + { + if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) + pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +@@ -1234,20 +1222,20 @@ static void ath11k_pci_kill_tasklets(str + } + } + +-static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) ++void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) + { + ath11k_pci_ce_irqs_disable(ab); + ath11k_pci_sync_ce_irqs(ab); + ath11k_pci_kill_tasklets(ab); + } + +-static void ath11k_pci_stop(struct ath11k_base *ab) ++void ath11k_pci_stop(struct ath11k_base *ab) + { + ath11k_pci_ce_irq_disable_sync(ab); + ath11k_ce_cleanup_pipes(ab); + } + +-static int ath11k_pci_start(struct ath11k_base *ab) ++int ath11k_pci_start(struct ath11k_base *ab) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + +@@ -1277,8 +1265,8 @@ static void ath11k_pci_hif_ce_irq_disabl + ath11k_pci_ce_irq_disable_sync(ab); + } + +-static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, +- u8 *ul_pipe, u8 *dl_pipe) ++int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, ++ u8 *ul_pipe, u8 *dl_pipe) + { + const struct service_to_pipe *entry; + bool ul_set = false, dl_set = false; +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: BSD-3-Clause-Clear */ + /* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + #ifndef _ATH11K_PCI_H + #define _ATH11K_PCI_H +@@ -52,6 +53,21 @@ + #define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c + #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 + ++#define ATH11K_PCI_IRQ_CE0_OFFSET 3 ++#define ATH11K_PCI_IRQ_DP_OFFSET 14 ++ ++#define ATH11K_PCI_WINDOW_ENABLE_BIT 0x40000000 ++#define ATH11K_PCI_WINDOW_REG_ADDRESS 0x310c ++#define ATH11K_PCI_WINDOW_VALUE_MASK GENMASK(24, 19) ++#define ATH11K_PCI_WINDOW_START 0x80000 ++#define ATH11K_PCI_WINDOW_RANGE_MASK GENMASK(18, 0) ++ ++/* BAR0 + 4k is always accessible, and no ++ * need to force wakeup. ++ * 4K - 32 = 0xFE0 ++ */ ++#define ATH11K_PCI_ACCESS_ALWAYS_OFF 0xFE0 ++ + struct ath11k_msi_user { + char *name; + int num_vectors; +@@ -103,5 +119,24 @@ int ath11k_pci_get_user_msi_assignment(s + int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector); + void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value); + u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset); ++void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, ++ u32 *msi_addr_hi); ++void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx); ++void ath11k_pci_free_irq(struct ath11k_base *ab); ++int ath11k_pci_config_irq(struct ath11k_base *ab); ++void ath11k_pci_ext_irq_enable(struct ath11k_base *ab); ++void ath11k_pci_ext_irq_disable(struct ath11k_base *ab); ++void ath11k_pci_stop(struct ath11k_base *ab); ++int ath11k_pci_start(struct ath11k_base *ab); ++int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, ++ u8 *ul_pipe, u8 *dl_pipe); ++void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab); ++void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab); ++int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, ++ int *num_vectors, u32 *user_base_data, ++ u32 *base_vector); ++void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci); ++int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m); + + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0216-ath11k-Refactor-PCI-code-to-support-WCN6750.patch b/package/kernel/mac80211/patches/ath11k/0216-ath11k-Refactor-PCI-code-to-support-WCN6750.patch new file mode 100644 index 000000000..bc3b16731 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0216-ath11k-Refactor-PCI-code-to-support-WCN6750.patch @@ -0,0 +1,2010 @@ +From bbfdc5a751a634fcdaae669cc98b3d0e1dc0eedf Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Fri, 1 Apr 2022 14:53:08 +0300 +Subject: [PATCH] ath11k: Refactor PCI code to support WCN6750 + +Unlike other ATH11K PCIe devices which are enumerated by APSS +processor (Application Processor SubSystem), WCN6750 gets +enumerated by the WPSS Q6 processor (Wireless Processor SubSystem); +In simple terms, though WCN6750 is PCIe device, it is not attached +to the APSS processor, APSS will not know of such a device being +present in the system and therefore WCN6750 will be registered as +a platform device to the kernel core like other supported AHB +devices. + +WCN6750 needs both AHB and PCI APIs for it's operation, it uses +AHB APIs for device probe/boot and PCI APIs for device setup and +register accesses. Because of this nature, it is referred as a +hybrid bus device. + +Refactor PCI code to support hybrid bus devices like WCN6750. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220328055714.6449-3-quic_mpubbise@quicinc.com +--- + drivers/net/wireless/ath/ath11k/Makefile | 2 +- + drivers/net/wireless/ath/ath11k/mhi.c | 27 +- + drivers/net/wireless/ath/ath11k/pci.c | 816 ++--------------------- + drivers/net/wireless/ath/ath11k/pci.h | 41 -- + drivers/net/wireless/ath/ath11k/pcic.c | 747 +++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/pcic.h | 53 ++ + 6 files changed, 856 insertions(+), 830 deletions(-) + create mode 100644 drivers/net/wireless/ath/ath11k/pcic.c + create mode 100644 drivers/net/wireless/ath/ath11k/pcic.h + +--- a/drivers/net/wireless/ath/ath11k/Makefile ++++ b/drivers/net/wireless/ath/ath11k/Makefile +@@ -29,7 +29,7 @@ obj-$(CPTCFG_ATH11K_AHB) += ath11k_ahb.o + ath11k_ahb-y += ahb.o + + obj-$(CPTCFG_ATH11K_PCI) += ath11k_pci.o +-ath11k_pci-y += mhi.o pci.o ++ath11k_pci-y += mhi.o pci.o pcic.o + + # for tracing framework to find trace.h + CFLAGS_trace.o := -I$(src) +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -1,5 +1,8 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear +-/* Copyright (c) 2020 The Linux Foundation. All rights reserved. */ ++/* ++ * Copyright (c) 2020 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ */ + + #include + #include +@@ -11,6 +14,7 @@ + #include "debug.h" + #include "mhi.h" + #include "pci.h" ++#include "pcic.h" + + #define MHI_TIMEOUT_DEFAULT_MS 90000 + #define RDDM_DUMP_SIZE 0x420000 +@@ -205,7 +209,7 @@ void ath11k_mhi_set_mhictrl_reset(struct + { + u32 val; + +- val = ath11k_pci_read32(ab, MHISTATUS); ++ val = ath11k_pcic_read32(ab, MHISTATUS); + + ath11k_dbg(ab, ATH11K_DBG_PCI, "MHISTATUS 0x%x\n", val); + +@@ -213,29 +217,29 @@ void ath11k_mhi_set_mhictrl_reset(struct + * has SYSERR bit set and thus need to set MHICTRL_RESET + * to clear SYSERR. + */ +- ath11k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK); ++ ath11k_pcic_write32(ab, MHICTRL, MHICTRL_RESET_MASK); + + mdelay(10); + } + + static void ath11k_mhi_reset_txvecdb(struct ath11k_base *ab) + { +- ath11k_pci_write32(ab, PCIE_TXVECDB, 0); ++ ath11k_pcic_write32(ab, PCIE_TXVECDB, 0); + } + + static void ath11k_mhi_reset_txvecstatus(struct ath11k_base *ab) + { +- ath11k_pci_write32(ab, PCIE_TXVECSTATUS, 0); ++ ath11k_pcic_write32(ab, PCIE_TXVECSTATUS, 0); + } + + static void ath11k_mhi_reset_rxvecdb(struct ath11k_base *ab) + { +- ath11k_pci_write32(ab, PCIE_RXVECDB, 0); ++ ath11k_pcic_write32(ab, PCIE_RXVECDB, 0); + } + + static void ath11k_mhi_reset_rxvecstatus(struct ath11k_base *ab) + { +- ath11k_pci_write32(ab, PCIE_RXVECSTATUS, 0); ++ ath11k_pcic_write32(ab, PCIE_RXVECSTATUS, 0); + } + + void ath11k_mhi_clear_vector(struct ath11k_base *ab) +@@ -254,9 +258,9 @@ static int ath11k_mhi_get_msi(struct ath + int *irq; + unsigned int msi_data; + +- ret = ath11k_pci_get_user_msi_assignment(ab_pci, +- "MHI", &num_vectors, +- &user_base_data, &base_vector); ++ ret = ath11k_pcic_get_user_msi_assignment(ab_pci, ++ "MHI", &num_vectors, ++ &user_base_data, &base_vector); + if (ret) + return ret; + +@@ -273,8 +277,7 @@ static int ath11k_mhi_get_msi(struct ath + if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + msi_data += i; + +- irq[i] = ath11k_pci_get_msi_irq(ab->dev, +- msi_data); ++ irq[i] = ath11k_pcic_get_msi_irq(ab->dev, msi_data); + } + + ab_pci->mhi_ctrl->irq = irq; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -14,6 +14,7 @@ + #include "hif.h" + #include "mhi.h" + #include "debug.h" ++#include "pcic.h" + + #define ATH11K_PCI_BAR_NUM 0 + #define ATH11K_PCI_DMA_MASK 32 +@@ -75,76 +76,6 @@ static const struct ath11k_msi_config ms + }, + }; + +-static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { +- "bhi", +- "mhi-er0", +- "mhi-er1", +- "ce0", +- "ce1", +- "ce2", +- "ce3", +- "ce4", +- "ce5", +- "ce6", +- "ce7", +- "ce8", +- "ce9", +- "ce10", +- "ce11", +- "host2wbm-desc-feed", +- "host2reo-re-injection", +- "host2reo-command", +- "host2rxdma-monitor-ring3", +- "host2rxdma-monitor-ring2", +- "host2rxdma-monitor-ring1", +- "reo2ost-exception", +- "wbm2host-rx-release", +- "reo2host-status", +- "reo2host-destination-ring4", +- "reo2host-destination-ring3", +- "reo2host-destination-ring2", +- "reo2host-destination-ring1", +- "rxdma2host-monitor-destination-mac3", +- "rxdma2host-monitor-destination-mac2", +- "rxdma2host-monitor-destination-mac1", +- "ppdu-end-interrupts-mac3", +- "ppdu-end-interrupts-mac2", +- "ppdu-end-interrupts-mac1", +- "rxdma2host-monitor-status-ring-mac3", +- "rxdma2host-monitor-status-ring-mac2", +- "rxdma2host-monitor-status-ring-mac1", +- "host2rxdma-host-buf-ring-mac3", +- "host2rxdma-host-buf-ring-mac2", +- "host2rxdma-host-buf-ring-mac1", +- "rxdma2host-destination-ring-mac3", +- "rxdma2host-destination-ring-mac2", +- "rxdma2host-destination-ring-mac1", +- "host2tcl-input-ring4", +- "host2tcl-input-ring3", +- "host2tcl-input-ring2", +- "host2tcl-input-ring1", +- "wbm2host-tx-completions-ring3", +- "wbm2host-tx-completions-ring2", +- "wbm2host-tx-completions-ring1", +- "tcl2host-status-ring", +-}; +- +-static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) +-{ +- struct ath11k_base *ab = ab_pci->ab; +- +- u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); +- +- lockdep_assert_held(&ab_pci->window_lock); +- +- if (window != ab_pci->register_window) { +- iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, +- ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); +- ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); +- ab_pci->register_window = window; +- } +-} +- + static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) + { + u32 umac_window; +@@ -159,116 +90,15 @@ static inline void ath11k_pci_select_sta + ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + } + +-static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, +- u32 offset) +-{ +- u32 window_start; +- +- /* If offset lies within DP register range, use 3rd window */ +- if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK) +- window_start = 3 * ATH11K_PCI_WINDOW_START; +- /* If offset lies within CE register range, use 2nd window */ +- else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < ATH11K_PCI_WINDOW_RANGE_MASK) +- window_start = 2 * ATH11K_PCI_WINDOW_START; +- else +- window_start = ATH11K_PCI_WINDOW_START; +- +- return window_start; +-} +- +-void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- u32 window_start; +- int ret = 0; +- +- /* for offset beyond BAR + 4K - 32, may +- * need to wakeup MHI to access. +- */ +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) +- ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); +- +- if (offset < ATH11K_PCI_WINDOW_START) { +- iowrite32(value, ab->mem + offset); +- } else { +- if (ab->bus_params.static_window_map) +- window_start = ath11k_pci_get_window_start(ab, offset); +- else +- window_start = ATH11K_PCI_WINDOW_START; +- +- if (window_start == ATH11K_PCI_WINDOW_START) { +- spin_lock_bh(&ab_pci->window_lock); +- ath11k_pci_select_window(ab_pci, offset); +- iowrite32(value, ab->mem + window_start + +- (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); +- spin_unlock_bh(&ab_pci->window_lock); +- } else { +- iowrite32(value, ab->mem + window_start + +- (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); +- } +- } +- +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && +- !ret) +- mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); +-} +- +-u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- u32 val, window_start; +- int ret = 0; +- +- /* for offset beyond BAR + 4K - 32, may +- * need to wakeup MHI to access. +- */ +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) +- ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); +- +- if (offset < ATH11K_PCI_WINDOW_START) { +- val = ioread32(ab->mem + offset); +- } else { +- if (ab->bus_params.static_window_map) +- window_start = ath11k_pci_get_window_start(ab, offset); +- else +- window_start = ATH11K_PCI_WINDOW_START; +- +- if (window_start == ATH11K_PCI_WINDOW_START) { +- spin_lock_bh(&ab_pci->window_lock); +- ath11k_pci_select_window(ab_pci, offset); +- val = ioread32(ab->mem + window_start + +- (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); +- spin_unlock_bh(&ab_pci->window_lock); +- } else { +- val = ioread32(ab->mem + window_start + +- (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); +- } +- } +- +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && +- !ret) +- mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); +- +- return val; +-} +- + static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) + { + u32 val, delay; + +- val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); ++ val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); + + val |= PCIE_SOC_GLOBAL_RESET_V; + +- ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); ++ ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); + + /* TODO: exact time to sleep is uncertain */ + delay = 10; +@@ -277,11 +107,11 @@ static void ath11k_pci_soc_global_reset( + /* Need to toggle V bit back otherwise stuck in reset status */ + val &= ~PCIE_SOC_GLOBAL_RESET_V; + +- ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); ++ ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); + + mdelay(delay); + +- val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); ++ val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); + if (val == 0xffffffff) + ath11k_warn(ab, "link down error during global reset\n"); + } +@@ -291,10 +121,10 @@ static void ath11k_pci_clear_dbg_registe + u32 val; + + /* read cookie */ +- val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); ++ val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR); + ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); + +- val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); ++ val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); + ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); + + /* TODO: exact time to sleep is uncertain */ +@@ -303,16 +133,16 @@ static void ath11k_pci_clear_dbg_registe + /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from + * continuing warm path and entering dead loop. + */ +- ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); ++ ath11k_pcic_write32(ab, WLAON_WARM_SW_ENTRY, 0); + mdelay(10); + +- val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); ++ val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); + ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); + + /* A read clear register. clear the register to prevent + * Q6 from entering wrong code path. + */ +- val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); ++ val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG); + ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); + } + +@@ -322,14 +152,14 @@ static int ath11k_pci_set_link_reg(struc + u32 v; + int i; + +- v = ath11k_pci_read32(ab, offset); ++ v = ath11k_pcic_read32(ab, offset); + if ((v & mask) == value) + return 0; + + for (i = 0; i < 10; i++) { +- ath11k_pci_write32(ab, offset, (v & ~mask) | value); ++ ath11k_pcic_write32(ab, offset, (v & ~mask) | value); + +- v = ath11k_pci_read32(ab, offset); ++ v = ath11k_pcic_read32(ab, offset); + if ((v & mask) == value) + return 0; + +@@ -390,23 +220,23 @@ static void ath11k_pci_enable_ltssm(stru + u32 val; + int i; + +- val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); ++ val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); + + /* PCIE link seems very unstable after the Hot Reset*/ + for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { + if (val == 0xffffffff) + mdelay(5); + +- ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); +- val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); ++ ath11k_pcic_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); ++ val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); + } + + ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); + +- val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); ++ val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); + val |= GCC_GCC_PCIE_HOT_RST_VAL; +- ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); +- val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); ++ ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val); ++ val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); + + ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); + +@@ -420,21 +250,21 @@ static void ath11k_pci_clear_all_intrs(s + * So when download SBL again, SBL will open Interrupt and + * receive it, and crash immediately. + */ +- ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); ++ ath11k_pcic_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); + } + + static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) + { + u32 val; + +- val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); ++ val = ath11k_pcic_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); + val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; +- ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); ++ ath11k_pcic_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); + } + + static void ath11k_pci_force_wake(struct ath11k_base *ab) + { +- ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); ++ ath11k_pcic_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); + mdelay(5); + } + +@@ -456,462 +286,6 @@ static void ath11k_pci_sw_reset(struct a + ath11k_mhi_set_mhictrl_reset(ab); + } + +-int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) +-{ +- struct pci_dev *pci_dev = to_pci_dev(dev); +- +- return pci_irq_vector(pci_dev, vector); +-} +- +-void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, +- u32 *msi_addr_hi) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- struct pci_dev *pci_dev = to_pci_dev(ab->dev); +- +- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, +- msi_addr_lo); +- +- if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { +- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, +- msi_addr_hi); +- } else { +- *msi_addr_hi = 0; +- } +-} +- +-int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector) +-{ +- struct ath11k_base *ab = ab_pci->ab; +- const struct ath11k_msi_config *msi_config = ab_pci->msi_config; +- int idx; +- +- for (idx = 0; idx < msi_config->total_users; idx++) { +- if (strcmp(user_name, msi_config->users[idx].name) == 0) { +- *num_vectors = msi_config->users[idx].num_vectors; +- *base_vector = msi_config->users[idx].base_vector; +- *user_base_data = *base_vector + ab_pci->msi_ep_base_data; +- +- ath11k_dbg(ab, ATH11K_DBG_PCI, +- "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", +- user_name, *num_vectors, *user_base_data, +- *base_vector); +- +- return 0; +- } +- } +- +- ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); +- +- return -EINVAL; +-} +- +-void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx) +-{ +- u32 i, msi_data_idx; +- +- for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- +- if (ce_id == i) +- break; +- +- msi_data_idx++; +- } +- *msi_idx = msi_data_idx; +-} +- +-int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- +- return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, +- num_vectors, user_base_data, +- base_vector); +-} +- +-static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) +-{ +- int i, j; +- +- for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { +- struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; +- +- for (j = 0; j < irq_grp->num_irq; j++) +- free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); +- +- netif_napi_del(&irq_grp->napi); +- } +-} +- +-void ath11k_pci_free_irq(struct ath11k_base *ab) +-{ +- int i, irq_idx; +- +- for (i = 0; i < ab->hw_params.ce_count; i++) { +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; +- free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); +- } +- +- ath11k_pci_free_ext_irq(ab); +-} +- +-static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- u32 irq_idx; +- +- /* In case of one MSI vector, we handle irq enable/disable in a +- * uniform way since we only have one irq +- */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- return; +- +- irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; +- enable_irq(ab->irq_num[irq_idx]); +-} +- +-static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- u32 irq_idx; +- +- /* In case of one MSI vector, we handle irq enable/disable in a +- * uniform way since we only have one irq +- */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- return; +- +- irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; +- disable_irq_nosync(ab->irq_num[irq_idx]); +-} +- +-static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) +-{ +- int i; +- +- clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); +- +- for (i = 0; i < ab->hw_params.ce_count; i++) { +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- ath11k_pci_ce_irq_disable(ab, i); +- } +-} +- +-static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) +-{ +- int i; +- int irq_idx; +- +- for (i = 0; i < ab->hw_params.ce_count; i++) { +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- +- irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; +- synchronize_irq(ab->irq_num[irq_idx]); +- } +-} +- +-static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) +-{ +- struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); +- int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; +- +- ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); +- +- enable_irq(ce_pipe->ab->irq_num[irq_idx]); +-} +- +-static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) +-{ +- struct ath11k_ce_pipe *ce_pipe = arg; +- struct ath11k_base *ab = ce_pipe->ab; +- int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; +- +- if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) +- return IRQ_HANDLED; +- +- /* last interrupt received for this CE */ +- ce_pipe->timestamp = jiffies; +- +- disable_irq_nosync(ab->irq_num[irq_idx]); +- +- tasklet_schedule(&ce_pipe->intr_tq); +- +- return IRQ_HANDLED; +-} +- +-static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); +- int i; +- +- /* In case of one MSI vector, we handle irq enable/disable +- * in a uniform way since we only have one irq +- */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- return; +- +- for (i = 0; i < irq_grp->num_irq; i++) +- disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); +-} +- +-static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) +-{ +- int i; +- +- clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); +- +- for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { +- struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; +- +- ath11k_pci_ext_grp_disable(irq_grp); +- +- if (irq_grp->napi_enabled) { +- napi_synchronize(&irq_grp->napi); +- napi_disable(&irq_grp->napi); +- irq_grp->napi_enabled = false; +- } +- } +-} +- +-static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); +- int i; +- +- /* In case of one MSI vector, we handle irq enable/disable in a +- * uniform way since we only have one irq +- */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- return; +- +- for (i = 0; i < irq_grp->num_irq; i++) +- enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); +-} +- +-void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) +-{ +- int i; +- +- set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); +- +- for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { +- struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; +- +- if (!irq_grp->napi_enabled) { +- napi_enable(&irq_grp->napi); +- irq_grp->napi_enabled = true; +- } +- ath11k_pci_ext_grp_enable(irq_grp); +- } +-} +- +-static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) +-{ +- int i, j, irq_idx; +- +- for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { +- struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; +- +- for (j = 0; j < irq_grp->num_irq; j++) { +- irq_idx = irq_grp->irqs[j]; +- synchronize_irq(ab->irq_num[irq_idx]); +- } +- } +-} +- +-void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) +-{ +- __ath11k_pci_ext_irq_disable(ab); +- ath11k_pci_sync_ext_irqs(ab); +-} +- +-static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) +-{ +- struct ath11k_ext_irq_grp *irq_grp = container_of(napi, +- struct ath11k_ext_irq_grp, +- napi); +- struct ath11k_base *ab = irq_grp->ab; +- int work_done; +- int i; +- +- work_done = ath11k_dp_service_srng(ab, irq_grp, budget); +- if (work_done < budget) { +- napi_complete_done(napi, work_done); +- for (i = 0; i < irq_grp->num_irq; i++) +- enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); +- } +- +- if (work_done > budget) +- work_done = budget; +- +- return work_done; +-} +- +-static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) +-{ +- struct ath11k_ext_irq_grp *irq_grp = arg; +- struct ath11k_base *ab = irq_grp->ab; +- int i; +- +- if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) +- return IRQ_HANDLED; +- +- ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); +- +- /* last interrupt received for this group */ +- irq_grp->timestamp = jiffies; +- +- for (i = 0; i < irq_grp->num_irq; i++) +- disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); +- +- napi_schedule(&irq_grp->napi); +- +- return IRQ_HANDLED; +-} +- +-static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- int i, j, ret, num_vectors = 0; +- u32 user_base_data = 0, base_vector = 0; +- +- ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", +- &num_vectors, +- &user_base_data, +- &base_vector); +- if (ret < 0) +- return ret; +- +- for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { +- struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; +- u32 num_irq = 0; +- +- irq_grp->ab = ab; +- irq_grp->grp_id = i; +- init_dummy_netdev(&irq_grp->napi_ndev); +- netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, +- ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); +- +- if (ab->hw_params.ring_mask->tx[i] || +- ab->hw_params.ring_mask->rx[i] || +- ab->hw_params.ring_mask->rx_err[i] || +- ab->hw_params.ring_mask->rx_wbm_rel[i] || +- ab->hw_params.ring_mask->reo_status[i] || +- ab->hw_params.ring_mask->rxdma2host[i] || +- ab->hw_params.ring_mask->host2rxdma[i] || +- ab->hw_params.ring_mask->rx_mon_status[i]) { +- num_irq = 1; +- } +- +- irq_grp->num_irq = num_irq; +- irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; +- +- for (j = 0; j < irq_grp->num_irq; j++) { +- int irq_idx = irq_grp->irqs[j]; +- int vector = (i % num_vectors) + base_vector; +- int irq = ath11k_pci_get_msi_irq(ab->dev, vector); +- +- ab->irq_num[irq_idx] = irq; +- +- ath11k_dbg(ab, ATH11K_DBG_PCI, +- "irq:%d group:%d\n", irq, i); +- +- irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); +- ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, +- ab_pci->irq_flags, +- "DP_EXT_IRQ", irq_grp); +- if (ret) { +- ath11k_err(ab, "failed request irq %d: %d\n", +- vector, ret); +- return ret; +- } +- } +- ath11k_pci_ext_grp_disable(irq_grp); +- } +- +- return 0; +-} +- +-int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, +- const struct cpumask *m) +-{ +- if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- return 0; +- +- return irq_set_affinity_hint(ab_pci->pdev->irq, m); +-} +- +-int ath11k_pci_config_irq(struct ath11k_base *ab) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- struct ath11k_ce_pipe *ce_pipe; +- u32 msi_data_start; +- u32 msi_data_count, msi_data_idx; +- u32 msi_irq_start; +- unsigned int msi_data; +- int irq, i, ret, irq_idx; +- +- ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), +- "CE", &msi_data_count, +- &msi_data_start, &msi_irq_start); +- if (ret) +- return ret; +- +- ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); +- if (ret) { +- ath11k_err(ab, "failed to set irq affinity %d\n", ret); +- return ret; +- } +- +- /* Configure CE irqs */ +- for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- +- msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; +- irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); +- ce_pipe = &ab->ce.ce_pipe[i]; +- +- irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; +- +- tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); +- +- ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, +- ab_pci->irq_flags, irq_name[irq_idx], +- ce_pipe); +- if (ret) { +- ath11k_err(ab, "failed to request irq %d: %d\n", +- irq_idx, ret); +- goto err_irq_affinity_cleanup; +- } +- +- ab->irq_num[irq_idx] = irq; +- msi_data_idx++; +- +- ath11k_pci_ce_irq_disable(ab, i); +- } +- +- ret = ath11k_pci_ext_irq_config(ab); +- if (ret) +- goto err_irq_affinity_cleanup; +- +- return 0; +- +-err_irq_affinity_cleanup: +- ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); +- return ret; +-} +- + static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) + { + struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; +@@ -927,19 +301,6 @@ static void ath11k_pci_init_qmi_ce_confi + &cfg->shadow_reg_v2_len); + } + +-void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) +-{ +- int i; +- +- set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); +- +- for (i = 0; i < ab->hw_params.ce_count; i++) { +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- ath11k_pci_ce_irq_enable(ab, i); +- } +-} +- + static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) + { + struct pci_dev *dev = ab_pci->pdev; +@@ -1139,13 +500,6 @@ static void ath11k_pci_aspm_disable(stru + set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); + } + +-void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) +-{ +- if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) +- pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +- ab_pci->link_ctl); +-} +- + static int ath11k_pci_power_up(struct ath11k_base *ab) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +@@ -1179,7 +533,7 @@ static void ath11k_pci_power_down(struct + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + /* restore aspm in case firmware bootup fails */ +- ath11k_pci_aspm_restore(ab_pci); ++ ath11k_pcic_aspm_restore(ab_pci); + + ath11k_pci_force_wake(ab_pci->ab); + +@@ -1208,130 +562,40 @@ static int ath11k_pci_hif_resume(struct + return 0; + } + +-static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) +-{ +- int i; +- +- for (i = 0; i < ab->hw_params.ce_count; i++) { +- struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; +- +- if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +- continue; +- +- tasklet_kill(&ce_pipe->intr_tq); +- } +-} +- +-void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) +-{ +- ath11k_pci_ce_irqs_disable(ab); +- ath11k_pci_sync_ce_irqs(ab); +- ath11k_pci_kill_tasklets(ab); +-} +- +-void ath11k_pci_stop(struct ath11k_base *ab) +-{ +- ath11k_pci_ce_irq_disable_sync(ab); +- ath11k_ce_cleanup_pipes(ab); +-} +- +-int ath11k_pci_start(struct ath11k_base *ab) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- +- set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); +- +- /* TODO: for now don't restore ASPM in case of single MSI +- * vector as MHI register reading in M2 causes system hang. +- */ +- if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- ath11k_pci_aspm_restore(ab_pci); +- else +- ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); +- +- ath11k_pci_ce_irqs_enable(ab); +- ath11k_ce_rx_post_buf(ab); +- +- return 0; +-} +- + static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) + { +- ath11k_pci_ce_irqs_enable(ab); ++ ath11k_pcic_ce_irqs_enable(ab); + } + + static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) + { +- ath11k_pci_ce_irq_disable_sync(ab); +-} +- +-int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, +- u8 *ul_pipe, u8 *dl_pipe) +-{ +- const struct service_to_pipe *entry; +- bool ul_set = false, dl_set = false; +- int i; +- +- for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { +- entry = &ab->hw_params.svc_to_ce_map[i]; +- +- if (__le32_to_cpu(entry->service_id) != service_id) +- continue; +- +- switch (__le32_to_cpu(entry->pipedir)) { +- case PIPEDIR_NONE: +- break; +- case PIPEDIR_IN: +- WARN_ON(dl_set); +- *dl_pipe = __le32_to_cpu(entry->pipenum); +- dl_set = true; +- break; +- case PIPEDIR_OUT: +- WARN_ON(ul_set); +- *ul_pipe = __le32_to_cpu(entry->pipenum); +- ul_set = true; +- break; +- case PIPEDIR_INOUT: +- WARN_ON(dl_set); +- WARN_ON(ul_set); +- *dl_pipe = __le32_to_cpu(entry->pipenum); +- *ul_pipe = __le32_to_cpu(entry->pipenum); +- dl_set = true; +- ul_set = true; +- break; +- } +- } +- +- if (WARN_ON(!ul_set || !dl_set)) +- return -ENOENT; +- +- return 0; ++ ath11k_pcic_ce_irq_disable_sync(ab); + } + + static const struct ath11k_hif_ops ath11k_pci_hif_ops = { +- .start = ath11k_pci_start, +- .stop = ath11k_pci_stop, +- .read32 = ath11k_pci_read32, +- .write32 = ath11k_pci_write32, ++ .start = ath11k_pcic_start, ++ .stop = ath11k_pcic_stop, ++ .read32 = ath11k_pcic_read32, ++ .write32 = ath11k_pcic_write32, + .power_down = ath11k_pci_power_down, + .power_up = ath11k_pci_power_up, + .suspend = ath11k_pci_hif_suspend, + .resume = ath11k_pci_hif_resume, +- .irq_enable = ath11k_pci_ext_irq_enable, +- .irq_disable = ath11k_pci_ext_irq_disable, +- .get_msi_address = ath11k_pci_get_msi_address, ++ .irq_enable = ath11k_pcic_ext_irq_enable, ++ .irq_disable = ath11k_pcic_ext_irq_disable, ++ .get_msi_address = ath11k_pcic_get_msi_address, + .get_user_msi_vector = ath11k_get_user_msi_assignment, +- .map_service_to_pipe = ath11k_pci_map_service_to_pipe, ++ .map_service_to_pipe = ath11k_pcic_map_service_to_pipe, + .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, + .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, +- .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, ++ .get_ce_msi_idx = ath11k_pcic_get_ce_msi_idx, + }; + + static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) + { + u32 soc_hw_version; + +- soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); ++ soc_hw_version = ath11k_pcic_read32(ab, TCSR_SOC_HW_VERSION); + *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, + soc_hw_version); + *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, +@@ -1473,7 +737,7 @@ unsupported_wcn6855_soc: + + ath11k_pci_init_qmi_ce_config(ab); + +- ret = ath11k_pci_config_irq(ab); ++ ret = ath11k_pcic_config_irq(ab); + if (ret) { + ath11k_err(ab, "failed to config irq: %d\n", ret); + goto err_ce_free; +@@ -1498,7 +762,7 @@ unsupported_wcn6855_soc: + return 0; + + err_free_irq: +- ath11k_pci_free_irq(ab); ++ ath11k_pcic_free_irq(ab); + + err_ce_free: + ath11k_ce_free_pipes(ab); +@@ -1526,7 +790,7 @@ static void ath11k_pci_remove(struct pci + struct ath11k_base *ab = pci_get_drvdata(pdev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + +- ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); ++ ath11k_pcic_set_irq_affinity_hint(ab_pci, NULL); + + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { + ath11k_pci_power_down(ab); +@@ -1542,7 +806,7 @@ static void ath11k_pci_remove(struct pci + qmi_fail: + ath11k_mhi_unregister(ab_pci); + +- ath11k_pci_free_irq(ab); ++ ath11k_pcic_free_irq(ab); + ath11k_pci_free_msi(ab_pci); + ath11k_pci_free_region(ab_pci); + +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -53,21 +53,6 @@ + #define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c + #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 + +-#define ATH11K_PCI_IRQ_CE0_OFFSET 3 +-#define ATH11K_PCI_IRQ_DP_OFFSET 14 +- +-#define ATH11K_PCI_WINDOW_ENABLE_BIT 0x40000000 +-#define ATH11K_PCI_WINDOW_REG_ADDRESS 0x310c +-#define ATH11K_PCI_WINDOW_VALUE_MASK GENMASK(24, 19) +-#define ATH11K_PCI_WINDOW_START 0x80000 +-#define ATH11K_PCI_WINDOW_RANGE_MASK GENMASK(18, 0) +- +-/* BAR0 + 4k is always accessible, and no +- * need to force wakeup. +- * 4K - 32 = 0xFE0 +- */ +-#define ATH11K_PCI_ACCESS_ALWAYS_OFF 0xFE0 +- + struct ath11k_msi_user { + char *name; + int num_vectors; +@@ -113,30 +98,4 @@ static inline struct ath11k_pci *ath11k_ + return (struct ath11k_pci *)ab->drv_priv; + } + +-int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ar_pci, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector); +-int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector); +-void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value); +-u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset); +-void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, +- u32 *msi_addr_hi); +-void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx); +-void ath11k_pci_free_irq(struct ath11k_base *ab); +-int ath11k_pci_config_irq(struct ath11k_base *ab); +-void ath11k_pci_ext_irq_enable(struct ath11k_base *ab); +-void ath11k_pci_ext_irq_disable(struct ath11k_base *ab); +-void ath11k_pci_stop(struct ath11k_base *ab); +-int ath11k_pci_start(struct ath11k_base *ab); +-int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, +- u8 *ul_pipe, u8 *dl_pipe); +-void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab); +-void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab); +-int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector); +-void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci); +-int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, +- const struct cpumask *m); +- + #endif +--- /dev/null ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -0,0 +1,747 @@ ++// SPDX-License-Identifier: BSD-3-Clause-Clear ++/* ++ * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ */ ++ ++#include ++#include "core.h" ++#include "pcic.h" ++#include "debug.h" ++ ++static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { ++ "bhi", ++ "mhi-er0", ++ "mhi-er1", ++ "ce0", ++ "ce1", ++ "ce2", ++ "ce3", ++ "ce4", ++ "ce5", ++ "ce6", ++ "ce7", ++ "ce8", ++ "ce9", ++ "ce10", ++ "ce11", ++ "host2wbm-desc-feed", ++ "host2reo-re-injection", ++ "host2reo-command", ++ "host2rxdma-monitor-ring3", ++ "host2rxdma-monitor-ring2", ++ "host2rxdma-monitor-ring1", ++ "reo2ost-exception", ++ "wbm2host-rx-release", ++ "reo2host-status", ++ "reo2host-destination-ring4", ++ "reo2host-destination-ring3", ++ "reo2host-destination-ring2", ++ "reo2host-destination-ring1", ++ "rxdma2host-monitor-destination-mac3", ++ "rxdma2host-monitor-destination-mac2", ++ "rxdma2host-monitor-destination-mac1", ++ "ppdu-end-interrupts-mac3", ++ "ppdu-end-interrupts-mac2", ++ "ppdu-end-interrupts-mac1", ++ "rxdma2host-monitor-status-ring-mac3", ++ "rxdma2host-monitor-status-ring-mac2", ++ "rxdma2host-monitor-status-ring-mac1", ++ "host2rxdma-host-buf-ring-mac3", ++ "host2rxdma-host-buf-ring-mac2", ++ "host2rxdma-host-buf-ring-mac1", ++ "rxdma2host-destination-ring-mac3", ++ "rxdma2host-destination-ring-mac2", ++ "rxdma2host-destination-ring-mac1", ++ "host2tcl-input-ring4", ++ "host2tcl-input-ring3", ++ "host2tcl-input-ring2", ++ "host2tcl-input-ring1", ++ "wbm2host-tx-completions-ring3", ++ "wbm2host-tx-completions-ring2", ++ "wbm2host-tx-completions-ring1", ++ "tcl2host-status-ring", ++}; ++ ++void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci) ++{ ++ if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) ++ pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, ++ ab_pci->link_ctl); ++} ++ ++static inline void ath11k_pcic_select_window(struct ath11k_pci *ab_pci, u32 offset) ++{ ++ struct ath11k_base *ab = ab_pci->ab; ++ ++ u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); ++ ++ lockdep_assert_held(&ab_pci->window_lock); ++ ++ if (window != ab_pci->register_window) { ++ iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, ++ ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); ++ ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); ++ ab_pci->register_window = window; ++ } ++} ++ ++static inline u32 ath11k_pcic_get_window_start(struct ath11k_base *ab, ++ u32 offset) ++{ ++ u32 window_start; ++ ++ /* If offset lies within DP register range, use 3rd window */ ++ if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK) ++ window_start = 3 * ATH11K_PCI_WINDOW_START; ++ /* If offset lies within CE register range, use 2nd window */ ++ else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < ATH11K_PCI_WINDOW_RANGE_MASK) ++ window_start = 2 * ATH11K_PCI_WINDOW_START; ++ else ++ window_start = ATH11K_PCI_WINDOW_START; ++ ++ return window_start; ++} ++ ++void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ u32 window_start; ++ int ret = 0; ++ ++ /* for offset beyond BAR + 4K - 32, may ++ * need to wakeup MHI to access. ++ */ ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) ++ ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++ ++ if (offset < ATH11K_PCI_WINDOW_START) { ++ iowrite32(value, ab->mem + offset); ++ } else { ++ if (ab->bus_params.static_window_map) ++ window_start = ath11k_pcic_get_window_start(ab, offset); ++ else ++ window_start = ATH11K_PCI_WINDOW_START; ++ ++ if (window_start == ATH11K_PCI_WINDOW_START) { ++ spin_lock_bh(&ab_pci->window_lock); ++ ath11k_pcic_select_window(ab_pci, offset); ++ iowrite32(value, ab->mem + window_start + ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); ++ spin_unlock_bh(&ab_pci->window_lock); ++ } else { ++ iowrite32(value, ab->mem + window_start + ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); ++ } ++ } ++ ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ++ !ret) ++ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); ++} ++ ++u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ u32 val, window_start; ++ int ret = 0; ++ ++ /* for offset beyond BAR + 4K - 32, may ++ * need to wakeup MHI to access. ++ */ ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) ++ ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++ ++ if (offset < ATH11K_PCI_WINDOW_START) { ++ val = ioread32(ab->mem + offset); ++ } else { ++ if (ab->bus_params.static_window_map) ++ window_start = ath11k_pcic_get_window_start(ab, offset); ++ else ++ window_start = ATH11K_PCI_WINDOW_START; ++ ++ if (window_start == ATH11K_PCI_WINDOW_START) { ++ spin_lock_bh(&ab_pci->window_lock); ++ ath11k_pcic_select_window(ab_pci, offset); ++ val = ioread32(ab->mem + window_start + ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); ++ spin_unlock_bh(&ab_pci->window_lock); ++ } else { ++ val = ioread32(ab->mem + window_start + ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); ++ } ++ } ++ ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ++ !ret) ++ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); ++ ++ return val; ++} ++ ++int ath11k_pcic_get_msi_irq(struct device *dev, unsigned int vector) ++{ ++ struct pci_dev *pci_dev = to_pci_dev(dev); ++ ++ return pci_irq_vector(pci_dev, vector); ++} ++ ++void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, ++ u32 *msi_addr_hi) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ struct pci_dev *pci_dev = to_pci_dev(ab->dev); ++ ++ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, ++ msi_addr_lo); ++ ++ if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { ++ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, ++ msi_addr_hi); ++ } else { ++ *msi_addr_hi = 0; ++ } ++} ++ ++int ath11k_pcic_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, ++ int *num_vectors, u32 *user_base_data, ++ u32 *base_vector) ++{ ++ struct ath11k_base *ab = ab_pci->ab; ++ const struct ath11k_msi_config *msi_config = ab_pci->msi_config; ++ int idx; ++ ++ for (idx = 0; idx < msi_config->total_users; idx++) { ++ if (strcmp(user_name, msi_config->users[idx].name) == 0) { ++ *num_vectors = msi_config->users[idx].num_vectors; ++ *base_vector = msi_config->users[idx].base_vector; ++ *user_base_data = *base_vector + ab_pci->msi_ep_base_data; ++ ++ ath11k_dbg(ab, ATH11K_DBG_PCI, ++ "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", ++ user_name, *num_vectors, *user_base_data, ++ *base_vector); ++ ++ return 0; ++ } ++ } ++ ++ ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); ++ ++ return -EINVAL; ++} ++ ++void ath11k_pcic_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx) ++{ ++ u32 i, msi_data_idx; ++ ++ for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ ++ if (ce_id == i) ++ break; ++ ++ msi_data_idx++; ++ } ++ *msi_idx = msi_data_idx; ++} ++ ++int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, ++ int *num_vectors, u32 *user_base_data, ++ u32 *base_vector) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ ++ return ath11k_pcic_get_user_msi_assignment(ab_pci, user_name, ++ num_vectors, user_base_data, ++ base_vector); ++} ++ ++static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab) ++{ ++ int i, j; ++ ++ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { ++ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; ++ ++ for (j = 0; j < irq_grp->num_irq; j++) ++ free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); ++ ++ netif_napi_del(&irq_grp->napi); ++ } ++} ++ ++void ath11k_pcic_free_irq(struct ath11k_base *ab) ++{ ++ int i, irq_idx; ++ ++ for (i = 0; i < ab->hw_params.ce_count; i++) { ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; ++ free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); ++ } ++ ++ ath11k_pcic_free_ext_irq(ab); ++} ++ ++static void ath11k_pcic_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ u32 irq_idx; ++ ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ ++ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; ++ enable_irq(ab->irq_num[irq_idx]); ++} ++ ++static void ath11k_pcic_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ u32 irq_idx; ++ ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ ++ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; ++ disable_irq_nosync(ab->irq_num[irq_idx]); ++} ++ ++static void ath11k_pcic_ce_irqs_disable(struct ath11k_base *ab) ++{ ++ int i; ++ ++ clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); ++ ++ for (i = 0; i < ab->hw_params.ce_count; i++) { ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ ath11k_pcic_ce_irq_disable(ab, i); ++ } ++} ++ ++static void ath11k_pcic_sync_ce_irqs(struct ath11k_base *ab) ++{ ++ int i; ++ int irq_idx; ++ ++ for (i = 0; i < ab->hw_params.ce_count; i++) { ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ ++ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; ++ synchronize_irq(ab->irq_num[irq_idx]); ++ } ++} ++ ++static void ath11k_pcic_ce_tasklet(struct tasklet_struct *t) ++{ ++ struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); ++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ++ ++ ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); ++ ++ enable_irq(ce_pipe->ab->irq_num[irq_idx]); ++} ++ ++static irqreturn_t ath11k_pcic_ce_interrupt_handler(int irq, void *arg) ++{ ++ struct ath11k_ce_pipe *ce_pipe = arg; ++ struct ath11k_base *ab = ce_pipe->ab; ++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ++ ++ if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) ++ return IRQ_HANDLED; ++ ++ /* last interrupt received for this CE */ ++ ce_pipe->timestamp = jiffies; ++ ++ disable_irq_nosync(ab->irq_num[irq_idx]); ++ ++ tasklet_schedule(&ce_pipe->intr_tq); ++ ++ return IRQ_HANDLED; ++} ++ ++static void ath11k_pcic_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); ++ int i; ++ ++ /* In case of one MSI vector, we handle irq enable/disable ++ * in a uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ ++ for (i = 0; i < irq_grp->num_irq; i++) ++ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); ++} ++ ++static void __ath11k_pcic_ext_irq_disable(struct ath11k_base *sc) ++{ ++ int i; ++ ++ clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); ++ ++ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { ++ struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; ++ ++ ath11k_pcic_ext_grp_disable(irq_grp); ++ ++ if (irq_grp->napi_enabled) { ++ napi_synchronize(&irq_grp->napi); ++ napi_disable(&irq_grp->napi); ++ irq_grp->napi_enabled = false; ++ } ++ } ++} ++ ++static void ath11k_pcic_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); ++ int i; ++ ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ ++ for (i = 0; i < irq_grp->num_irq; i++) ++ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); ++} ++ ++void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab) ++{ ++ int i; ++ ++ set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); ++ ++ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { ++ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; ++ ++ if (!irq_grp->napi_enabled) { ++ napi_enable(&irq_grp->napi); ++ irq_grp->napi_enabled = true; ++ } ++ ath11k_pcic_ext_grp_enable(irq_grp); ++ } ++} ++ ++static void ath11k_pcic_sync_ext_irqs(struct ath11k_base *ab) ++{ ++ int i, j, irq_idx; ++ ++ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { ++ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; ++ ++ for (j = 0; j < irq_grp->num_irq; j++) { ++ irq_idx = irq_grp->irqs[j]; ++ synchronize_irq(ab->irq_num[irq_idx]); ++ } ++ } ++} ++ ++void ath11k_pcic_ext_irq_disable(struct ath11k_base *ab) ++{ ++ __ath11k_pcic_ext_irq_disable(ab); ++ ath11k_pcic_sync_ext_irqs(ab); ++} ++ ++static int ath11k_pcic_ext_grp_napi_poll(struct napi_struct *napi, int budget) ++{ ++ struct ath11k_ext_irq_grp *irq_grp = container_of(napi, ++ struct ath11k_ext_irq_grp, ++ napi); ++ struct ath11k_base *ab = irq_grp->ab; ++ int work_done; ++ int i; ++ ++ work_done = ath11k_dp_service_srng(ab, irq_grp, budget); ++ if (work_done < budget) { ++ napi_complete_done(napi, work_done); ++ for (i = 0; i < irq_grp->num_irq; i++) ++ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); ++ } ++ ++ if (work_done > budget) ++ work_done = budget; ++ ++ return work_done; ++} ++ ++static irqreturn_t ath11k_pcic_ext_interrupt_handler(int irq, void *arg) ++{ ++ struct ath11k_ext_irq_grp *irq_grp = arg; ++ struct ath11k_base *ab = irq_grp->ab; ++ int i; ++ ++ if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) ++ return IRQ_HANDLED; ++ ++ ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); ++ ++ /* last interrupt received for this group */ ++ irq_grp->timestamp = jiffies; ++ ++ for (i = 0; i < irq_grp->num_irq; i++) ++ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); ++ ++ napi_schedule(&irq_grp->napi); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ int i, j, ret, num_vectors = 0; ++ u32 user_base_data = 0, base_vector = 0; ++ ++ ret = ath11k_pcic_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", ++ &num_vectors, ++ &user_base_data, ++ &base_vector); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { ++ struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; ++ u32 num_irq = 0; ++ ++ irq_grp->ab = ab; ++ irq_grp->grp_id = i; ++ init_dummy_netdev(&irq_grp->napi_ndev); ++ netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, ++ ath11k_pcic_ext_grp_napi_poll, NAPI_POLL_WEIGHT); ++ ++ if (ab->hw_params.ring_mask->tx[i] || ++ ab->hw_params.ring_mask->rx[i] || ++ ab->hw_params.ring_mask->rx_err[i] || ++ ab->hw_params.ring_mask->rx_wbm_rel[i] || ++ ab->hw_params.ring_mask->reo_status[i] || ++ ab->hw_params.ring_mask->rxdma2host[i] || ++ ab->hw_params.ring_mask->host2rxdma[i] || ++ ab->hw_params.ring_mask->rx_mon_status[i]) { ++ num_irq = 1; ++ } ++ ++ irq_grp->num_irq = num_irq; ++ irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; ++ ++ for (j = 0; j < irq_grp->num_irq; j++) { ++ int irq_idx = irq_grp->irqs[j]; ++ int vector = (i % num_vectors) + base_vector; ++ int irq = ath11k_pcic_get_msi_irq(ab->dev, vector); ++ ++ ab->irq_num[irq_idx] = irq; ++ ++ ath11k_dbg(ab, ATH11K_DBG_PCI, ++ "irq:%d group:%d\n", irq, i); ++ ++ irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); ++ ret = request_irq(irq, ath11k_pcic_ext_interrupt_handler, ++ ab_pci->irq_flags, ++ "DP_EXT_IRQ", irq_grp); ++ if (ret) { ++ ath11k_err(ab, "failed request irq %d: %d\n", ++ vector, ret); ++ return ret; ++ } ++ } ++ ath11k_pcic_ext_grp_disable(irq_grp); ++ } ++ ++ return 0; ++} ++ ++int ath11k_pcic_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m) ++{ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return 0; ++ ++ return irq_set_affinity_hint(ab_pci->pdev->irq, m); ++} ++ ++int ath11k_pcic_config_irq(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ struct ath11k_ce_pipe *ce_pipe; ++ u32 msi_data_start; ++ u32 msi_data_count, msi_data_idx; ++ u32 msi_irq_start; ++ unsigned int msi_data; ++ int irq, i, ret, irq_idx; ++ ++ ret = ath11k_pcic_get_user_msi_assignment(ath11k_pci_priv(ab), ++ "CE", &msi_data_count, ++ &msi_data_start, &msi_irq_start); ++ if (ret) ++ return ret; ++ ++ ret = ath11k_pcic_set_irq_affinity_hint(ab_pci, cpumask_of(0)); ++ if (ret) { ++ ath11k_err(ab, "failed to set irq affinity %d\n", ret); ++ return ret; ++ } ++ ++ /* Configure CE irqs */ ++ for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ ++ msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; ++ irq = ath11k_pcic_get_msi_irq(ab->dev, msi_data); ++ ce_pipe = &ab->ce.ce_pipe[i]; ++ ++ irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; ++ ++ tasklet_setup(&ce_pipe->intr_tq, ath11k_pcic_ce_tasklet); ++ ++ ret = request_irq(irq, ath11k_pcic_ce_interrupt_handler, ++ ab_pci->irq_flags, irq_name[irq_idx], ++ ce_pipe); ++ if (ret) { ++ ath11k_err(ab, "failed to request irq %d: %d\n", ++ irq_idx, ret); ++ goto err_irq_affinity_cleanup; ++ } ++ ++ ab->irq_num[irq_idx] = irq; ++ msi_data_idx++; ++ ++ ath11k_pcic_ce_irq_disable(ab, i); ++ } ++ ++ ret = ath11k_pcic_ext_irq_config(ab); ++ if (ret) ++ goto err_irq_affinity_cleanup; ++ ++ return 0; ++ ++err_irq_affinity_cleanup: ++ ath11k_pcic_set_irq_affinity_hint(ab_pci, NULL); ++ return ret; ++} ++ ++void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab) ++{ ++ int i; ++ ++ set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); ++ ++ for (i = 0; i < ab->hw_params.ce_count; i++) { ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ ath11k_pcic_ce_irq_enable(ab, i); ++ } ++} ++ ++static void ath11k_pcic_kill_tasklets(struct ath11k_base *ab) ++{ ++ int i; ++ ++ for (i = 0; i < ab->hw_params.ce_count; i++) { ++ struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; ++ ++ if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) ++ continue; ++ ++ tasklet_kill(&ce_pipe->intr_tq); ++ } ++} ++ ++void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab) ++{ ++ ath11k_pcic_ce_irqs_disable(ab); ++ ath11k_pcic_sync_ce_irqs(ab); ++ ath11k_pcic_kill_tasklets(ab); ++} ++ ++void ath11k_pcic_stop(struct ath11k_base *ab) ++{ ++ ath11k_pcic_ce_irq_disable_sync(ab); ++ ath11k_ce_cleanup_pipes(ab); ++} ++ ++int ath11k_pcic_start(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ ++ set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); ++ ++ /* TODO: for now don't restore ASPM in case of single MSI ++ * vector as MHI register reading in M2 causes system hang. ++ */ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ ath11k_pcic_aspm_restore(ab_pci); ++ else ++ ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); ++ ++ ath11k_pcic_ce_irqs_enable(ab); ++ ath11k_ce_rx_post_buf(ab); ++ ++ return 0; ++} ++ ++int ath11k_pcic_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, ++ u8 *ul_pipe, u8 *dl_pipe) ++{ ++ const struct service_to_pipe *entry; ++ bool ul_set = false, dl_set = false; ++ int i; ++ ++ for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { ++ entry = &ab->hw_params.svc_to_ce_map[i]; ++ ++ if (__le32_to_cpu(entry->service_id) != service_id) ++ continue; ++ ++ switch (__le32_to_cpu(entry->pipedir)) { ++ case PIPEDIR_NONE: ++ break; ++ case PIPEDIR_IN: ++ WARN_ON(dl_set); ++ *dl_pipe = __le32_to_cpu(entry->pipenum); ++ dl_set = true; ++ break; ++ case PIPEDIR_OUT: ++ WARN_ON(ul_set); ++ *ul_pipe = __le32_to_cpu(entry->pipenum); ++ ul_set = true; ++ break; ++ case PIPEDIR_INOUT: ++ WARN_ON(dl_set); ++ WARN_ON(ul_set); ++ *dl_pipe = __le32_to_cpu(entry->pipenum); ++ *ul_pipe = __le32_to_cpu(entry->pipenum); ++ dl_set = true; ++ ul_set = true; ++ break; ++ } ++ } ++ ++ if (WARN_ON(!ul_set || !dl_set)) ++ return -ENOENT; ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/wireless/ath/ath11k/pcic.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: BSD-3-Clause-Clear */ ++/* ++ * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. ++ */ ++ ++#ifndef _ATH11K_PCI_CMN_H ++#define _ATH11K_PCI_CMN_H ++ ++#include "core.h" ++#include "pci.h" ++ ++#define ATH11K_PCI_IRQ_CE0_OFFSET 3 ++#define ATH11K_PCI_IRQ_DP_OFFSET 14 ++ ++#define ATH11K_PCI_WINDOW_ENABLE_BIT 0x40000000 ++#define ATH11K_PCI_WINDOW_REG_ADDRESS 0x310c ++#define ATH11K_PCI_WINDOW_VALUE_MASK GENMASK(24, 19) ++#define ATH11K_PCI_WINDOW_START 0x80000 ++#define ATH11K_PCI_WINDOW_RANGE_MASK GENMASK(18, 0) ++ ++/* BAR0 + 4k is always accessible, and no ++ * need to force wakeup. ++ * 4K - 32 = 0xFE0 ++ */ ++#define ATH11K_PCI_ACCESS_ALWAYS_OFF 0xFE0 ++ ++int ath11k_pcic_get_user_msi_assignment(struct ath11k_pci *ar_pci, char *user_name, ++ int *num_vectors, u32 *user_base_data, ++ u32 *base_vector); ++int ath11k_pcic_get_msi_irq(struct device *dev, unsigned int vector); ++void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value); ++u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset); ++void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, ++ u32 *msi_addr_hi); ++void ath11k_pcic_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx); ++void ath11k_pcic_free_irq(struct ath11k_base *ab); ++int ath11k_pcic_config_irq(struct ath11k_base *ab); ++void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab); ++void ath11k_pcic_ext_irq_disable(struct ath11k_base *ab); ++void ath11k_pcic_stop(struct ath11k_base *ab); ++int ath11k_pcic_start(struct ath11k_base *ab); ++int ath11k_pcic_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, ++ u8 *ul_pipe, u8 *dl_pipe); ++void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab); ++void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab); ++int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, ++ int *num_vectors, u32 *user_base_data, ++ u32 *base_vector); ++void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci); ++int ath11k_pcic_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m); ++#endif diff --git a/package/kernel/mac80211/patches/ath11k/0217-ath11k-Choose-MSI-config-based-on-HW-revision.patch b/package/kernel/mac80211/patches/ath11k/0217-ath11k-Choose-MSI-config-based-on-HW-revision.patch new file mode 100644 index 000000000..03fdd7eb4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0217-ath11k-Choose-MSI-config-based-on-HW-revision.patch @@ -0,0 +1,184 @@ +From 8d06b8023ace027dc31a9cb3c85c3c8fe83289c5 Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Fri, 1 Apr 2022 14:53:08 +0300 +Subject: [PATCH] ath11k: Choose MSI config based on HW revision + +Instead of selecting MSI config based on magic numbers, make +the assignment based on HW revision. The logic is similar to +the selection of HW params. This improves readability of the +code and also simplifies new additions. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220328055714.6449-4-quic_mpubbise@quicinc.com +--- + drivers/net/wireless/ath/ath11k/pci.c | 31 +++--------- + drivers/net/wireless/ath/ath11k/pci.h | 1 + + drivers/net/wireless/ath/ath11k/pcic.c | 70 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/pcic.h | 1 + + 4 files changed, 78 insertions(+), 25 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -43,28 +43,6 @@ static const struct ath11k_bus_params at + .fixed_mem_region = false, + }; + +-static const struct ath11k_msi_config ath11k_msi_config[] = { +- { +- .total_vectors = 32, +- .total_users = 4, +- .users = (struct ath11k_msi_user[]) { +- { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, +- { .name = "CE", .num_vectors = 10, .base_vector = 3 }, +- { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, +- { .name = "DP", .num_vectors = 18, .base_vector = 14 }, +- }, +- }, +- { +- .total_vectors = 16, +- .total_users = 3, +- .users = (struct ath11k_msi_user[]) { +- { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, +- { .name = "CE", .num_vectors = 5, .base_vector = 3 }, +- { .name = "DP", .num_vectors = 8, .base_vector = 8 }, +- }, +- }, +-}; +- + static const struct ath11k_msi_config msi_config_one_msi = { + .total_vectors = 1, + .total_users = 4, +@@ -667,10 +645,8 @@ static int ath11k_pci_probe(struct pci_d + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } +- ab_pci->msi_config = &ath11k_msi_config[0]; + break; + case QCN9074_DEVICE_ID: +- ab_pci->msi_config = &ath11k_msi_config[1]; + ab->bus_params.static_window_map = true; + ab->hw_rev = ATH11K_HW_QCN9074_HW10; + break; +@@ -700,7 +676,6 @@ unsupported_wcn6855_soc: + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } +- ab_pci->msi_config = &ath11k_msi_config[0]; + break; + default: + dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", +@@ -709,6 +684,12 @@ unsupported_wcn6855_soc: + goto err_pci_free_region; + } + ++ ret = ath11k_pcic_init_msi_config(ab); ++ if (ret) { ++ ath11k_err(ab, "failed to init msi config: %d\n", ret); ++ goto err_pci_free_region; ++ } ++ + ret = ath11k_pci_alloc_msi(ab_pci); + if (ret) { + ath11k_err(ab, "failed to enable msi: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -63,6 +63,7 @@ struct ath11k_msi_config { + int total_vectors; + int total_users; + struct ath11k_msi_user *users; ++ u16 hw_rev; + }; + + enum ath11k_pci_flags { +--- a/drivers/net/wireless/ath/ath11k/pcic.c ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -63,6 +63,76 @@ static const char *irq_name[ATH11K_IRQ_N + "tcl2host-status-ring", + }; + ++static const struct ath11k_msi_config ath11k_msi_config[] = { ++ { ++ .total_vectors = 32, ++ .total_users = 4, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, ++ { .name = "CE", .num_vectors = 10, .base_vector = 3 }, ++ { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, ++ { .name = "DP", .num_vectors = 18, .base_vector = 14 }, ++ }, ++ .hw_rev = ATH11K_HW_QCA6390_HW20, ++ }, ++ { ++ .total_vectors = 16, ++ .total_users = 3, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, ++ { .name = "CE", .num_vectors = 5, .base_vector = 3 }, ++ { .name = "DP", .num_vectors = 8, .base_vector = 8 }, ++ }, ++ .hw_rev = ATH11K_HW_QCN9074_HW10, ++ }, ++ { ++ .total_vectors = 32, ++ .total_users = 4, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, ++ { .name = "CE", .num_vectors = 10, .base_vector = 3 }, ++ { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, ++ { .name = "DP", .num_vectors = 18, .base_vector = 14 }, ++ }, ++ .hw_rev = ATH11K_HW_WCN6855_HW20, ++ }, ++ { ++ .total_vectors = 32, ++ .total_users = 4, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, ++ { .name = "CE", .num_vectors = 10, .base_vector = 3 }, ++ { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, ++ { .name = "DP", .num_vectors = 18, .base_vector = 14 }, ++ }, ++ .hw_rev = ATH11K_HW_WCN6855_HW21, ++ }, ++}; ++ ++int ath11k_pcic_init_msi_config(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ const struct ath11k_msi_config *msi_config; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ath11k_msi_config); i++) { ++ msi_config = &ath11k_msi_config[i]; ++ ++ if (msi_config->hw_rev == ab->hw_rev) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(ath11k_msi_config)) { ++ ath11k_err(ab, "failed to fetch msi config, unsupported hw version: 0x%x\n", ++ ab->hw_rev); ++ return -EINVAL; ++ } ++ ++ ab_pci->msi_config = msi_config; ++ return 0; ++} ++EXPORT_SYMBOL(ath11k_pcic_init_msi_config); ++ + void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci) + { + if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) +--- a/drivers/net/wireless/ath/ath11k/pcic.h ++++ b/drivers/net/wireless/ath/ath11k/pcic.h +@@ -50,4 +50,5 @@ int ath11k_get_user_msi_assignment(struc + void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci); + int ath11k_pcic_set_irq_affinity_hint(struct ath11k_pci *ab_pci, + const struct cpumask *m); ++int ath11k_pcic_init_msi_config(struct ath11k_base *ab); + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0218-ath11k-Refactor-MSI-logic-to-support-WCN6750.patch b/package/kernel/mac80211/patches/ath11k/0218-ath11k-Refactor-MSI-logic-to-support-WCN6750.patch new file mode 100644 index 000000000..30e0e6099 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0218-ath11k-Refactor-MSI-logic-to-support-WCN6750.patch @@ -0,0 +1,299 @@ +From 0cfaf2243e9eef8ed32cdde6467a7e123a9f915f Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Fri, 1 Apr 2022 14:53:08 +0300 +Subject: [PATCH] ath11k: Refactor MSI logic to support WCN6750 + +Refactor MSI logic in order to support hybrid bus devices +like WCN6750. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220328055714.6449-5-quic_mpubbise@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 22 ++++++++++++++ + drivers/net/wireless/ath/ath11k/mhi.c | 3 +- + drivers/net/wireless/ath/ath11k/pci.c | 29 +++++++++++------- + drivers/net/wireless/ath/ath11k/pci.h | 16 ---------- + drivers/net/wireless/ath/ath11k/pcic.c | 41 +++++--------------------- + drivers/net/wireless/ath/ath11k/pcic.h | 5 +--- + 6 files changed, 51 insertions(+), 65 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -769,6 +769,19 @@ struct ath11k_soc_dp_stats { + struct ath11k_dp_ring_bp_stats bp_stats; + }; + ++struct ath11k_msi_user { ++ char *name; ++ int num_vectors; ++ u32 base_vector; ++}; ++ ++struct ath11k_msi_config { ++ int total_vectors; ++ int total_users; ++ struct ath11k_msi_user *users; ++ u16 hw_rev; ++}; ++ + /* Master structure to hold the hw data which may be used in core module */ + struct ath11k_base { + enum ath11k_hw_rev hw_rev; +@@ -905,6 +918,15 @@ struct ath11k_base { + u32 subsystem_device; + } id; + ++ struct { ++ struct { ++ const struct ath11k_msi_config *config; ++ u32 ep_base_data; ++ u32 addr_lo; ++ u32 addr_hi; ++ } msi; ++ } pci; ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -258,8 +258,7 @@ static int ath11k_mhi_get_msi(struct ath + int *irq; + unsigned int msi_data; + +- ret = ath11k_pcic_get_user_msi_assignment(ab_pci, +- "MHI", &num_vectors, ++ ret = ath11k_pcic_get_user_msi_assignment(ab, "MHI", &num_vectors, + &user_base_data, &base_vector); + if (ret) + return ret; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -307,12 +307,13 @@ static void ath11k_pci_msi_disable(struc + static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) + { + struct ath11k_base *ab = ab_pci->ab; +- const struct ath11k_msi_config *msi_config = ab_pci->msi_config; ++ const struct ath11k_msi_config *msi_config = ab->pci.msi.config; ++ struct pci_dev *pci_dev = ab_pci->pdev; + struct msi_desc *msi_desc; + int num_vectors; + int ret; + +- num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, ++ num_vectors = pci_alloc_irq_vectors(pci_dev, + msi_config->total_vectors, + msi_config->total_vectors, + PCI_IRQ_MSI); +@@ -329,7 +330,7 @@ static int ath11k_pci_alloc_msi(struct a + goto reset_msi_config; + } + clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); +- ab_pci->msi_config = &msi_config_one_msi; ++ ab->pci.msi.config = &msi_config_one_msi; + ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); + } +@@ -344,11 +345,19 @@ static int ath11k_pci_alloc_msi(struct a + goto free_msi_vector; + } + +- ab_pci->msi_ep_base_data = msi_desc->msg.data; +- if (msi_desc->msi_attrib.is_64) +- set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); ++ ab->pci.msi.ep_base_data = msi_desc->msg.data; ++ ++ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, ++ &ab->pci.msi.addr_lo); ++ ++ if (msi_desc->msi_attrib.is_64) { ++ pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, ++ &ab->pci.msi.addr_hi); ++ } else { ++ ab->pci.msi.addr_hi = 0; ++ } + +- ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); ++ ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab->pci.msi.ep_base_data); + + return 0; + +@@ -375,10 +384,10 @@ static int ath11k_pci_config_msi_data(st + return -EINVAL; + } + +- ab_pci->msi_ep_base_data = msi_desc->msg.data; ++ ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data; + + ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", +- ab_pci->msi_ep_base_data); ++ ab_pci->ab->pci.msi.ep_base_data); + + return 0; + } +@@ -562,7 +571,7 @@ static const struct ath11k_hif_ops ath11 + .irq_enable = ath11k_pcic_ext_irq_enable, + .irq_disable = ath11k_pcic_ext_irq_disable, + .get_msi_address = ath11k_pcic_get_msi_address, +- .get_user_msi_vector = ath11k_get_user_msi_assignment, ++ .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment, + .map_service_to_pipe = ath11k_pcic_map_service_to_pipe, + .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, + .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -53,22 +53,8 @@ + #define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c + #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 + +-struct ath11k_msi_user { +- char *name; +- int num_vectors; +- u32 base_vector; +-}; +- +-struct ath11k_msi_config { +- int total_vectors; +- int total_users; +- struct ath11k_msi_user *users; +- u16 hw_rev; +-}; +- + enum ath11k_pci_flags { + ATH11K_PCI_FLAG_INIT_DONE, +- ATH11K_PCI_FLAG_IS_MSI_64, + ATH11K_PCI_ASPM_RESTORE, + ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, + }; +@@ -78,9 +64,7 @@ struct ath11k_pci { + struct ath11k_base *ab; + u16 dev_id; + char amss_path[100]; +- u32 msi_ep_base_data; + struct mhi_controller *mhi_ctrl; +- const struct ath11k_msi_config *msi_config; + unsigned long mhi_state; + u32 register_window; + +--- a/drivers/net/wireless/ath/ath11k/pcic.c ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -111,7 +111,6 @@ static const struct ath11k_msi_config at + + int ath11k_pcic_init_msi_config(struct ath11k_base *ab) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + const struct ath11k_msi_config *msi_config; + int i; + +@@ -128,7 +127,7 @@ int ath11k_pcic_init_msi_config(struct a + return -EINVAL; + } + +- ab_pci->msi_config = msi_config; ++ ab->pci.msi.config = msi_config; + return 0; + } + EXPORT_SYMBOL(ath11k_pcic_init_msi_config); +@@ -267,33 +266,22 @@ int ath11k_pcic_get_msi_irq(struct devic + void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, + u32 *msi_addr_hi) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- struct pci_dev *pci_dev = to_pci_dev(ab->dev); +- +- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, +- msi_addr_lo); +- +- if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { +- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, +- msi_addr_hi); +- } else { +- *msi_addr_hi = 0; +- } ++ *msi_addr_lo = ab->pci.msi.addr_lo; ++ *msi_addr_hi = ab->pci.msi.addr_hi; + } + +-int ath11k_pcic_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, ++int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector) + { +- struct ath11k_base *ab = ab_pci->ab; +- const struct ath11k_msi_config *msi_config = ab_pci->msi_config; ++ const struct ath11k_msi_config *msi_config = ab->pci.msi.config; + int idx; + + for (idx = 0; idx < msi_config->total_users; idx++) { + if (strcmp(user_name, msi_config->users[idx].name) == 0) { + *num_vectors = msi_config->users[idx].num_vectors; + *base_vector = msi_config->users[idx].base_vector; +- *user_base_data = *base_vector + ab_pci->msi_ep_base_data; ++ *user_base_data = *base_vector + ab->pci.msi.ep_base_data; + + ath11k_dbg(ab, ATH11K_DBG_PCI, + "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", +@@ -325,17 +313,6 @@ void ath11k_pcic_get_ce_msi_idx(struct a + *msi_idx = msi_data_idx; + } + +-int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector) +-{ +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- +- return ath11k_pcic_get_user_msi_assignment(ab_pci, user_name, +- num_vectors, user_base_data, +- base_vector); +-} +- + static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab) + { + int i, j; +@@ -586,8 +563,7 @@ static int ath11k_pcic_ext_irq_config(st + int i, j, ret, num_vectors = 0; + u32 user_base_data = 0, base_vector = 0; + +- ret = ath11k_pcic_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", +- &num_vectors, ++ ret = ath11k_pcic_get_user_msi_assignment(ab, "DP", &num_vectors, + &user_base_data, + &base_vector); + if (ret < 0) +@@ -662,8 +638,7 @@ int ath11k_pcic_config_irq(struct ath11k + unsigned int msi_data; + int irq, i, ret, irq_idx; + +- ret = ath11k_pcic_get_user_msi_assignment(ath11k_pci_priv(ab), +- "CE", &msi_data_count, ++ ret = ath11k_pcic_get_user_msi_assignment(ab, "CE", &msi_data_count, + &msi_data_start, &msi_irq_start); + if (ret) + return ret; +--- a/drivers/net/wireless/ath/ath11k/pcic.h ++++ b/drivers/net/wireless/ath/ath11k/pcic.h +@@ -25,7 +25,7 @@ + */ + #define ATH11K_PCI_ACCESS_ALWAYS_OFF 0xFE0 + +-int ath11k_pcic_get_user_msi_assignment(struct ath11k_pci *ar_pci, char *user_name, ++int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector); + int ath11k_pcic_get_msi_irq(struct device *dev, unsigned int vector); +@@ -44,9 +44,6 @@ int ath11k_pcic_map_service_to_pipe(stru + u8 *ul_pipe, u8 *dl_pipe); + void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab); + void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab); +-int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, +- int *num_vectors, u32 *user_base_data, +- u32 *base_vector); + void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci); + int ath11k_pcic_set_irq_affinity_hint(struct ath11k_pci *ab_pci, + const struct cpumask *m); diff --git a/package/kernel/mac80211/patches/ath11k/0219-ath11k-Remove-core-PCI-references-from-PCI-common-co.patch b/package/kernel/mac80211/patches/ath11k/0219-ath11k-Remove-core-PCI-references-from-PCI-common-co.patch new file mode 100644 index 000000000..ef7cb1ec8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0219-ath11k-Remove-core-PCI-references-from-PCI-common-co.patch @@ -0,0 +1,845 @@ +From 5b32b6dd966338005671780c1df02327582c4be4 Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Fri, 1 Apr 2022 14:53:08 +0300 +Subject: [PATCH] ath11k: Remove core PCI references from PCI common code + +Remove core PCI and ath11k PCI references(struct ath11k_pci) +from PCI common code. Since, PCI common code will be used +by hybrid bus devices, this code should be independent +from ATH11K PCI references and Linux core PCI references +like struct pci_dev. + +Since this change introduces function callbacks for bus wakeup +and bus release operations, wakeup_mhi HW param is no longer +needed and hence it is removed completely. Alternatively, bus +wakeup/release ops for QCA9074 are initialized to NULL as +QCA9704 does not need bus wakeup/release for register accesses. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220328055714.6449-6-quic_mpubbise@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 - + drivers/net/wireless/ath/ath11k/core.h | 12 ++ + drivers/net/wireless/ath/ath11k/hw.h | 2 +- + drivers/net/wireless/ath/ath11k/mhi.c | 6 +- + drivers/net/wireless/ath/ath11k/pci.c | 146 +++++++++++++++++++-- + drivers/net/wireless/ath/ath11k/pci.h | 5 +- + drivers/net/wireless/ath/ath11k/pcic.c | 169 +++++++++---------------- + drivers/net/wireless/ath/ath11k/pcic.h | 5 - + 8 files changed, 211 insertions(+), 140 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -96,7 +96,6 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, +- .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, +@@ -163,7 +162,6 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, +- .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, +@@ -229,7 +227,6 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, +- .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, +@@ -295,7 +292,6 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, + .alloc_cacheable_memory = true, +- .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, +@@ -361,7 +357,6 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, +- .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, +@@ -426,7 +421,6 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, +- .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -239,6 +239,8 @@ enum ath11k_dev_flags { + ATH11K_FLAG_CE_IRQ_ENABLED, + ATH11K_FLAG_EXT_IRQ_ENABLED, + ATH11K_FLAG_FIXED_MEM_RGN, ++ ATH11K_FLAG_DEVICE_INIT_DONE, ++ ATH11K_FLAG_MULTI_MSI_VECTORS, + }; + + enum ath11k_monitor_flags { +@@ -728,6 +730,14 @@ struct ath11k_bus_params { + bool static_window_map; + }; + ++struct ath11k_pci_ops { ++ int (*wakeup)(struct ath11k_base *ab); ++ void (*release)(struct ath11k_base *ab); ++ int (*get_msi_irq)(struct ath11k_base *ab, unsigned int vector); ++ void (*window_write32)(struct ath11k_base *ab, u32 offset, u32 value); ++ u32 (*window_read32)(struct ath11k_base *ab, u32 offset); ++}; ++ + /* IPQ8074 HW channel counters frequency value in hertz */ + #define IPQ8074_CC_FREQ_HERTZ 320000 + +@@ -925,6 +935,8 @@ struct ath11k_base { + u32 addr_lo; + u32 addr_hi; + } msi; ++ ++ const struct ath11k_pci_ops *ops; + } pci; + + /* must be last */ +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: BSD-3-Clause-Clear */ + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #ifndef ATH11K_HW_H +@@ -189,7 +190,6 @@ struct ath11k_hw_params { + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; + bool alloc_cacheable_memory; +- bool wakeup_mhi; + bool supports_rssi_stats; + bool fw_wmi_diag_event; + bool current_cc_support; +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -273,10 +273,10 @@ static int ath11k_mhi_get_msi(struct ath + for (i = 0; i < num_vectors; i++) { + msi_data = base_vector; + +- if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) + msi_data += i; + +- irq[i] = ath11k_pcic_get_msi_irq(ab->dev, msi_data); ++ irq[i] = ath11k_pci_get_msi_irq(ab, msi_data); + } + + ab_pci->mhi_ctrl->irq = irq; +@@ -408,7 +408,7 @@ int ath11k_mhi_register(struct ath11k_pc + return ret; + } + +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) + mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + + if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -36,6 +36,85 @@ static const struct pci_device_id ath11k + + MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); + ++static int ath11k_pci_bus_wake_up(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ ++ return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++} ++ ++static void ath11k_pci_bus_release(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ ++ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); ++} ++ ++static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) ++{ ++ struct ath11k_base *ab = ab_pci->ab; ++ ++ u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); ++ ++ lockdep_assert_held(&ab_pci->window_lock); ++ ++ if (window != ab_pci->register_window) { ++ iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, ++ ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); ++ ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); ++ ab_pci->register_window = window; ++ } ++} ++ ++static void ++ath11k_pci_window_write32(struct ath11k_base *ab, u32 offset, u32 value) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ u32 window_start = ATH11K_PCI_WINDOW_START; ++ ++ spin_lock_bh(&ab_pci->window_lock); ++ ath11k_pci_select_window(ab_pci, offset); ++ iowrite32(value, ab->mem + window_start + ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); ++ spin_unlock_bh(&ab_pci->window_lock); ++} ++ ++static u32 ath11k_pci_window_read32(struct ath11k_base *ab, u32 offset) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ u32 window_start = ATH11K_PCI_WINDOW_START; ++ u32 val; ++ ++ spin_lock_bh(&ab_pci->window_lock); ++ ath11k_pci_select_window(ab_pci, offset); ++ val = ioread32(ab->mem + window_start + ++ (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); ++ spin_unlock_bh(&ab_pci->window_lock); ++ ++ return val; ++} ++ ++int ath11k_pci_get_msi_irq(struct ath11k_base *ab, unsigned int vector) ++{ ++ struct pci_dev *pci_dev = to_pci_dev(ab->dev); ++ ++ return pci_irq_vector(pci_dev, vector); ++} ++ ++static const struct ath11k_pci_ops ath11k_pci_ops_qca6390 = { ++ .wakeup = ath11k_pci_bus_wake_up, ++ .release = ath11k_pci_bus_release, ++ .get_msi_irq = ath11k_pci_get_msi_irq, ++ .window_write32 = ath11k_pci_window_write32, ++ .window_read32 = ath11k_pci_window_read32, ++}; ++ ++static const struct ath11k_pci_ops ath11k_pci_ops_qcn9074 = { ++ .get_msi_irq = ath11k_pci_get_msi_irq, ++ .window_write32 = ath11k_pci_window_write32, ++ .window_read32 = ath11k_pci_window_read32, ++}; ++ + static const struct ath11k_bus_params ath11k_pci_bus_params = { + .mhi_support = true, + .m3_fw_support = true, +@@ -318,8 +397,7 @@ static int ath11k_pci_alloc_msi(struct a + msi_config->total_vectors, + PCI_IRQ_MSI); + if (num_vectors == msi_config->total_vectors) { +- set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); +- ab_pci->irq_flags = IRQF_SHARED; ++ set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); + } else { + num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, + 1, +@@ -329,9 +407,8 @@ static int ath11k_pci_alloc_msi(struct a + ret = -EINVAL; + goto reset_msi_config; + } +- clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); ++ clear_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); + ab->pci.msi.config = &msi_config_one_msi; +- ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); + } + ath11k_info(ab, "MSI vectors: %d\n", num_vectors); +@@ -487,13 +564,20 @@ static void ath11k_pci_aspm_disable(stru + set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); + } + ++static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) ++{ ++ if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) ++ pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, ++ ab_pci->link_ctl); ++} ++ + static int ath11k_pci_power_up(struct ath11k_base *ab) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + int ret; + + ab_pci->register_window = 0; +- clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); ++ clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); + ath11k_pci_sw_reset(ab_pci->ab, true); + + /* Disable ASPM during firmware download due to problems switching +@@ -520,14 +604,14 @@ static void ath11k_pci_power_down(struct + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + /* restore aspm in case firmware bootup fails */ +- ath11k_pcic_aspm_restore(ab_pci); ++ ath11k_pci_aspm_restore(ab_pci); + + ath11k_pci_force_wake(ab_pci->ab); + + ath11k_pci_msi_disable(ab_pci); + + ath11k_mhi_stop(ab_pci); +- clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); ++ clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); + ath11k_pci_sw_reset(ab_pci->ab, false); + } + +@@ -559,8 +643,25 @@ static void ath11k_pci_hif_ce_irq_disabl + ath11k_pcic_ce_irq_disable_sync(ab); + } + ++static int ath11k_pci_start(struct ath11k_base *ab) ++{ ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ ++ /* TODO: for now don't restore ASPM in case of single MSI ++ * vector as MHI register reading in M2 causes system hang. ++ */ ++ if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) ++ ath11k_pci_aspm_restore(ab_pci); ++ else ++ ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); ++ ++ ath11k_pcic_start(ab); ++ ++ return 0; ++} ++ + static const struct ath11k_hif_ops ath11k_pci_hif_ops = { +- .start = ath11k_pcic_start, ++ .start = ath11k_pci_start, + .stop = ath11k_pcic_stop, + .read32 = ath11k_pcic_read32, + .write32 = ath11k_pcic_write32, +@@ -592,6 +693,15 @@ static void ath11k_pci_read_hw_version(s + *major, *minor); + } + ++static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m) ++{ ++ if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab_pci->ab->dev_flags)) ++ return 0; ++ ++ return irq_set_affinity_hint(ab_pci->pdev->irq, m); ++} ++ + static int ath11k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_dev) + { +@@ -654,9 +764,12 @@ static int ath11k_pci_probe(struct pci_d + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } ++ ++ ab->pci.ops = &ath11k_pci_ops_qca6390; + break; + case QCN9074_DEVICE_ID: + ab->bus_params.static_window_map = true; ++ ab->pci.ops = &ath11k_pci_ops_qcn9074; + ab->hw_rev = ATH11K_HW_QCN9074_HW10; + break; + case WCN6855_DEVICE_ID: +@@ -685,6 +798,8 @@ unsupported_wcn6855_soc: + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } ++ ++ ab->pci.ops = &ath11k_pci_ops_qca6390; + break; + default: + dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", +@@ -733,6 +848,12 @@ unsupported_wcn6855_soc: + goto err_ce_free; + } + ++ ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); ++ if (ret) { ++ ath11k_err(ab, "failed to set irq affinity %d\n", ret); ++ goto err_free_irq; ++ } ++ + /* kernel may allocate a dummy vector before request_irq and + * then allocate a real vector when request_irq is called. + * So get msi_data here again to avoid spurious interrupt +@@ -741,16 +862,19 @@ unsupported_wcn6855_soc: + ret = ath11k_pci_config_msi_data(ab_pci); + if (ret) { + ath11k_err(ab, "failed to config msi_data: %d\n", ret); +- goto err_free_irq; ++ goto err_irq_affinity_cleanup; + } + + ret = ath11k_core_init(ab); + if (ret) { + ath11k_err(ab, "failed to init core: %d\n", ret); +- goto err_free_irq; ++ goto err_irq_affinity_cleanup; + } + return 0; + ++err_irq_affinity_cleanup: ++ ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); ++ + err_free_irq: + ath11k_pcic_free_irq(ab); + +@@ -780,7 +904,7 @@ static void ath11k_pci_remove(struct pci + struct ath11k_base *ab = pci_get_drvdata(pdev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + +- ath11k_pcic_set_irq_affinity_hint(ab_pci, NULL); ++ ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); + + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { + ath11k_pci_power_down(ab); +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -54,9 +54,7 @@ + #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 + + enum ath11k_pci_flags { +- ATH11K_PCI_FLAG_INIT_DONE, + ATH11K_PCI_ASPM_RESTORE, +- ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, + }; + + struct ath11k_pci { +@@ -74,8 +72,6 @@ struct ath11k_pci { + /* enum ath11k_pci_flags */ + unsigned long flags; + u16 link_ctl; +- +- unsigned long irq_flags; + }; + + static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) +@@ -83,4 +79,5 @@ static inline struct ath11k_pci *ath11k_ + return (struct ath11k_pci *)ab->drv_priv; + } + ++int ath11k_pci_get_msi_irq(struct ath11k_base *ab, unsigned int vector); + #endif +--- a/drivers/net/wireless/ath/ath11k/pcic.c ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -4,7 +4,6 @@ + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +-#include + #include "core.h" + #include "pcic.h" + #include "debug.h" +@@ -132,29 +131,6 @@ int ath11k_pcic_init_msi_config(struct a + } + EXPORT_SYMBOL(ath11k_pcic_init_msi_config); + +-void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci) +-{ +- if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) +- pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, +- ab_pci->link_ctl); +-} +- +-static inline void ath11k_pcic_select_window(struct ath11k_pci *ab_pci, u32 offset) +-{ +- struct ath11k_base *ab = ab_pci->ab; +- +- u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); +- +- lockdep_assert_held(&ab_pci->window_lock); +- +- if (window != ab_pci->register_window) { +- iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, +- ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); +- ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); +- ab_pci->register_window = window; +- } +-} +- + static inline u32 ath11k_pcic_get_window_start(struct ath11k_base *ab, + u32 offset) + { +@@ -174,17 +150,15 @@ static inline u32 ath11k_pcic_get_window + + void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 window_start; + int ret = 0; + + /* for offset beyond BAR + 4K - 32, may +- * need to wakeup MHI to access. ++ * need to wakeup the device to access. + */ +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) +- ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++ if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup) ++ ret = ab->pci.ops->wakeup(ab); + + if (offset < ATH11K_PCI_WINDOW_START) { + iowrite32(value, ab->mem + offset); +@@ -194,38 +168,32 @@ void ath11k_pcic_write32(struct ath11k_b + else + window_start = ATH11K_PCI_WINDOW_START; + +- if (window_start == ATH11K_PCI_WINDOW_START) { +- spin_lock_bh(&ab_pci->window_lock); +- ath11k_pcic_select_window(ab_pci, offset); +- iowrite32(value, ab->mem + window_start + +- (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); +- spin_unlock_bh(&ab_pci->window_lock); ++ if (window_start == ATH11K_PCI_WINDOW_START && ++ ab->pci.ops->window_write32) { ++ ab->pci.ops->window_write32(ab, offset, value); + } else { + iowrite32(value, ab->mem + window_start + + (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); + } + } + +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ++ if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release && + !ret) +- mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); ++ ab->pci.ops->release(ab); + } + + u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 val, window_start; + int ret = 0; + + /* for offset beyond BAR + 4K - 32, may +- * need to wakeup MHI to access. ++ * need to wakeup the device to access. + */ +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) +- ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); ++ if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup) ++ ret = ab->pci.ops->wakeup(ab); + + if (offset < ATH11K_PCI_WINDOW_START) { + val = ioread32(ab->mem + offset); +@@ -235,34 +203,23 @@ u32 ath11k_pcic_read32(struct ath11k_bas + else + window_start = ATH11K_PCI_WINDOW_START; + +- if (window_start == ATH11K_PCI_WINDOW_START) { +- spin_lock_bh(&ab_pci->window_lock); +- ath11k_pcic_select_window(ab_pci, offset); +- val = ioread32(ab->mem + window_start + +- (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); +- spin_unlock_bh(&ab_pci->window_lock); ++ if (window_start == ATH11K_PCI_WINDOW_START && ++ ab->pci.ops->window_read32) { ++ val = ab->pci.ops->window_read32(ab, offset); + } else { + val = ioread32(ab->mem + window_start + + (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); + } + } + +- if (ab->hw_params.wakeup_mhi && +- test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && +- offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ++ if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && ++ offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release && + !ret) +- mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); ++ ab->pci.ops->release(ab); + + return val; + } + +-int ath11k_pcic_get_msi_irq(struct device *dev, unsigned int vector) +-{ +- struct pci_dev *pci_dev = to_pci_dev(dev); +- +- return pci_irq_vector(pci_dev, vector); +-} +- + void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, + u32 *msi_addr_hi) + { +@@ -343,13 +300,12 @@ void ath11k_pcic_free_irq(struct ath11k_ + + static void ath11k_pcic_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 irq_idx; + + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) + return; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; +@@ -358,13 +314,12 @@ static void ath11k_pcic_ce_irq_enable(st + + static void ath11k_pcic_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 irq_idx; + + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) + return; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; +@@ -429,13 +384,13 @@ static irqreturn_t ath11k_pcic_ce_interr + + static void ath11k_pcic_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); ++ struct ath11k_base *ab = irq_grp->ab; + int i; + + /* In case of one MSI vector, we handle irq enable/disable + * in a uniform way since we only have one irq + */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) + return; + + for (i = 0; i < irq_grp->num_irq; i++) +@@ -463,13 +418,13 @@ static void __ath11k_pcic_ext_irq_disabl + + static void ath11k_pcic_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); ++ struct ath11k_base *ab = irq_grp->ab; + int i; + + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ +- if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) + return; + + for (i = 0; i < irq_grp->num_irq; i++) +@@ -557,11 +512,22 @@ static irqreturn_t ath11k_pcic_ext_inter + return IRQ_HANDLED; + } + ++static int ++ath11k_pcic_get_msi_irq(struct ath11k_base *ab, unsigned int vector) ++{ ++ if (!ab->pci.ops->get_msi_irq) { ++ WARN_ONCE(1, "get_msi_irq pci op not defined"); ++ return -EOPNOTSUPP; ++ } ++ ++ return ab->pci.ops->get_msi_irq(ab, vector); ++} ++ + static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + int i, j, ret, num_vectors = 0; + u32 user_base_data = 0, base_vector = 0; ++ unsigned long irq_flags; + + ret = ath11k_pcic_get_user_msi_assignment(ab, "DP", &num_vectors, + &user_base_data, +@@ -569,6 +535,10 @@ static int ath11k_pcic_ext_irq_config(st + if (ret < 0) + return ret; + ++ irq_flags = IRQF_SHARED; ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) ++ irq_flags |= IRQF_NOBALANCING; ++ + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + u32 num_irq = 0; +@@ -596,7 +566,10 @@ static int ath11k_pcic_ext_irq_config(st + for (j = 0; j < irq_grp->num_irq; j++) { + int irq_idx = irq_grp->irqs[j]; + int vector = (i % num_vectors) + base_vector; +- int irq = ath11k_pcic_get_msi_irq(ab->dev, vector); ++ int irq = ath11k_pcic_get_msi_irq(ab, vector); ++ ++ if (irq < 0) ++ return irq; + + ab->irq_num[irq_idx] = irq; + +@@ -605,8 +578,7 @@ static int ath11k_pcic_ext_irq_config(st + + irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); + ret = request_irq(irq, ath11k_pcic_ext_interrupt_handler, +- ab_pci->irq_flags, +- "DP_EXT_IRQ", irq_grp); ++ irq_flags, "DP_EXT_IRQ", irq_grp); + if (ret) { + ath11k_err(ab, "failed request irq %d: %d\n", + vector, ret); +@@ -619,35 +591,24 @@ static int ath11k_pcic_ext_irq_config(st + return 0; + } + +-int ath11k_pcic_set_irq_affinity_hint(struct ath11k_pci *ab_pci, +- const struct cpumask *m) +-{ +- if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- return 0; +- +- return irq_set_affinity_hint(ab_pci->pdev->irq, m); +-} +- + int ath11k_pcic_config_irq(struct ath11k_base *ab) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + struct ath11k_ce_pipe *ce_pipe; + u32 msi_data_start; + u32 msi_data_count, msi_data_idx; + u32 msi_irq_start; + unsigned int msi_data; + int irq, i, ret, irq_idx; ++ unsigned long irq_flags; + + ret = ath11k_pcic_get_user_msi_assignment(ab, "CE", &msi_data_count, + &msi_data_start, &msi_irq_start); + if (ret) + return ret; + +- ret = ath11k_pcic_set_irq_affinity_hint(ab_pci, cpumask_of(0)); +- if (ret) { +- ath11k_err(ab, "failed to set irq affinity %d\n", ret); +- return ret; +- } ++ irq_flags = IRQF_SHARED; ++ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) ++ irq_flags |= IRQF_NOBALANCING; + + /* Configure CE irqs */ + for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { +@@ -655,7 +616,10 @@ int ath11k_pcic_config_irq(struct ath11k + continue; + + msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; +- irq = ath11k_pcic_get_msi_irq(ab->dev, msi_data); ++ irq = ath11k_pcic_get_msi_irq(ab, msi_data); ++ if (irq < 0) ++ return irq; ++ + ce_pipe = &ab->ce.ce_pipe[i]; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; +@@ -663,12 +627,11 @@ int ath11k_pcic_config_irq(struct ath11k + tasklet_setup(&ce_pipe->intr_tq, ath11k_pcic_ce_tasklet); + + ret = request_irq(irq, ath11k_pcic_ce_interrupt_handler, +- ab_pci->irq_flags, irq_name[irq_idx], +- ce_pipe); ++ irq_flags, irq_name[irq_idx], ce_pipe); + if (ret) { + ath11k_err(ab, "failed to request irq %d: %d\n", + irq_idx, ret); +- goto err_irq_affinity_cleanup; ++ return ret; + } + + ab->irq_num[irq_idx] = irq; +@@ -679,13 +642,9 @@ int ath11k_pcic_config_irq(struct ath11k + + ret = ath11k_pcic_ext_irq_config(ab); + if (ret) +- goto err_irq_affinity_cleanup; ++ return ret; + + return 0; +- +-err_irq_affinity_cleanup: +- ath11k_pcic_set_irq_affinity_hint(ab_pci, NULL); +- return ret; + } + + void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab) +@@ -730,17 +689,7 @@ void ath11k_pcic_stop(struct ath11k_base + + int ath11k_pcic_start(struct ath11k_base *ab) + { +- struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +- +- set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); +- +- /* TODO: for now don't restore ASPM in case of single MSI +- * vector as MHI register reading in M2 causes system hang. +- */ +- if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) +- ath11k_pcic_aspm_restore(ab_pci); +- else +- ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); ++ set_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); + + ath11k_pcic_ce_irqs_enable(ab); + ath11k_ce_rx_post_buf(ab); +--- a/drivers/net/wireless/ath/ath11k/pcic.h ++++ b/drivers/net/wireless/ath/ath11k/pcic.h +@@ -8,7 +8,6 @@ + #define _ATH11K_PCI_CMN_H + + #include "core.h" +-#include "pci.h" + + #define ATH11K_PCI_IRQ_CE0_OFFSET 3 + #define ATH11K_PCI_IRQ_DP_OFFSET 14 +@@ -28,7 +27,6 @@ + int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector); +-int ath11k_pcic_get_msi_irq(struct device *dev, unsigned int vector); + void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value); + u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset); + void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, +@@ -44,8 +42,5 @@ int ath11k_pcic_map_service_to_pipe(stru + u8 *ul_pipe, u8 *dl_pipe); + void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab); + void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab); +-void ath11k_pcic_aspm_restore(struct ath11k_pci *ab_pci); +-int ath11k_pcic_set_irq_affinity_hint(struct ath11k_pci *ab_pci, +- const struct cpumask *m); + int ath11k_pcic_init_msi_config(struct ath11k_base *ab); + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0220-ath11k-Change-max-no-of-active-probe-SSID-and-BSSID-.patch b/package/kernel/mac80211/patches/ath11k/0220-ath11k-Change-max-no-of-active-probe-SSID-and-BSSID-.patch new file mode 100644 index 000000000..98259dbb1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0220-ath11k-Change-max-no-of-active-probe-SSID-and-BSSID-.patch @@ -0,0 +1,70 @@ +From 50dc9ce9f80554a88e33b73c30851acf2be36ed3 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Kathirvel +Date: Fri, 1 Apr 2022 14:53:09 +0300 +Subject: [PATCH] ath11k: Change max no of active probe SSID and BSSID to fw + capability + +The maximum number of SSIDs in a for active probe requests is currently +reported as 16 (WLAN_SCAN_PARAMS_MAX_SSID) when registering the driver. +The scan_req_params structure only has the capacity to hold 10 SSIDs. +This leads to a buffer overflow which can be triggered from +wpa_supplicant in userspace. When copying the SSIDs into the +scan_req_params structure in the ath11k_mac_op_hw_scan route, it can +overwrite the extraie pointer. + +Firmware supports 16 ssid * 4 bssid, for each ssid 4 bssid combo probe +request will be sent, so totally 64 probe requests supported. So +set both max ssid and bssid to 16 and 4 respectively. Remove the +redundant macros of ssid and bssid. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01300-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Kathirvel +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220329150221.21907-1-quic_kathirve@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.h | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3089,9 +3089,6 @@ enum scan_dwelltime_adaptive_mode { + SCAN_DWELL_MODE_STATIC = 4 + }; + +-#define WLAN_SCAN_MAX_NUM_SSID 10 +-#define WLAN_SCAN_MAX_NUM_BSSID 10 +- + #define WLAN_SSID_MAX_LEN 32 + + struct element_info { +@@ -3106,7 +3103,6 @@ struct wlan_ssid { + + #define WMI_IE_BITMAP_SIZE 8 + +-#define WMI_SCAN_MAX_NUM_SSID 0x0A + /* prefix used by scan requestor ids on the host */ + #define WMI_HOST_SCAN_REQUESTOR_ID_PREFIX 0xA000 + +@@ -3114,10 +3110,6 @@ struct wlan_ssid { + /* host cycles through the lower 12 bits to generate ids */ + #define WMI_HOST_SCAN_REQ_ID_PREFIX 0xA000 + +-#define WLAN_SCAN_PARAMS_MAX_SSID 16 +-#define WLAN_SCAN_PARAMS_MAX_BSSID 4 +-#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +- + /* Values lower than this may be refused by some firmware revisions with a scan + * completion with a timedout reason. + */ +@@ -3313,8 +3305,8 @@ struct scan_req_params { + u32 n_probes; + u32 *chan_list; + u32 notify_scan_events; +- struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID]; +- struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID]; ++ struct wlan_ssid ssid[WLAN_SCAN_PARAMS_MAX_SSID]; ++ struct wmi_mac_addr bssid_list[WLAN_SCAN_PARAMS_MAX_BSSID]; + struct element_info extraie; + struct element_info htcap; + struct element_info vhtcap; diff --git a/package/kernel/mac80211/patches/ath11k/0221-ath11k-Remove-unnecessary-delay-in-ath11k_core_suspe.patch b/package/kernel/mac80211/patches/ath11k/0221-ath11k-Remove-unnecessary-delay-in-ath11k_core_suspe.patch new file mode 100644 index 000000000..34d1a4875 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0221-ath11k-Remove-unnecessary-delay-in-ath11k_core_suspe.patch @@ -0,0 +1,36 @@ +From 2dd398dee7aa5ec6b296d9915bbb1c1a76199b4a Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Fri, 1 Apr 2022 14:53:10 +0300 +Subject: [PATCH] ath11k: Remove unnecessary delay in ath11k_core_suspend + +The intended delay in ath11k_core_suspend is introduced in commit +d1b0c33850d2 ("ath11k: implement suspend for QCA6390 PCI devices"), +now with ath11k_mac_wait_tx_complete added in commit ba9177fcef21 +("ath11k: Add basic WoW functionalities"), that delay is not +necessary now, so remove it. + +This is found in code review. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02431-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220331002105.1162099-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -453,11 +453,6 @@ int ath11k_core_suspend(struct ath11k_ba + if (!ar || ar->state != ATH11K_STATE_OFF) + return 0; + +- /* TODO: there can frames in queues so for now add delay as a hack. +- * Need to implement to handle and remove this delay. +- */ +- msleep(500); +- + ret = ath11k_dp_rx_pktlog_stop(ab, true); + if (ret) { + ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n", diff --git a/package/kernel/mac80211/patches/ath11k/0222-ath11k-fix-driver-initialization-failure-with-WoW-un.patch b/package/kernel/mac80211/patches/ath11k/0222-ath11k-fix-driver-initialization-failure-with-WoW-un.patch new file mode 100644 index 000000000..374d3d70b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0222-ath11k-fix-driver-initialization-failure-with-WoW-un.patch @@ -0,0 +1,72 @@ +From 633469e3bac10650ecff421ba6b9603d67da884b Mon Sep 17 00:00:00 2001 +From: Nagarajan Maran +Date: Fri, 1 Apr 2022 14:53:10 +0300 +Subject: [PATCH] ath11k: fix driver initialization failure with WoW + unsupported hw + +In the "ath11k_wow_init", error value "EINVAL" is returned +when the check for firmware support of WoW feature fails, +which in turn stops the driver initialization. + +Warning message: +[ 31.040144] ------------[ cut here ]------------ +[ 31.040185] WARNING: CPU: 1 PID: 51 at drivers/net/wireless/ath/ath11k/wow.c:813 ath11k_wow_init+0xc8/0x13a8 [ath11k] +[ 31.043846] Modules linked in: ath11k_pci ath11k qmi_helpers +[ 31.054341] CPU: 1 PID: 51 Comm: kworker/u8:1 Tainted: G W 5.17.0-wt-ath-594817-ga7f6aa925cf8-dirty #17 +[ 31.060078] Hardware name: Qualcomm Technologies, Inc. IPQ8074/AP-HK10-C2 (DT) +[ 31.070578] Workqueue: ath11k_qmi_driver_event ath11k_qmi_driver_event_work [ath11k] +[ 31.077782] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 31.085676] pc : ath11k_wow_init+0xc8/0x13a8 [ath11k] +[ 31.092359] lr : ath11k_mac_register+0x548/0xb98 [ath11k] +[ 31.097567] sp : ffff80000aa13c40 +[ 31.102944] x29: ffff80000aa13c40 x28: ffff800009184390 x27: ffff000002959f20 +[ 31.106251] x26: ffff000002828000 x25: ffff000002830000 x24: ffff000002830000 +[ 31.113369] x23: ffff000002820000 x22: ffff00000282854c x21: 0000000000000000 +[ 31.120487] x20: ffff00000295cf20 x19: ffff000002828540 x18: 0000000000000031 +[ 31.127605] x17: 0000000000000004 x16: ffff0000028285fc x15: ffff00000295b040 +[ 31.134723] x14: 0000000000000067 x13: ffff00000282859c x12: 000000000000000d +[ 31.141840] x11: 0000000000000018 x10: 0000000000000004 x9 : 0000000000000000 +[ 31.148959] x8 : ffff00000289d680 x7 : 0000000000000000 x6 : 000000000000003f +[ 31.156077] x5 : 0000000000000040 x4 : 0000000000000000 x3 : ffff000002820968 +[ 31.163196] x2 : 0000000000000080 x1 : 0080008af9981779 x0 : ffff000002959f20 +[ 31.170314] Call trace: +[ 31.177421] ath11k_wow_init+0xc8/0x13a8 [ath11k] +[ 31.179684] ath11k_core_qmi_firmware_ready+0x430/0x5e0 [ath11k] +[ 31.184548] ath11k_qmi_driver_event_work+0x16c/0x4f8 [ath11k] +[ 31.190623] process_one_work+0x134/0x350 +[ 31.196262] worker_thread+0x12c/0x450 +[ 31.200340] kthread+0xf4/0x110 +[ 31.203986] ret_from_fork+0x10/0x20 +[ 31.207026] ---[ end trace 0000000000000000 ]--- +[ 31.210894] ath11k_pci 0000:01:00.0: failed to init wow: -22 +[ 31.215467] ath11k_pci 0000:01:00.0: failed register the radio with mac80211: -22 +[ 31.221117] ath11k_pci 0000:01:00.0: failed to create pdev core: -22 + +Fix this by returning value "0" when FW doesn't support WoW +to allow driver to proceed with initialize sequence and also +remove the unnecessary "WARN_ON". + + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Fixes: ba9177fcef21 ("ath11k: Add basic WoW functionalities") +Signed-off-by: Nagarajan Maran +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220331073110.3846-1-quic_nmaran@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wow.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wow.c ++++ b/drivers/net/wireless/ath/ath11k/wow.c +@@ -810,8 +810,8 @@ exit: + + int ath11k_wow_init(struct ath11k *ar) + { +- if (WARN_ON(!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map))) +- return -EINVAL; ++ if (!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map)) ++ return 0; + + ar->wow.wowlan_support = ath11k_wowlan_support; + diff --git a/package/kernel/mac80211/patches/ath11k/0223-ath11k-mhi-remove-state-machine.patch b/package/kernel/mac80211/patches/ath11k/0223-ath11k-mhi-remove-state-machine.patch new file mode 100644 index 000000000..0ddec2ffe --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0223-ath11k-mhi-remove-state-machine.patch @@ -0,0 +1,278 @@ +From 121210ec935c47b076709974d95360f5e9c9b869 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Fri, 1 Apr 2022 20:30:40 +0300 +Subject: [PATCH] ath11k: mhi: remove state machine + +State machines are difficult to understand and in this case it's just useless, +which is shown by the diffstat. So remove it entirely to make the code simpler. + +No functional changes. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220401173042.17467-2-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 194 ++------------------------ + drivers/net/wireless/ath/ath11k/mhi.h | 13 -- + drivers/net/wireless/ath/ath11k/pci.h | 2 +- + 3 files changed, 11 insertions(+), 198 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -465,195 +465,17 @@ void ath11k_mhi_unregister(struct ath11k + mhi_free_controller(mhi_ctrl); + } + +-static char *ath11k_mhi_state_to_str(enum ath11k_mhi_state mhi_state) +-{ +- switch (mhi_state) { +- case ATH11K_MHI_INIT: +- return "INIT"; +- case ATH11K_MHI_DEINIT: +- return "DEINIT"; +- case ATH11K_MHI_POWER_ON: +- return "POWER_ON"; +- case ATH11K_MHI_POWER_OFF: +- return "POWER_OFF"; +- case ATH11K_MHI_FORCE_POWER_OFF: +- return "FORCE_POWER_OFF"; +- case ATH11K_MHI_SUSPEND: +- return "SUSPEND"; +- case ATH11K_MHI_RESUME: +- return "RESUME"; +- case ATH11K_MHI_TRIGGER_RDDM: +- return "TRIGGER_RDDM"; +- case ATH11K_MHI_RDDM_DONE: +- return "RDDM_DONE"; +- default: +- return "UNKNOWN"; +- } +-}; +- +-static void ath11k_mhi_set_state_bit(struct ath11k_pci *ab_pci, +- enum ath11k_mhi_state mhi_state) +-{ +- struct ath11k_base *ab = ab_pci->ab; +- +- switch (mhi_state) { +- case ATH11K_MHI_INIT: +- set_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_DEINIT: +- clear_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_POWER_ON: +- set_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_POWER_OFF: +- case ATH11K_MHI_FORCE_POWER_OFF: +- clear_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state); +- clear_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); +- clear_bit(ATH11K_MHI_RDDM_DONE, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_SUSPEND: +- set_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_RESUME: +- clear_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_TRIGGER_RDDM: +- set_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); +- break; +- case ATH11K_MHI_RDDM_DONE: +- set_bit(ATH11K_MHI_RDDM_DONE, &ab_pci->mhi_state); +- break; +- default: +- ath11k_err(ab, "unhandled mhi state (%d)\n", mhi_state); +- } +-} +- +-static int ath11k_mhi_check_state_bit(struct ath11k_pci *ab_pci, +- enum ath11k_mhi_state mhi_state) +-{ +- struct ath11k_base *ab = ab_pci->ab; +- +- switch (mhi_state) { +- case ATH11K_MHI_INIT: +- if (!test_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state)) +- return 0; +- break; +- case ATH11K_MHI_DEINIT: +- case ATH11K_MHI_POWER_ON: +- if (test_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state) && +- !test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state)) +- return 0; +- break; +- case ATH11K_MHI_FORCE_POWER_OFF: +- if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state)) +- return 0; +- break; +- case ATH11K_MHI_POWER_OFF: +- case ATH11K_MHI_SUSPEND: +- if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state) && +- !test_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state)) +- return 0; +- break; +- case ATH11K_MHI_RESUME: +- if (test_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state)) +- return 0; +- break; +- case ATH11K_MHI_TRIGGER_RDDM: +- if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state) && +- !test_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state)) +- return 0; +- break; +- case ATH11K_MHI_RDDM_DONE: +- return 0; +- default: +- ath11k_err(ab, "unhandled mhi state: %s(%d)\n", +- ath11k_mhi_state_to_str(mhi_state), mhi_state); +- } +- +- ath11k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n", +- ath11k_mhi_state_to_str(mhi_state), mhi_state, +- ab_pci->mhi_state); +- +- return -EINVAL; +-} +- +-static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci, +- enum ath11k_mhi_state mhi_state) +-{ +- struct ath11k_base *ab = ab_pci->ab; +- int ret; +- +- ret = ath11k_mhi_check_state_bit(ab_pci, mhi_state); +- if (ret) +- goto out; +- +- ath11k_dbg(ab, ATH11K_DBG_PCI, "setting mhi state: %s(%d)\n", +- ath11k_mhi_state_to_str(mhi_state), mhi_state); +- +- switch (mhi_state) { +- case ATH11K_MHI_INIT: +- ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); +- break; +- case ATH11K_MHI_DEINIT: +- mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); +- ret = 0; +- break; +- case ATH11K_MHI_POWER_ON: +- ret = mhi_sync_power_up(ab_pci->mhi_ctrl); +- break; +- case ATH11K_MHI_POWER_OFF: +- mhi_power_down(ab_pci->mhi_ctrl, true); +- ret = 0; +- break; +- case ATH11K_MHI_FORCE_POWER_OFF: +- mhi_power_down(ab_pci->mhi_ctrl, false); +- ret = 0; +- break; +- case ATH11K_MHI_SUSPEND: +- ret = mhi_pm_suspend(ab_pci->mhi_ctrl); +- break; +- case ATH11K_MHI_RESUME: +- /* Do force MHI resume as some devices like QCA6390, WCN6855 +- * are not in M3 state but they are functional. So just ignore +- * the MHI state while resuming. +- */ +- ret = mhi_pm_resume_force(ab_pci->mhi_ctrl); +- break; +- case ATH11K_MHI_TRIGGER_RDDM: +- ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); +- break; +- case ATH11K_MHI_RDDM_DONE: +- break; +- default: +- ath11k_err(ab, "unhandled MHI state (%d)\n", mhi_state); +- ret = -EINVAL; +- } +- +- if (ret) +- goto out; +- +- ath11k_mhi_set_state_bit(ab_pci, mhi_state); +- +- return 0; +- +-out: +- ath11k_err(ab, "failed to set mhi state: %s(%d)\n", +- ath11k_mhi_state_to_str(mhi_state), mhi_state); +- return ret; +-} +- + int ath11k_mhi_start(struct ath11k_pci *ab_pci) + { + int ret; + + ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS; + +- ret = ath11k_mhi_set_state(ab_pci, ATH11K_MHI_INIT); ++ ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); + if (ret) + goto out; + +- ret = ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_ON); ++ ret = mhi_sync_power_up(ab_pci->mhi_ctrl); + if (ret) + goto out; + +@@ -665,16 +487,20 @@ out: + + void ath11k_mhi_stop(struct ath11k_pci *ab_pci) + { +- ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_OFF); +- ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT); ++ mhi_power_down(ab_pci->mhi_ctrl, true); ++ mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); + } + + void ath11k_mhi_suspend(struct ath11k_pci *ab_pci) + { +- ath11k_mhi_set_state(ab_pci, ATH11K_MHI_SUSPEND); ++ mhi_pm_suspend(ab_pci->mhi_ctrl); + } + + void ath11k_mhi_resume(struct ath11k_pci *ab_pci) + { +- ath11k_mhi_set_state(ab_pci, ATH11K_MHI_RESUME); ++ /* Do force MHI resume as some devices like QCA6390, WCN6855 ++ * are not in M3 state but they are functional. So just ignore ++ * the MHI state while resuming. ++ */ ++ mhi_pm_resume_force(ab_pci->mhi_ctrl); + } +--- a/drivers/net/wireless/ath/ath11k/mhi.h ++++ b/drivers/net/wireless/ath/ath11k/mhi.h +@@ -16,19 +16,6 @@ + #define MHICTRL 0x38 + #define MHICTRL_RESET_MASK 0x2 + +-enum ath11k_mhi_state { +- ATH11K_MHI_INIT, +- ATH11K_MHI_DEINIT, +- ATH11K_MHI_POWER_ON, +- ATH11K_MHI_POWER_OFF, +- ATH11K_MHI_FORCE_POWER_OFF, +- ATH11K_MHI_SUSPEND, +- ATH11K_MHI_RESUME, +- ATH11K_MHI_TRIGGER_RDDM, +- ATH11K_MHI_RDDM, +- ATH11K_MHI_RDDM_DONE, +-}; +- + int ath11k_mhi_start(struct ath11k_pci *ar_pci); + void ath11k_mhi_stop(struct ath11k_pci *ar_pci); + int ath11k_mhi_register(struct ath11k_pci *ar_pci); +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -63,7 +63,7 @@ struct ath11k_pci { + u16 dev_id; + char amss_path[100]; + struct mhi_controller *mhi_ctrl; +- unsigned long mhi_state; ++ const struct ath11k_msi_config *msi_config; + u32 register_window; + + /* protects register_window above */ diff --git a/package/kernel/mac80211/patches/ath11k/0224-ath11k-mhi-add-error-handling-for-suspend-and-resume.patch b/package/kernel/mac80211/patches/ath11k/0224-ath11k-mhi-add-error-handling-for-suspend-and-resume.patch new file mode 100644 index 000000000..ae60753ba --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0224-ath11k-mhi-add-error-handling-for-suspend-and-resume.patch @@ -0,0 +1,95 @@ +From 3e80fcbca37221cd1e5a33eea4b0f215f66a7a00 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Tue, 5 Apr 2022 11:26:39 +0300 +Subject: [PATCH] ath11k: mhi: add error handling for suspend and resume + +While reviewing the mhi.c I noticed we were just ignoring the errors coming +from MHI subsystem during suspend and resume. Add proper checks and warning +messages. Also pass the error value to callers. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220401173042.17467-3-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 26 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/mhi.h | 4 ++-- + drivers/net/wireless/ath/ath11k/pci.c | 8 ++------ + 3 files changed, 26 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -491,16 +491,34 @@ void ath11k_mhi_stop(struct ath11k_pci * + mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); + } + +-void ath11k_mhi_suspend(struct ath11k_pci *ab_pci) ++int ath11k_mhi_suspend(struct ath11k_pci *ab_pci) + { +- mhi_pm_suspend(ab_pci->mhi_ctrl); ++ struct ath11k_base *ab = ab_pci->ab; ++ int ret; ++ ++ ret = mhi_pm_suspend(ab_pci->mhi_ctrl); ++ if (ret) { ++ ath11k_warn(ab, "failed to suspend mhi: %d", ret); ++ return ret; ++ } ++ ++ return 0; + } + +-void ath11k_mhi_resume(struct ath11k_pci *ab_pci) ++int ath11k_mhi_resume(struct ath11k_pci *ab_pci) + { ++ struct ath11k_base *ab = ab_pci->ab; ++ int ret; ++ + /* Do force MHI resume as some devices like QCA6390, WCN6855 + * are not in M3 state but they are functional. So just ignore + * the MHI state while resuming. + */ +- mhi_pm_resume_force(ab_pci->mhi_ctrl); ++ ret = mhi_pm_resume_force(ab_pci->mhi_ctrl); ++ if (ret) { ++ ath11k_warn(ab, "failed to resume mhi: %d", ret); ++ return ret; ++ } ++ ++ return 0; + } +--- a/drivers/net/wireless/ath/ath11k/mhi.h ++++ b/drivers/net/wireless/ath/ath11k/mhi.h +@@ -23,7 +23,7 @@ void ath11k_mhi_unregister(struct ath11k + void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab); + void ath11k_mhi_clear_vector(struct ath11k_base *ab); + +-void ath11k_mhi_suspend(struct ath11k_pci *ar_pci); +-void ath11k_mhi_resume(struct ath11k_pci *ar_pci); ++int ath11k_mhi_suspend(struct ath11k_pci *ar_pci); ++int ath11k_mhi_resume(struct ath11k_pci *ar_pci); + + #endif +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -619,18 +619,14 @@ static int ath11k_pci_hif_suspend(struct + { + struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); + +- ath11k_mhi_suspend(ar_pci); +- +- return 0; ++ return ath11k_mhi_suspend(ar_pci); + } + + static int ath11k_pci_hif_resume(struct ath11k_base *ab) + { + struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); + +- ath11k_mhi_resume(ar_pci); +- +- return 0; ++ return ath11k_mhi_resume(ar_pci); + } + + static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) diff --git a/package/kernel/mac80211/patches/ath11k/0225-ath11k-mhi-remove-unnecessary-goto-from-ath11k_mhi_s.patch b/package/kernel/mac80211/patches/ath11k/0225-ath11k-mhi-remove-unnecessary-goto-from-ath11k_mhi_s.patch new file mode 100644 index 000000000..362a0fc53 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0225-ath11k-mhi-remove-unnecessary-goto-from-ath11k_mhi_s.patch @@ -0,0 +1,52 @@ +From b9e34ba6b314780a47ac40f450ec04f18be85b5e Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Tue, 5 Apr 2022 11:26:44 +0300 +Subject: [PATCH] ath11k: mhi: remove unnecessary goto from ath11k_mhi_start() + +No need to have goto for a return statement, so simplify the code. While at it, +print warning messages if power up calls fail. + +No functional changes. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220401173042.17467-4-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -467,22 +467,24 @@ void ath11k_mhi_unregister(struct ath11k + + int ath11k_mhi_start(struct ath11k_pci *ab_pci) + { ++ struct ath11k_base *ab = ab_pci->ab; + int ret; + + ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS; + + ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); +- if (ret) +- goto out; ++ if (ret) { ++ ath11k_warn(ab, "failed to prepare mhi: %d", ret); ++ return ret; ++ } + + ret = mhi_sync_power_up(ab_pci->mhi_ctrl); +- if (ret) +- goto out; ++ if (ret) { ++ ath11k_warn(ab, "failed to power up mhi: %d", ret); ++ return ret; ++ } + + return 0; +- +-out: +- return ret; + } + + void ath11k_mhi_stop(struct ath11k_pci *ab_pci) diff --git a/package/kernel/mac80211/patches/ath11k/0226-ath11k-Fix-spelling-mistake-reseting-resetting.patch b/package/kernel/mac80211/patches/ath11k/0226-ath11k-Fix-spelling-mistake-reseting-resetting.patch new file mode 100644 index 000000000..057cc9e68 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0226-ath11k-Fix-spelling-mistake-reseting-resetting.patch @@ -0,0 +1,25 @@ +From 405342ebea2ab776df070ee54c308f1f59723844 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Thu, 7 Apr 2022 11:28:20 +0100 +Subject: [PATCH] ath11k: Fix spelling mistake "reseting" -> "resetting" + +There is a spelling mistake in an ath11k_warn message. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220407102820.613881-1-colin.i.king@gmail.com +--- + drivers/net/wireless/ath/ath11k/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1567,7 +1567,7 @@ static void ath11k_core_reset(struct wor + * completed, then the second reset worker will destroy the previous one, + * thus below is to avoid that. + */ +- ath11k_warn(ab, "already reseting count %d\n", reset_count); ++ ath11k_warn(ab, "already resetting count %d\n", reset_count); + + reinit_completion(&ab->reset_complete); + time_left = wait_for_completion_timeout(&ab->reset_complete, diff --git a/package/kernel/mac80211/patches/ath11k/100-ath11k-load-appropriate-board-data-from-board-id.patch b/package/kernel/mac80211/patches/ath11k/100-ath11k-load-appropriate-board-data-from-board-id.patch new file mode 100644 index 000000000..01f67ca97 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/100-ath11k-load-appropriate-board-data-from-board-id.patch @@ -0,0 +1,47 @@ +From 89aec0a67ee30cd11762aede86b3edfdb2433663 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Thu, 2 Jul 2020 12:04:34 +0530 +Subject: [PATCH] ath11k: load appropriate board data based on board id + +This patch adds support to read board id from dts and load +appropriate board data. + +Adding the patch which was removed as a part of commit id - +Ib950b3271fede9ccf7d53fe9629c38ee729a0ef5 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Lavanya Suresh +--- + drivers/net/wireless/ath/ath11k/qmi.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2009,9 +2009,11 @@ static int ath11k_qmi_assign_target_mem_ + + static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) + { ++ struct device *dev = ab->dev; + struct qmi_wlanfw_cap_req_msg_v01 req; + struct qmi_wlanfw_cap_resp_msg_v01 resp; + struct qmi_txn txn; ++ unsigned int board_id; + int ret = 0; + int r; + char *fw_build_id; +@@ -2056,10 +2058,13 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.chip_family = resp.chip_info.chip_family; + } + +- if (resp.board_info_valid) ++ if (!of_property_read_u32(dev->of_node, "qcom,board_id", &board_id) && board_id != 0xFF) { ++ ab->qmi.target.board_id = board_id; ++ } else if (resp.board_info_valid) { + ab->qmi.target.board_id = resp.board_info.board_id; +- else ++ } else { + ab->qmi.target.board_id = 0xFF; ++ } + + if (resp.soc_info_valid) + ab->qmi.target.soc_id = resp.soc_info.soc_id; diff --git a/package/kernel/mac80211/patches/ath11k/101-ath11k-update-debugfs-support-for-mupltiple-radios-i.patch b/package/kernel/mac80211/patches/ath11k/101-ath11k-update-debugfs-support-for-mupltiple-radios-i.patch new file mode 100644 index 000000000..83c597ca7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/101-ath11k-update-debugfs-support-for-mupltiple-radios-i.patch @@ -0,0 +1,151 @@ +From a1e16842a097171cc544b45e343effe97eadb493 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 30 Mar 2022 11:28:03 +0300 +Subject: ath11k: update debugfs support for mupltiple radios in PCI bus + +debugfs_ath11k struct is moved to ath11k_core, since its common +for both pci and ahb. + +Current ath11k_pci insmod fails if there are multiple PCI rdaios, + + ath11k_pci 0000:01:00.0: Hardware name qcn9074 hw1.0 + debugfs: Directory 'ath11k' with parent '/' already present! + ath11k_pci 0000:01:00.0: failed to create ath11k debugfs + ath11k_pci 0000:01:00.0: failed to create soc core: -17 + ath11k_pci 0000:01:00.0: failed to init core: -17 + ath11k_pci: probe of 0000:01:00.0 failed with error -17 + +To avoid the failure, debugfs directory is created with soc_name +and bus_id to allow creating debugfs directory for second PCI radio. + +with this Debugfs entries looks like, + # ls -l /sys/kernel/debug/ath11k/ + ipq8074 hw2.0 qcn9000 hw1.0_0000:01:00.0 qcn9000 hw1.0_0001:01:00.0 + + # ls -l /sys/kernel/debug/ath11k/ipq8074 hw2.0/ + mac0 mac1 simulate_fw_crash soc_dp_stats + + # ls -l /sys/kernel/debug/ath11k/qcn9000 hw1.0_0000:01:00.0 + mac0 simulate_fw_crash soc_dp_stats + + # /sys/kernel/debug/ath11k/qcn9000 hw1.0_0001:01:00.0: + mac0 simulate_fw_crash soc_dp_stats + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Patchwork-Id: 12101611 +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 58 +++++++++++++++++++++++++------ + 1 file changed, 48 insertions(+), 10 deletions(-) + +(limited to 'drivers/net/wireless/ath/ath11k/debugfs.c') + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -15,6 +15,8 @@ + #include "debugfs_htt_stats.h" + #include "peer.h" + ++struct dentry *debugfs_ath11k; ++ + static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = { + "REO2SW1_RING", + "REO2SW2_RING", +@@ -987,10 +989,6 @@ int ath11k_debugfs_pdev_create(struct at + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + +- ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k); +- if (IS_ERR(ab->debugfs_soc)) +- return PTR_ERR(ab->debugfs_soc); +- + debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab, + &fops_simulate_fw_crash); + +@@ -1002,24 +1000,58 @@ int ath11k_debugfs_pdev_create(struct at + + void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab) + { +- debugfs_remove_recursive(ab->debugfs_soc); +- ab->debugfs_soc = NULL; + } + + int ath11k_debugfs_soc_create(struct ath11k_base *ab) + { +- ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL); ++ struct device *dev = ab->dev; ++ char soc_name[64] = {0}; ++ ++ if (!(IS_ERR_OR_NULL(ab->debugfs_soc))) ++ return 0; ++ ++ if (ab->hif.bus == ATH11K_BUS_AHB) { ++ snprintf(soc_name, sizeof(soc_name), "%s", ab->hw_params.name); ++ } else { ++ snprintf(soc_name, sizeof(soc_name), "%s_%s", ++ ab->hw_params.name, dev_name(dev)); ++ } + +- return PTR_ERR_OR_ZERO(ab->debugfs_ath11k); ++ ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath11k); ++ if (IS_ERR_OR_NULL(ab->debugfs_soc)) { ++ if (IS_ERR(ab->debugfs_soc)) ++ return PTR_ERR(ab->debugfs_soc); ++ return -ENOMEM; ++ } ++ ++ return 0; + } + + void ath11k_debugfs_soc_destroy(struct ath11k_base *ab) + { +- debugfs_remove_recursive(ab->debugfs_ath11k); +- ab->debugfs_ath11k = NULL; ++ debugfs_remove_recursive(ab->debugfs_soc); ++ ab->debugfs_soc = NULL; + } + EXPORT_SYMBOL(ath11k_debugfs_soc_destroy); + ++int ath11k_debugfs_create(void) ++{ ++ debugfs_ath11k = debugfs_create_dir("ath11k", NULL); ++ if (IS_ERR_OR_NULL(debugfs_ath11k)) { ++ if (IS_ERR(debugfs_ath11k)) ++ return PTR_ERR(debugfs_ath11k); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++void ath11k_debugfs_destroy(void) ++{ ++ debugfs_remove_recursive(debugfs_ath11k); ++ debugfs_ath11k = NULL; ++} ++ + void ath11k_debugfs_fw_stats_init(struct ath11k *ar) + { + struct dentry *fwstats_dir = debugfs_create_dir("fw_stats", +@@ -1388,6 +1420,9 @@ int ath11k_debugfs_register(struct ath11 + char pdev_name[5]; + char buf[100] = {0}; + ++ if (!(IS_ERR_OR_NULL(ar->debug.debugfs_pdev))) ++ return 0; ++ + snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx); + + ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc); +@@ -1448,6 +1483,9 @@ void ath11k_debugfs_unregister(struct at + kfree(dbr_debug); + ar->debug.dbr_debug[i] = NULL; + } ++ ++ debugfs_remove_recursive(ar->debug.debugfs_pdev); ++ ar->debug.debugfs_pdev = NULL; + } + + static ssize_t ath11k_write_twt_add_dialog(struct file *file, diff --git a/package/kernel/mac80211/patches/ath11k/102-ath11k-Enable-threaded-NAPI-on-some-radios.patch b/package/kernel/mac80211/patches/ath11k/102-ath11k-Enable-threaded-NAPI-on-some-radios.patch new file mode 100644 index 000000000..c82f74e95 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/102-ath11k-Enable-threaded-NAPI-on-some-radios.patch @@ -0,0 +1,109 @@ +From 9a7f302b187dd845611ef4ee35b305bd078e59d6 Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Fri, 15 Apr 2022 11:29:25 +0200 +Subject: [PATCH] ath11k: Enable threaded NAPI on some radios + +Enable threaded NAPI on IPQ8074 and QCN9074. + +Unlike traditional NAPI poll which runs in softirq context and on the +core which scheduled the NAPI, threaded NAPI makes use of kernel threads +which are under direct control of the scheduler and helps in balancing the +NAPI processing load across multiple CPUs, this helps in improving +throughput. + +In the case of IPQ8074 it increased the throughput at 80MHz by about +200Mbps. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01201-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/ahb.c | 2 ++ + drivers/net/wireless/ath/ath11k/core.c | 6 ++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/pcic.c | 2 ++ + 4 files changed, 11 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -304,6 +304,8 @@ static void ath11k_ahb_ext_irq_enable(st + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + if (!irq_grp->napi_enabled) { ++ if (ab->hw_params.threaded_napi) ++ dev_set_threaded(&irq_grp->napi_ndev, true); + napi_enable(&irq_grp->napi); + irq_grp->napi_enabled = true; + } +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -101,6 +101,7 @@ static const struct ath11k_hw_params ath + .current_cc_support = false, + .dbr_debug_support = true, + .global_reset = false, ++ .threaded_napi = true, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -167,6 +168,7 @@ static const struct ath11k_hw_params ath + .current_cc_support = false, + .dbr_debug_support = true, + .global_reset = false, ++ .threaded_napi = false, + }, + { + .name = "qca6390 hw2.0", +@@ -232,6 +234,7 @@ static const struct ath11k_hw_params ath + .current_cc_support = true, + .dbr_debug_support = false, + .global_reset = true, ++ .threaded_napi = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -297,6 +300,7 @@ static const struct ath11k_hw_params ath + .current_cc_support = false, + .dbr_debug_support = true, + .global_reset = false, ++ .threaded_napi = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -362,6 +366,7 @@ static const struct ath11k_hw_params ath + .current_cc_support = true, + .dbr_debug_support = false, + .global_reset = true, ++ .threaded_napi = false, + }, + { + .name = "wcn6855 hw2.1", +@@ -426,6 +431,7 @@ static const struct ath11k_hw_params ath + .current_cc_support = true, + .dbr_debug_support = false, + .global_reset = true, ++ .threaded_napi = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -195,6 +195,7 @@ struct ath11k_hw_params { + bool current_cc_support; + bool dbr_debug_support; + bool global_reset; ++ bool threaded_napi; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/pcic.c ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -441,6 +441,8 @@ void ath11k_pcic_ext_irq_enable(struct a + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + if (!irq_grp->napi_enabled) { ++ if (ab->hw_params.threaded_napi) ++ dev_set_threaded(&irq_grp->napi_ndev, true); + napi_enable(&irq_grp->napi); + irq_grp->napi_enabled = true; + } diff --git a/package/kernel/mac80211/patches/ath11k/351-mac80211-fix-mesh-airtime-link-metric-estimating.patch b/package/kernel/mac80211/patches/ath11k/351-mac80211-fix-mesh-airtime-link-metric-estimating.patch new file mode 100644 index 000000000..5b417bfbc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/351-mac80211-fix-mesh-airtime-link-metric-estimating.patch @@ -0,0 +1,35 @@ +From fc9d9b3f367638505837a5815b1842bba2425993 Mon Sep 17 00:00:00 2001 +From: Aditya Kumar Singh +Date: Fri, 25 Mar 2022 11:04:37 +0530 +Subject: [PATCH] mac80211: fix mesh airtime link metric estimating + +ieee80211s_update_metric api uses sta_set_rate_info_tx api to +get struct rate_info data from struct ieee80211_tx_rate present +in ieee80211_sta->tx_stats. However, drivers can skip tx rate +calculation by setting rate idx as -1. Such drivers can provide +rate_info directly. + +Add fix to use rate_info directly if present instead of +sta_set_rate_info_tx. + +Signed-off-by: Aditya Kumar Singh +--- + net/mac80211/mesh_hwmp.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -310,7 +310,12 @@ void ieee80211s_update_metric(struct iee + LINK_FAIL_THRESH) + mesh_plink_broken(sta); + +- sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); ++ /* use rate info set by the driver directly if present */ ++ if (st->rate) ++ rinfo = sta->tx_stats.last_rate_info; ++ else ++ sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); ++ + ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, + cfg80211_calculate_bitrate(&rinfo)); + } diff --git a/package/kernel/mac80211/patches/ath11k/902-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch b/package/kernel/mac80211/patches/ath11k/900-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch similarity index 89% rename from package/kernel/mac80211/patches/ath11k/902-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch rename to package/kernel/mac80211/patches/ath11k/900-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch index ebcec97b7..5b4d49655 100644 --- a/package/kernel/mac80211/patches/ath11k/902-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch +++ b/package/kernel/mac80211/patches/ath11k/900-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch @@ -13,12 +13,12 @@ Signed-off-by: Robert Marko --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c -@@ -81,7 +81,7 @@ static const struct ath11k_hw_params ath +@@ -83,7 +83,7 @@ static const struct ath11k_hw_params ath .supports_shadow_regs = false, .idle_ps = false, .supports_sta_ps = false, - .cold_boot_calib = true, + .cold_boot_calib = false, - .cbcal_restart_fw = true, .fw_mem_mode = 0, .num_vdevs = 16 + 1, + .num_peers = 512, diff --git a/package/kernel/mac80211/patches/ath11k/900-ath11k-control-thermal-support-via-symbol.patch b/package/kernel/mac80211/patches/ath11k/900-ath11k-control-thermal-support-via-symbol.patch deleted file mode 100644 index 60720a721..000000000 --- a/package/kernel/mac80211/patches/ath11k/900-ath11k-control-thermal-support-via-symbol.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 703d6551f71e7290619d6effe2a25a64e10538b7 Mon Sep 17 00:00:00 2001 -From: Robert Marko -Date: Thu, 15 Dec 2022 12:20:52 +0100 -Subject: [PATCH] ath11k: control thermal support via symbol - -Currently, thermal support will get built if CONFIG_THERMAL is reachable, -however this is not suitable for OpenWrt as with ALL_KMODS being set to y -ATH11K_THERMAL wont get selected and so hwmon and thermal kmods wont get -pulled in resulting in a build-failure. - -So, to avoid that, lets do what is already done for ath10k and add a -config symbol into backports for enabling thermal support. - -Signed-off-by: Robert Marko ---- - drivers/net/wireless/ath/ath11k/Kconfig | 7 +++++++ - drivers/net/wireless/ath/ath11k/Makefile | 2 +- - drivers/net/wireless/ath/ath11k/thermal.h | 2 +- - local-symbols | 1 + - 4 files changed, 10 insertions(+), 2 deletions(-) - ---- a/drivers/net/wireless/ath/ath11k/Kconfig -+++ b/drivers/net/wireless/ath/ath11k/Kconfig -@@ -61,3 +61,10 @@ config ATH11K_SPECTRAL - Enable ath11k spectral scan support - - Say Y to enable access to the FFT/spectral data via debugfs. -+ -+config ATH11K_THERMAL -+ bool "ath11k thermal sensors and throttling support" -+ depends on ATH11K -+ depends on THERMAL -+ help -+ Enable ath11k thermal sensors and throttling support. ---- a/drivers/net/wireless/ath/ath11k/Makefile -+++ b/drivers/net/wireless/ath/ath11k/Makefile -@@ -22,7 +22,7 @@ ath11k-y += core.o \ - ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o - ath11k-$(CPTCFG_NL80211_TESTMODE) += testmode.o - ath11k-$(CPTCFG_ATH11K_TRACING) += trace.o --ath11k-$(CONFIG_THERMAL) += thermal.o -+ath11k-$(CPTCFG_ATH11K_THERMAL) += thermal.o - ath11k-$(CPTCFG_ATH11K_SPECTRAL) += spectral.o - ath11k-$(CONFIG_PM) += wow.o - ---- a/drivers/net/wireless/ath/ath11k/thermal.h -+++ b/drivers/net/wireless/ath/ath11k/thermal.h -@@ -25,7 +25,7 @@ struct ath11k_thermal { - int temperature; - }; - --#if IS_REACHABLE(CONFIG_THERMAL) -+#if IS_REACHABLE(CPTCFG_ATH11K_THERMAL) - int ath11k_thermal_register(struct ath11k_base *sc); - void ath11k_thermal_unregister(struct ath11k_base *sc); - int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state); ---- a/local-symbols -+++ b/local-symbols -@@ -174,6 +174,7 @@ ATH11K_DEBUG= - ATH11K_DEBUGFS= - ATH11K_TRACING= - ATH11K_SPECTRAL= -+ATH11K_THERMAL= - WLAN_VENDOR_ATMEL= - ATMEL= - PCI_ATMEL= diff --git a/package/kernel/mac80211/patches/ath11k/903-ath11k-ipq8074-support-512MB-memory-profile.patch b/package/kernel/mac80211/patches/ath11k/901-ath11k-ipq8074-support-512MB-memory-profile.patch similarity index 88% rename from package/kernel/mac80211/patches/ath11k/903-ath11k-ipq8074-support-512MB-memory-profile.patch rename to package/kernel/mac80211/patches/ath11k/901-ath11k-ipq8074-support-512MB-memory-profile.patch index 8d26978a6..589d5acce 100644 --- a/package/kernel/mac80211/patches/ath11k/903-ath11k-ipq8074-support-512MB-memory-profile.patch +++ b/package/kernel/mac80211/patches/ath11k/901-ath11k-ipq8074-support-512MB-memory-profile.patch @@ -16,11 +16,11 @@ Signed-off-by: Robert Marko 4 files changed, 176 insertions(+) --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig -@@ -61,6 +61,18 @@ +@@ -61,3 +61,15 @@ config ATH11K_SPECTRAL Enable ath11k spectral scan support Say Y to enable access to the FFT/spectral data via debugfs. -+ ++ +config ATH11K_MEM_PROFILE_512MB + bool "Atheros ath11k 512MB memory profile" + depends on ATH11K @@ -32,15 +32,12 @@ Signed-off-by: Robert Marko + depends on ATH11K + help + Use limits for the 1GB memory size. - - config ATH11K_THERMAL - bool "ath11k thermal sensors and throttling support" --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c -@@ -83,9 +83,15 @@ static const struct ath11k_hw_params ath +@@ -84,9 +84,15 @@ static const struct ath11k_hw_params ath + .idle_ps = false, .supports_sta_ps = false, .cold_boot_calib = false, - .cbcal_restart_fw = true, +#ifdef CPTCFG_ATH11K_MEM_PROFILE_1GB .fw_mem_mode = 0, .num_vdevs = 16 + 1, @@ -55,12 +52,12 @@ Signed-off-by: Robert Marko .supports_regdb = false, --- a/local-symbols +++ b/local-symbols -@@ -182,6 +182,8 @@ ATH11K_DEBUG= +@@ -155,6 +155,8 @@ ATH11K_DEBUG= ATH11K_DEBUGFS= ATH11K_TRACING= ATH11K_SPECTRAL= +ATH11K_MEM_PROFILE_512MB= +ATH11K_MEM_PROFILE_1GB= - ATH11K_THERMAL= WLAN_VENDOR_ATMEL= ATMEL= + PCI_ATMEL= diff --git a/package/kernel/mac80211/patches/ath11k/901-wifi-ath11k-pci-fix-compilation-in-5.16-and-older.patch b/package/kernel/mac80211/patches/ath11k/901-wifi-ath11k-pci-fix-compilation-in-5.16-and-older.patch deleted file mode 100644 index 2b6c18d6d..000000000 --- a/package/kernel/mac80211/patches/ath11k/901-wifi-ath11k-pci-fix-compilation-in-5.16-and-older.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 04178918e7f6b5f34dde81ec79ee8a1ccace3be3 Mon Sep 17 00:00:00 2001 -From: Robert Marko -Date: Mon, 17 Oct 2022 11:45:03 +0200 -Subject: [PATCH] wifi: ath11k: pci: fix compilation in 5.16 and older - -Commit ("genirq/msi, treewide: Use a named struct for PCI/MSI attributes") -changed the msi_desc structure a bit, however that is only available in -kernels 5.17 and newer, so check for kernel version to allow compilation -in 5.16 and older. - -Signed-off-by: Robert Marko ---- - drivers/net/wireless/ath/ath11k/pci.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/net/wireless/ath/ath11k/pci.c -+++ b/drivers/net/wireless/ath/ath11k/pci.c -@@ -451,7 +451,11 @@ static int ath11k_pci_alloc_msi(struct a - pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, - &ab->pci.msi.addr_lo); - -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 17, 0)) - if (msi_desc->pci.msi_attrib.is_64) { -+#else -+ if (msi_desc->msi_attrib.is_64) { -+#endif - pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, - &ab->pci.msi.addr_hi); - } else { diff --git a/package/kernel/mac80211/patches/ath11k/902-ath11k-linux-6.1-support.patch b/package/kernel/mac80211/patches/ath11k/902-ath11k-linux-6.1-support.patch new file mode 100644 index 000000000..94f2ffa92 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/902-ath11k-linux-6.1-support.patch @@ -0,0 +1,45 @@ +--- a/drivers/net/wireless/ath/ath11k/pci.c +--- b/drivers/net/wireless/ath/ath11k/pci.c +@@ -427,7 +427,11 @@ + pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, + &ab->pci.msi.addr_lo); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + if (msi_desc->msi_attrib.is_64) { ++#else ++ if (msi_desc->pci.msi_attrib.is_64) { ++#endif + pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, + &ab->pci.msi.addr_hi); + } else { +--- a/drivers/net/wireless/ath/ath11k/pcic.c ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -548,8 +548,13 @@ + irq_grp->ab = ab; + irq_grp->grp_id = i; + init_dummy_netdev(&irq_grp->napi_ndev); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + ath11k_pcic_ext_grp_napi_poll, NAPI_POLL_WEIGHT); ++#else ++ netif_napi_add_weight(&irq_grp->napi_ndev, &irq_grp->napi, ++ ath11k_pcic_ext_grp_napi_poll, NAPI_POLL_WEIGHT); ++#endif + + if (ab->hw_params.ring_mask->tx[i] || + ab->hw_params.ring_mask->rx[i] || +--- a/net/qrtr/qrtr.c ++++ b/net/qrtr/qrtr.c +@@ -1035,8 +1035,12 @@ + return -EADDRNOTAVAIL; + } + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &rc); ++#else ++ skb = skb_recv_datagram(sk, flags, &rc); ++#endif + if (!skb) { + release_sock(sk); + return rc; diff --git a/package/kernel/mac80211/patches/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch b/package/kernel/mac80211/patches/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch index 4fc97dfae..21516ffde 100644 --- a/package/kernel/mac80211/patches/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch +++ b/package/kernel/mac80211/patches/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch @@ -17,7 +17,7 @@ { AR5K_RXNOFRM, 8 }, --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c -@@ -854,10 +854,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) +@@ -869,10 +869,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) * guess we can tweak it and see how it goes ;-) */ if (ah->ah_version != AR5K_AR5210) { diff --git a/package/kernel/mac80211/patches/ath5k/411-ath5k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/ath5k/411-ath5k_allow_adhoc_and_ap.patch index 1df4aab57..35ed6ea55 100644 --- a/package/kernel/mac80211/patches/ath5k/411-ath5k_allow_adhoc_and_ap.patch +++ b/package/kernel/mac80211/patches/ath5k/411-ath5k_allow_adhoc_and_ap.patch @@ -18,7 +18,7 @@ goto end; --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c -@@ -2009,7 +2009,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) +@@ -1963,7 +1963,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) } if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + @@ -27,7 +27,7 @@ ah->opmode == NL80211_IFTYPE_MESH_POINT) { u64 tsf = ath5k_hw_get_tsf64(ah); u32 tsftu = TSF_TO_TU(tsf); -@@ -2095,7 +2095,7 @@ ath5k_beacon_update_timers(struct ath5k_ +@@ -2049,7 +2049,7 @@ ath5k_beacon_update_timers(struct ath5k_ intval = ah->bintval & AR5K_BEACON_PERIOD; if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs @@ -36,7 +36,7 @@ intval /= ATH_BCBUF; /* staggered multi-bss beacons */ if (intval < 15) ATH5K_WARN(ah, "intval %u is too low, min 15\n", -@@ -2561,6 +2561,7 @@ static const struct ieee80211_iface_limi +@@ -2515,6 +2515,7 @@ static const struct ieee80211_iface_limi BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_AP) }, diff --git a/package/kernel/mac80211/patches/ath9k/040-ath9k-support-DT-ieee80211-freq-limit-property-to-li.patch b/package/kernel/mac80211/patches/ath9k/040-ath9k-support-DT-ieee80211-freq-limit-property-to-li.patch new file mode 100644 index 000000000..7d4468176 --- /dev/null +++ b/package/kernel/mac80211/patches/ath9k/040-ath9k-support-DT-ieee80211-freq-limit-property-to-li.patch @@ -0,0 +1,28 @@ +From 03469e79fee9e8e908dae3bd1a80bcd9a66f2a88 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Mon, 11 Oct 2021 18:18:00 +0300 +Subject: ath9k: support DT ieee80211-freq-limit property to limit channels + +The common DT property can be used to limit the available channels +but ath9k has to manually call wiphy_read_of_freq_limits(). + +I would have put this into ath9k_of_init(). But it didn't work there. +The reason is that in ath9k_of_init() the channels and bands are not yet +registered in the wiphy struct. So there isn't any channel to flag as +disabled. + +Signed-off-by: Christian Lamparter +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211009212847.1781986-1-chunkeey@gmail.com +--- +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -1038,6 +1038,8 @@ int ath9k_init_device(u16 devid, struct + ARRAY_SIZE(ath9k_tpt_blink)); + #endif + ++ wiphy_read_of_freq_limits(hw->wiphy); ++ + /* Register with mac80211 */ + error = ieee80211_register_hw(hw); + if (error) diff --git a/package/kernel/mac80211/patches/ath9k/401-ath9k_blink_default.patch b/package/kernel/mac80211/patches/ath9k/401-ath9k_blink_default.patch index 3eb57bb1c..7405e594f 100644 --- a/package/kernel/mac80211/patches/ath9k/401-ath9k_blink_default.patch +++ b/package/kernel/mac80211/patches/ath9k/401-ath9k_blink_default.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -48,7 +48,7 @@ int ath9k_modparam_nohwcrypt; +@@ -47,7 +47,7 @@ int ath9k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); diff --git a/package/kernel/mac80211/patches/ath9k/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/ath9k/410-ath9k_allow_adhoc_and_ap.patch index b2f2763e8..b355e8372 100644 --- a/package/kernel/mac80211/patches/ath9k/410-ath9k_allow_adhoc_and_ap.patch +++ b/package/kernel/mac80211/patches/ath9k/410-ath9k_allow_adhoc_and_ap.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -882,6 +882,7 @@ static const struct ieee80211_iface_limi +@@ -826,6 +826,7 @@ static const struct ieee80211_iface_limi BIT(NL80211_IFTYPE_AP) }, { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, diff --git a/package/kernel/mac80211/patches/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch b/package/kernel/mac80211/patches/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch index f424ca530..284c88ff4 100644 --- a/package/kernel/mac80211/patches/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch +++ b/package/kernel/mac80211/patches/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch @@ -14,7 +14,7 @@ Signed-off-by: David Bauer --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -963,6 +963,7 @@ static void ath9k_set_hw_capab(struct at +@@ -907,6 +907,7 @@ static void ath9k_set_hw_capab(struct at ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); @@ -22,7 +22,7 @@ Signed-off-by: David Bauer if (ath9k_ps_enable) ieee80211_hw_set(hw, SUPPORTS_PS); -@@ -975,9 +976,6 @@ static void ath9k_set_hw_capab(struct at +@@ -919,9 +920,6 @@ static void ath9k_set_hw_capab(struct at IEEE80211_RADIOTAP_MCS_HAVE_STBC; } diff --git a/package/kernel/mac80211/patches/ath9k/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/ath9k/500-ath9k_eeprom_debugfs.patch index e2bbb4a1b..48ccc8130 100644 --- a/package/kernel/mac80211/patches/ath9k/500-ath9k_eeprom_debugfs.patch +++ b/package/kernel/mac80211/patches/ath9k/500-ath9k_eeprom_debugfs.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c -@@ -1413,6 +1413,53 @@ void ath9k_deinit_debug(struct ath_softc +@@ -1364,6 +1364,53 @@ void ath9k_deinit_debug(struct ath_softc ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); } @@ -54,7 +54,7 @@ int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); -@@ -1432,6 +1479,8 @@ int ath9k_init_debug(struct ath_hw *ah) +@@ -1383,6 +1430,8 @@ int ath9k_init_debug(struct ath_hw *ah) ath9k_tx99_init_debug(sc); ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); diff --git a/package/kernel/mac80211/patches/ath9k/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/ath9k/501-ath9k_ahb_init.patch index 740ddc39d..6ab7972b5 100644 --- a/package/kernel/mac80211/patches/ath9k/501-ath9k_ahb_init.patch +++ b/package/kernel/mac80211/patches/ath9k/501-ath9k_ahb_init.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -1178,25 +1178,25 @@ static int __init ath9k_init(void) +@@ -1122,25 +1122,25 @@ static int __init ath9k_init(void) { int error; diff --git a/package/kernel/mac80211/patches/ath9k/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/ath9k/512-ath9k_channelbw_debugfs.patch index 0c8b6920c..126d1d5c6 100644 --- a/package/kernel/mac80211/patches/ath9k/512-ath9k_channelbw_debugfs.patch +++ b/package/kernel/mac80211/patches/ath9k/512-ath9k_channelbw_debugfs.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c -@@ -1460,6 +1460,52 @@ static const struct file_operations fops +@@ -1411,6 +1411,52 @@ static const struct file_operations fops .owner = THIS_MODULE }; @@ -53,7 +53,7 @@ int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); -@@ -1481,6 +1527,8 @@ int ath9k_init_debug(struct ath_hw *ah) +@@ -1432,6 +1478,8 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_eeprom); diff --git a/package/kernel/mac80211/patches/ath9k/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/ath9k/530-ath9k_extra_leds.patch index 1fe004102..c16123782 100644 --- a/package/kernel/mac80211/patches/ath9k/530-ath9k_extra_leds.patch +++ b/package/kernel/mac80211/patches/ath9k/530-ath9k_extra_leds.patch @@ -181,7 +181,7 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -1088,7 +1088,7 @@ int ath9k_init_device(u16 devid, struct +@@ -1032,7 +1032,7 @@ int ath9k_init_device(u16 devid, struct #ifdef CPTCFG_MAC80211_LEDS /* must be initialized before ieee80211_register_hw */ @@ -192,7 +192,7 @@ #endif --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c -@@ -1505,6 +1505,61 @@ static const struct file_operations fops +@@ -1456,6 +1456,61 @@ static const struct file_operations fops .llseek = default_llseek, }; @@ -254,7 +254,7 @@ int ath9k_init_debug(struct ath_hw *ah) { -@@ -1529,6 +1584,10 @@ int ath9k_init_debug(struct ath_hw *ah) +@@ -1480,6 +1535,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_eeprom); debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_chanbw); diff --git a/package/kernel/mac80211/patches/ath9k/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/ath9k/542-ath9k_debugfs_diag.patch index 70f7ee365..5b64f560f 100644 --- a/package/kernel/mac80211/patches/ath9k/542-ath9k_debugfs_diag.patch +++ b/package/kernel/mac80211/patches/ath9k/542-ath9k_debugfs_diag.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c -@@ -1561,6 +1561,50 @@ static const struct file_operations fops +@@ -1512,6 +1512,50 @@ static const struct file_operations fops #endif @@ -51,7 +51,7 @@ int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); -@@ -1588,6 +1632,8 @@ int ath9k_init_debug(struct ath_hw *ah) +@@ -1539,6 +1583,8 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("gpio_led", S_IWUSR, sc->debug.debugfs_phy, sc, &fops_gpio_led); #endif @@ -84,7 +84,7 @@ bool reset_power_on; bool htc_reset_init; -@@ -1079,6 +1087,7 @@ void ath9k_hw_check_nav(struct ath_hw *a +@@ -1077,6 +1085,7 @@ void ath9k_hw_check_nav(struct ath_hw *a bool ath9k_hw_check_alive(struct ath_hw *ah); bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); diff --git a/package/kernel/mac80211/patches/ath9k/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/ath9k/543-ath9k_entropy_from_adc.patch index 6acc864d1..ef4e65987 100644 --- a/package/kernel/mac80211/patches/ath9k/543-ath9k_entropy_from_adc.patch +++ b/package/kernel/mac80211/patches/ath9k/543-ath9k_entropy_from_adc.patch @@ -18,7 +18,7 @@ void (*spectral_scan_trigger)(struct ath_hw *ah); --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c -@@ -1918,6 +1918,26 @@ void ar9003_hw_init_rate_txpower(struct +@@ -1927,6 +1927,26 @@ void ar9003_hw_init_rate_txpower(struct } } @@ -45,7 +45,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); -@@ -1954,6 +1974,7 @@ void ar9003_hw_attach_phy_ops(struct ath +@@ -1963,6 +1983,7 @@ void ar9003_hw_attach_phy_ops(struct ath priv_ops->set_radar_params = ar9003_hw_set_radar_params; priv_ops->fast_chan_change = ar9003_hw_fast_chan_change; @@ -55,7 +55,7 @@ ops->spectral_scan_config = ar9003_hw_spectral_scan_config; --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -870,7 +870,8 @@ static void ath9k_init_txpower_limits(st +@@ -814,7 +814,8 @@ static void ath9k_init_txpower_limits(st if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); @@ -65,7 +65,7 @@ } static const struct ieee80211_iface_limit if_limits[] = { -@@ -1048,6 +1049,18 @@ static void ath9k_set_hw_capab(struct at +@@ -992,6 +993,18 @@ static void ath9k_set_hw_capab(struct at wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); } @@ -84,7 +84,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { -@@ -1095,6 +1108,8 @@ int ath9k_init_device(u16 devid, struct +@@ -1039,6 +1052,8 @@ int ath9k_init_device(u16 devid, struct wiphy_read_of_freq_limits(hw->wiphy); diff --git a/package/kernel/mac80211/patches/ath9k/545-ath9k_ani_ws_detect.patch b/package/kernel/mac80211/patches/ath9k/545-ath9k_ani_ws_detect.patch index d3bf07ff9..854bb3659 100644 --- a/package/kernel/mac80211/patches/ath9k/545-ath9k_ani_ws_detect.patch +++ b/package/kernel/mac80211/patches/ath9k/545-ath9k_ani_ws_detect.patch @@ -79,7 +79,7 @@ static const u8 ofdm2pwr[] = { ALL_TARGET_LEGACY_6_24, ALL_TARGET_LEGACY_6_24, -@@ -1068,11 +1054,6 @@ static bool ar9003_hw_ani_control(struct +@@ -1077,11 +1063,6 @@ static bool ar9003_hw_ani_control(struct struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ar5416AniState *aniState = &ah->ani; @@ -91,7 +91,7 @@ s32 value, value2; switch (cmd & ah->ani_function) { -@@ -1086,61 +1067,6 @@ static bool ar9003_hw_ani_control(struct +@@ -1095,61 +1076,6 @@ static bool ar9003_hw_ani_control(struct */ u32 on = param ? 1 : 0; diff --git a/package/kernel/mac80211/patches/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch b/package/kernel/mac80211/patches/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch index 0fbc364c2..291bc6d1e 100644 --- a/package/kernel/mac80211/patches/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch +++ b/package/kernel/mac80211/patches/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch @@ -371,7 +371,7 @@ --- a/local-symbols +++ b/local-symbols -@@ -137,6 +137,7 @@ ATH9K_WOW= +@@ -110,6 +110,7 @@ ATH9K_WOW= ATH9K_RFKILL= ATH9K_CHANNEL_CONTEXT= ATH9K_PCOEM= diff --git a/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch b/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch index 57eef54e8..7ce8bc5b8 100644 --- a/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch +++ b/package/kernel/mac80211/patches/ath9k/552-ath9k-ahb_of.patch @@ -271,7 +271,7 @@ if (!dev_get_platdata(&pdev->dev)) { dev_err(&pdev->dev, "no platform data specified\n"); -@@ -118,13 +367,16 @@ static int ath_ahb_probe(struct platform +@@ -122,13 +371,16 @@ static int ath_ahb_probe(struct platform sc->mem = mem; sc->irq = irq; @@ -289,7 +289,7 @@ if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; -@@ -155,6 +407,9 @@ static int ath_ahb_remove(struct platfor +@@ -159,6 +411,9 @@ static int ath_ahb_remove(struct platfor free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); } @@ -299,7 +299,7 @@ return 0; } -@@ -164,6 +419,9 @@ static struct platform_driver ath_ahb_dr +@@ -168,6 +423,9 @@ static struct platform_driver ath_ahb_dr .remove = ath_ahb_remove, .driver = { .name = "ath9k", diff --git a/package/kernel/mac80211/patches/ath9k/553-ath9k_of_gpio_mask.patch b/package/kernel/mac80211/patches/ath9k/553-ath9k_of_gpio_mask.patch index 6d1820ecb..80e0dc4c5 100644 --- a/package/kernel/mac80211/patches/ath9k/553-ath9k_of_gpio_mask.patch +++ b/package/kernel/mac80211/patches/ath9k/553-ath9k_of_gpio_mask.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -696,6 +696,12 @@ static int ath9k_of_init(struct ath_soft +@@ -644,6 +644,12 @@ static int ath9k_of_init(struct ath_soft return 0; } @@ -13,7 +13,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { -@@ -803,6 +809,9 @@ static int ath9k_init_softc(u16 devid, s +@@ -747,6 +753,9 @@ static int ath9k_init_softc(u16 devid, s if (ret) goto err_hw; diff --git a/package/kernel/mac80211/patches/ath9k/600-v5.16-ath9k-fetch-calibration-data-via-nvmem-subsystem.patch b/package/kernel/mac80211/patches/ath9k/600-v5.16-ath9k-fetch-calibration-data-via-nvmem-subsystem.patch new file mode 100644 index 000000000..a250d2318 --- /dev/null +++ b/package/kernel/mac80211/patches/ath9k/600-v5.16-ath9k-fetch-calibration-data-via-nvmem-subsystem.patch @@ -0,0 +1,154 @@ +From dab16ef495dbb3cabb355b6c80f0771a4a25e35d Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Fri, 20 Aug 2021 22:44:52 +0200 +Subject: [PATCH] ath9k: fetch calibration data via nvmem subsystem + +On most embedded ath9k devices (like range extenders, +routers, accesspoints, ...) the calibration data is +stored in a MTD partitions named "ART", or "caldata"/ +"calibration". + +Ever since commit +4b361cfa8624 ("mtd: core: add OTP nvmem provider support") +all MTD partitions are all automatically available through +the nvmem subsystem. This allows drivers like ath9k to read +the necessary data without needing any userspace helpers +that would do this extraction. + +Signed-off-by: Christian Lamparter +--- + +includes: + +From 57671351379b2051cfb07fc14e0bead9916a0880 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Mon, 11 Oct 2021 18:18:01 +0300 +Subject: ath9k: fix an IS_ERR() vs NULL check + +The devm_kmemdup() function doesn't return error pointers, it returns +NULL on error. + +Fixes: eb3a97a69be8 ("ath9k: fetch calibration data via nvmem subsystem") +Signed-off-by: Dan Carpenter +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211011123533.GA15188@kili + +--- + +--- a/drivers/net/wireless/ath/ath9k/eeprom.c ++++ b/drivers/net/wireless/ath/ath9k/eeprom.c +@@ -135,13 +135,23 @@ static bool ath9k_hw_nvram_read_firmware + offset, data); + } + ++static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset, ++ u16 *data) ++{ ++ return ath9k_hw_nvram_read_array(ah->nvmem_blob, ++ ah->nvmem_blob_len / sizeof(u16), ++ offset, data); ++} ++ + bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) + { + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_platform_data *pdata = ah->dev->platform_data; + bool ret; + +- if (ah->eeprom_blob) ++ if (ah->nvmem_blob) ++ ret = ath9k_hw_nvram_read_nvmem(ah, off, data); ++ else if (ah->eeprom_blob) + ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); + else if (pdata && !pdata->use_eeprom) + ret = ath9k_hw_nvram_read_pdata(pdata, off, data); +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -988,6 +988,8 @@ struct ath_hw { + bool disable_5ghz; + + const struct firmware *eeprom_blob; ++ u16 *nvmem_blob; /* devres managed */ ++ size_t nvmem_blob_len; + + struct ath_dynack dynack; + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -568,6 +569,57 @@ static void ath9k_eeprom_release(struct + release_firmware(sc->sc_ah->eeprom_blob); + } + ++static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ struct nvmem_cell *cell; ++ void *buf; ++ size_t len; ++ int err; ++ ++ cell = devm_nvmem_cell_get(sc->dev, "calibration"); ++ if (IS_ERR(cell)) { ++ err = PTR_ERR(cell); ++ ++ /* nvmem cell might not be defined, or the nvmem ++ * subsystem isn't included. In this case, follow ++ * the established "just return 0;" convention of ++ * ath9k_init_platform to say: ++ * "All good. Nothing to see here. Please go on." ++ */ ++ if (err == -ENOENT || err == -EOPNOTSUPP) ++ return 0; ++ ++ return err; ++ } ++ ++ buf = nvmem_cell_read(cell, &len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ ++ /* run basic sanity checks on the returned nvram cell length. ++ * That length has to be a multiple of a "u16" (i.e.: & 1). ++ * Furthermore, it has to be more than "let's say" 512 bytes ++ * but less than the maximum of AR9300_EEPROM_SIZE (16kb). ++ */ ++ if (((len & 1) == 1) || (len < 512) || (len >= AR9300_EEPROM_SIZE)) { ++ kfree(buf); ++ return -EINVAL; ++ } ++ ++ /* devres manages the calibration values release on shutdown */ ++ ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); ++ kfree(buf); ++ if (!ah->nvmem_blob) ++ return -ENOMEM; ++ ++ ah->nvmem_blob_len = len; ++ ah->ah_flags &= ~AH_USE_EEPROM; ++ ah->ah_flags |= AH_NO_EEP_SWAP; ++ ++ return 0; ++} ++ + static int ath9k_init_platform(struct ath_softc *sc) + { + struct ath9k_platform_data *pdata = sc->dev->platform_data; +@@ -710,6 +762,10 @@ static int ath9k_init_softc(u16 devid, s + if (ret) + return ret; + ++ ret = ath9k_nvmem_request_eeprom(sc); ++ if (ret) ++ return ret; ++ + if (ath9k_led_active_high != -1) + ah->config.led_active_high = ath9k_led_active_high == 1; + diff --git a/package/kernel/mac80211/patches/ath9k/601-v5.16-ath9k-owl-loader-fetch-pci-init-values-through-nvmem.patch b/package/kernel/mac80211/patches/ath9k/601-v5.16-ath9k-owl-loader-fetch-pci-init-values-through-nvmem.patch new file mode 100644 index 000000000..62c561d61 --- /dev/null +++ b/package/kernel/mac80211/patches/ath9k/601-v5.16-ath9k-owl-loader-fetch-pci-init-values-through-nvmem.patch @@ -0,0 +1,181 @@ +From 9bf31835f11aa3c4fe5a9c1f7462c199c5d8e7ca Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Sat, 21 Aug 2021 00:22:39 +0200 +Subject: [PATCH] ath9k: owl-loader: fetch pci init values through nvmem + +extends the owl loader to fetch important pci initialization +values - which are stored together with the calibration data - +through the nvmem subsystem. + +This allows for much faster WIFI/ath9k initializations on devices +that do not require to perform any post-processing (like XOR'ing/ +reversal or unpacking) since no userspace helper is required. + +Signed-off-by: Christian Lamparter +--- + .../wireless/ath/ath9k/ath9k_pci_owl_loader.c | 105 +++++++++++++----- + 1 file changed, 76 insertions(+), 29 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c ++++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +@@ -19,9 +19,14 @@ + #include + #include + #include ++#include ++#include + + struct owl_ctx { ++ struct pci_dev *pdev; + struct completion eeprom_load; ++ struct work_struct work; ++ struct nvmem_cell *cell; + }; + + #define EEPROM_FILENAME_LEN 100 +@@ -42,6 +47,12 @@ static int ath9k_pci_fixup(struct pci_de + u32 bar0; + bool swap_needed = false; + ++ /* also note that we are doing *u16 operations on the file */ ++ if (cal_len > 4096 || cal_len < 0x200 || (cal_len & 1) == 1) { ++ dev_err(&pdev->dev, "eeprom has an invalid size.\n"); ++ return -EINVAL; ++ } ++ + if (*cal_data != AR5416_EEPROM_MAGIC) { + if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) { + dev_err(&pdev->dev, "invalid calibration data\n"); +@@ -99,38 +110,31 @@ static int ath9k_pci_fixup(struct pci_de + return 0; + } + +-static void owl_fw_cb(const struct firmware *fw, void *context) ++static void owl_rescan(struct pci_dev *pdev) + { +- struct pci_dev *pdev = (struct pci_dev *)context; +- struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev); +- struct pci_bus *bus; +- +- complete(&ctx->eeprom_load); +- +- if (!fw) { +- dev_err(&pdev->dev, "no eeprom data received.\n"); +- goto release; +- } +- +- /* also note that we are doing *u16 operations on the file */ +- if (fw->size > 4096 || fw->size < 0x200 || (fw->size & 1) == 1) { +- dev_err(&pdev->dev, "eeprom file has an invalid size.\n"); +- goto release; +- } +- +- if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size)) +- goto release; ++ struct pci_bus *bus = pdev->bus; + + pci_lock_rescan_remove(); +- bus = pdev->bus; + pci_stop_and_remove_bus_device(pdev); + /* the device should come back with the proper + * ProductId. But we have to initiate a rescan. + */ + pci_rescan_bus(bus); + pci_unlock_rescan_remove(); ++} ++ ++static void owl_fw_cb(const struct firmware *fw, void *context) ++{ ++ struct owl_ctx *ctx = (struct owl_ctx *)context; ++ ++ complete(&ctx->eeprom_load); + +-release: ++ if (fw) { ++ ath9k_pci_fixup(ctx->pdev, (const u16 *)fw->data, fw->size); ++ owl_rescan(ctx->pdev); ++ } else { ++ dev_err(&ctx->pdev->dev, "no eeprom data received.\n"); ++ } + release_firmware(fw); + } + +@@ -152,6 +156,43 @@ static const char *owl_get_eeprom_name(s + return eeprom_name; + } + ++static void owl_nvmem_work(struct work_struct *work) ++{ ++ struct owl_ctx *ctx = container_of(work, struct owl_ctx, work); ++ void *buf; ++ size_t len; ++ ++ complete(&ctx->eeprom_load); ++ ++ buf = nvmem_cell_read(ctx->cell, &len); ++ if (!IS_ERR(buf)) { ++ ath9k_pci_fixup(ctx->pdev, buf, len); ++ kfree(buf); ++ owl_rescan(ctx->pdev); ++ } else { ++ dev_err(&ctx->pdev->dev, "no nvmem data received.\n"); ++ } ++} ++ ++static int owl_nvmem_probe(struct owl_ctx *ctx) ++{ ++ int err; ++ ++ ctx->cell = devm_nvmem_cell_get(&ctx->pdev->dev, "calibration"); ++ if (IS_ERR(ctx->cell)) { ++ err = PTR_ERR(ctx->cell); ++ if (err == -ENOENT || err == -EOPNOTSUPP) ++ return 1; /* not present, try firmware_request */ ++ ++ return err; ++ } ++ ++ INIT_WORK(&ctx->work, owl_nvmem_work); ++ schedule_work(&ctx->work); ++ ++ return 0; ++} ++ + static int owl_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { +@@ -164,21 +205,27 @@ static int owl_probe(struct pci_dev *pde + + pcim_pin_device(pdev); + +- eeprom_name = owl_get_eeprom_name(pdev); +- if (!eeprom_name) { +- dev_err(&pdev->dev, "no eeprom filename found.\n"); +- return -ENODEV; +- } +- + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + init_completion(&ctx->eeprom_load); ++ ctx->pdev = pdev; + + pci_set_drvdata(pdev, ctx); ++ ++ err = owl_nvmem_probe(ctx); ++ if (err <= 0) ++ return err; ++ ++ eeprom_name = owl_get_eeprom_name(pdev); ++ if (!eeprom_name) { ++ dev_err(&pdev->dev, "no eeprom filename found.\n"); ++ return -ENODEV; ++ } ++ + err = request_firmware_nowait(THIS_MODULE, true, eeprom_name, +- &pdev->dev, GFP_KERNEL, pdev, owl_fw_cb); ++ &pdev->dev, GFP_KERNEL, ctx, owl_fw_cb); + if (err) + dev_err(&pdev->dev, "failed to request caldata (%d).\n", err); + diff --git a/package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch b/package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch new file mode 100644 index 000000000..03d9f8ecd --- /dev/null +++ b/package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch @@ -0,0 +1,103 @@ +From 716c220b4d990a4fe7800d0685ca69dee99e4e8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20L=C3=B6bl?= +Date: Fri, 6 May 2022 06:42:46 +0200 +Subject: [PATCH] brcmfmac: allow setting wlan MAC address using device tree +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows firmware to provide MAC address using device tree. Like in +case there is no MAC burned in wlan NVRAM. + +Signed-off-by: Pavel Löbl +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220506044246.67146-1-pavel@loebl.cz +--- + .../broadcom/brcm80211/brcmfmac/common.c | 23 ++++++++++++++----- + .../broadcom/brcm80211/brcmfmac/common.h | 1 + + .../broadcom/brcm80211/brcmfmac/core.c | 4 +++- + .../wireless/broadcom/brcm80211/brcmfmac/of.c | 3 +++ + 4 files changed, 24 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -202,13 +202,24 @@ int brcmf_c_preinit_dcmds(struct brcmf_i + char *ptr; + s32 err; + +- /* retreive mac address */ +- err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, +- sizeof(ifp->mac_addr)); +- if (err < 0) { +- bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err); +- goto done; ++ if (is_valid_ether_addr(ifp->mac_addr)) { ++ /* set mac address */ ++ err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, ++ ETH_ALEN); ++ if (err < 0) { ++ bphy_err(ifp->drvr, "Setting cur_etheraddr failed, %d\n", err); ++ goto done; ++ } ++ } else { ++ /* retrieve mac address */ ++ err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, ++ sizeof(ifp->mac_addr)); ++ if (err < 0) { ++ bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err); ++ goto done; ++ } + } ++ + memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); + memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +@@ -50,6 +50,7 @@ struct brcmf_mp_device { + bool ignore_probe_fail; + struct brcmfmac_pd_cc *country_codes; + const char *board_type; ++ unsigned char mac[ETH_ALEN]; + union { + struct brcmfmac_sdio_pd sdio; + } bus; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1226,7 +1227,8 @@ static int brcmf_bus_started(struct brcm + brcmf_dbg(TRACE, "\n"); + + /* add primary networking interface */ +- ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL); ++ ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", ++ is_valid_ether_addr(drvr->settings->mac) ? drvr->settings->mac : NULL); + if (IS_ERR(ifp)) + return PTR_ERR(ifp); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include + #include "debug.h" +@@ -97,6 +98,8 @@ void brcmf_of_probe(struct device *dev, + if (err) + brcmf_err("failed to get OF country code map (err=%d)\n", err); + ++ of_get_mac_address(np, settings->mac); ++ + if (bus_type != BRCMF_BUSTYPE_SDIO) + return; + diff --git a/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch b/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch index 22b67c49d..5dc04ecc8 100644 --- a/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch +++ b/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch @@ -20,7 +20,7 @@ if (phy->type == B43_PHYTYPE_B) { value16 = b43_read16(dev, 0x005E); -@@ -3986,7 +3986,6 @@ static int b43_op_config(struct ieee8021 +@@ -3985,7 +3985,6 @@ static int b43_op_config(struct ieee8021 struct b43_wldev *dev = wl->current_dev; struct b43_phy *phy = &dev->phy; struct ieee80211_conf *conf = &hw->conf; @@ -28,7 +28,7 @@ int err = 0; mutex_lock(&wl->mutex); -@@ -4029,11 +4028,9 @@ static int b43_op_config(struct ieee8021 +@@ -4028,11 +4027,9 @@ static int b43_op_config(struct ieee8021 } /* Antennas for RX and management frame TX. */ @@ -42,7 +42,7 @@ if (wl->radio_enabled != phy->radio_on) { if (wl->radio_enabled) { -@@ -5176,6 +5173,47 @@ static int b43_op_get_survey(struct ieee +@@ -5175,6 +5172,47 @@ static int b43_op_get_survey(struct ieee return 0; } @@ -89,8 +89,8 @@ + static const struct ieee80211_ops b43_hw_ops = { .tx = b43_op_tx, - .wake_tx_queue = ieee80211_handle_wake_tx_queue, -@@ -5198,6 +5236,8 @@ static const struct ieee80211_ops b43_hw + .conf_tx = b43_op_conf_tx, +@@ -5196,6 +5234,8 @@ static const struct ieee80211_ops b43_hw .sw_scan_complete = b43_op_sw_scan_complete_notifier, .get_survey = b43_op_get_survey, .rfkill_poll = b43_rfkill_poll, @@ -99,7 +99,7 @@ }; /* Hard-reset the chip. Do not call this directly. -@@ -5499,6 +5539,8 @@ static int b43_one_core_attach(struct b4 +@@ -5497,6 +5537,8 @@ static int b43_one_core_attach(struct b4 if (!wldev) goto out; @@ -108,7 +108,7 @@ wldev->use_pio = b43_modparam_pio; wldev->dev = dev; wldev->wl = wl; -@@ -5590,6 +5632,9 @@ static struct b43_wl *b43_wireless_init( +@@ -5588,6 +5630,9 @@ static struct b43_wl *b43_wireless_init( wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); diff --git a/package/kernel/mac80211/patches/brcm/815-b43-always-take-overlapping-devs.patch b/package/kernel/mac80211/patches/brcm/815-b43-always-take-overlapping-devs.patch index 3700eaa1a..a8eae1941 100644 --- a/package/kernel/mac80211/patches/brcm/815-b43-always-take-overlapping-devs.patch +++ b/package/kernel/mac80211/patches/brcm/815-b43-always-take-overlapping-devs.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c -@@ -114,7 +114,7 @@ static int b43_modparam_pio; +@@ -114,7 +114,7 @@ static int b43_modparam_pio = 0; module_param_named(pio, b43_modparam_pio, int, 0644); MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); diff --git a/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch index 9d0f3e20b..7b9512f74 100644 --- a/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch +++ b/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch @@ -13,15 +13,15 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c -@@ -459,6 +459,7 @@ struct brcmf_fw { +@@ -431,6 +431,7 @@ struct brcmf_fw { + struct brcmf_fw_request *req; u32 curpos; - unsigned int board_index; void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); + struct completion *completion; }; #ifdef CONFIG_EFI -@@ -686,6 +687,8 @@ static void brcmf_fw_request_done(const +@@ -655,6 +656,8 @@ static void brcmf_fw_request_done(const fwctx->req = NULL; } fwctx->done(fwctx->dev, ret, fwctx->req); @@ -30,7 +30,7 @@ Signed-off-by: Rafał Miłecki kfree(fwctx); } -@@ -751,6 +754,8 @@ int brcmf_fw_get_firmwares(struct device +@@ -695,6 +698,8 @@ int brcmf_fw_get_firmwares(struct device { struct brcmf_fw_item *first = &req->items[0]; struct brcmf_fw *fwctx; @@ -39,7 +39,7 @@ Signed-off-by: Rafał Miłecki char *alt_path = NULL; int ret; -@@ -768,6 +773,9 @@ int brcmf_fw_get_firmwares(struct device +@@ -712,6 +717,9 @@ int brcmf_fw_get_firmwares(struct device fwctx->dev = dev; fwctx->req = req; fwctx->done = fw_cb; @@ -48,8 +48,8 @@ Signed-off-by: Rafał Miłecki + fwctx->completion = &completion; /* First try alternative board-specific path if any */ - if (fwctx->req->board_types[0]) -@@ -787,6 +795,12 @@ int brcmf_fw_get_firmwares(struct device + if (fwctx->req->board_type) +@@ -730,6 +738,12 @@ int brcmf_fw_get_firmwares(struct device if (ret < 0) brcmf_fw_request_done(NULL, fwctx); diff --git a/package/kernel/mac80211/patches/brcm/861-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch b/package/kernel/mac80211/patches/brcm/861-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch index 4db63f92e..7b4cb250f 100644 --- a/package/kernel/mac80211/patches/brcm/861-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch +++ b/package/kernel/mac80211/patches/brcm/861-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch @@ -10,7 +10,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -710,8 +710,36 @@ static struct wireless_dev *brcmf_cfg802 +@@ -715,8 +715,36 @@ static struct wireless_dev *brcmf_cfg802 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_pub *drvr = cfg->pub; struct wireless_dev *wdev; diff --git a/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch b/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch index 16eef0e10..88465f256 100644 --- a/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch +++ b/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch @@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -2973,6 +2973,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip +@@ -2974,6 +2974,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip * preference in cfg struct to apply this to * FW later while initializing the dongle */ diff --git a/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch b/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch index cd202f657..1ddc78f7c 100644 --- a/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch +++ b/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch @@ -12,7 +12,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -@@ -65,6 +65,36 @@ static int brcmf_of_get_country_codes(st +@@ -59,6 +59,36 @@ static int brcmf_of_get_country_codes(st return 0; } @@ -49,7 +49,7 @@ Signed-off-by: Rafał Miłecki void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { -@@ -105,6 +135,8 @@ void brcmf_of_probe(struct device *dev, +@@ -91,6 +121,8 @@ void brcmf_of_probe(struct device *dev, of_node_put(root); } diff --git a/package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch b/package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch deleted file mode 100644 index 7d0e730b6..000000000 --- a/package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 4e32024cbb14230af3048e249e84f8c2b25ce45a Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 28 Oct 2021 15:03:16 +0100 -Subject: [PATCH] brcmfmac: Read alternative firmware names from DT - -Add the ability to load the names of alternative firmwares from the -Device Tree node. This permits separate firmwares for 43436s and 43438 -and allows downstream firmwares to coexist with upstream. - -Signed-off-by: Phil Elwell ---- - .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 ++++++++++++++ - .../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 +++ - .../broadcom/brcm80211/brcmfmac/sdio.c | 47 +++++++++++++++++-- - 3 files changed, 87 insertions(+), 3 deletions(-) - ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -@@ -11,6 +11,7 @@ - #include "debug.h" - #include "core.h" - #include "common.h" -+#include "firmware.h" - #include "of.h" - - static int brcmf_of_get_country_codes(struct device *dev, -@@ -167,3 +168,38 @@ void brcmf_of_probe(struct device *dev, - sdio->oob_irq_nr = irq; - sdio->oob_irq_flags = irqf; - } -+ -+struct brcmf_firmware_mapping * -+brcmf_of_fwnames(struct device *dev, u32 *fwname_count) -+{ -+ struct device_node *np = dev->of_node; -+ struct brcmf_firmware_mapping *fwnames; -+ struct device_node *map_np, *fw_np; -+ int of_count; -+ int count = 0; -+ -+ map_np = of_get_child_by_name(np, "firmwares"); -+ of_count = of_get_child_count(map_np); -+ if (!of_count) -+ return NULL; -+ -+ fwnames = devm_kcalloc(dev, of_count, -+ sizeof(struct brcmf_firmware_mapping), -+ GFP_KERNEL); -+ -+ for_each_child_of_node(map_np, fw_np) -+ { -+ struct brcmf_firmware_mapping *cur = &fwnames[count]; -+ -+ if (of_property_read_u32(fw_np, "chipid", &cur->chipid) || -+ of_property_read_u32(fw_np, "revmask", &cur->revmask)) -+ continue; -+ cur->fw_base = of_get_property(fw_np, "fw_base", NULL); -+ if (cur->fw_base) -+ count++; -+ } -+ -+ *fwname_count = count; -+ -+ return count ? fwnames : NULL; -+} ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h -@@ -5,9 +5,16 @@ - #ifdef CONFIG_OF - void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings); -+struct brcmf_firmware_mapping * -+brcmf_of_fwnames(struct device *dev, u32 *map_count); - #else - static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings) - { - } -+static struct brcmf_firmware_mapping * -+brcmf_of_fwnames(struct device *dev, u32 *map_count) -+{ -+ return NULL; -+} - #endif /* CONFIG_OF */ ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -@@ -35,6 +35,7 @@ - #include "core.h" - #include "common.h" - #include "bcdc.h" -+#include "of.h" - - #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) - #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) -@@ -634,7 +635,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "b - /* per-board firmware binaries */ - MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin"); - --static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { -+static const struct brcmf_firmware_mapping sdio_fwnames[] = { - BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), - BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), - BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), -@@ -662,6 +663,9 @@ static const struct brcmf_firmware_mappi - BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752) - }; - -+static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames; -+static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); -+ - #define TXCTL_CREDITS 2 - - static void pkt_align(struct sk_buff *p, int len, int align) -@@ -4192,6 +4196,9 @@ static const struct brcmf_bus_ops brcmf_ - #define BRCMF_SDIO_FW_NVRAM 1 - #define BRCMF_SDIO_FW_CLM 2 - -+static struct brcmf_fw_request * -+brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); -+ - static void brcmf_sdio_firmware_callback(struct device *dev, int err, - struct brcmf_fw_request *fwreq) - { -@@ -4207,6 +4214,22 @@ static void brcmf_sdio_firmware_callback - - brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); - -+ if (err && brcmf_sdio_fwnames != sdio_fwnames) { -+ /* Try again with the standard firmware names */ -+ brcmf_sdio_fwnames = sdio_fwnames; -+ brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); -+ kfree(fwreq); -+ fwreq = brcmf_sdio_prepare_fw_request(bus); -+ if (!fwreq) { -+ err = -ENOMEM; -+ goto fail; -+ } -+ err = brcmf_fw_get_firmwares(dev, fwreq, -+ brcmf_sdio_firmware_callback); -+ if (!err) -+ return; -+ } -+ - if (err) - goto fail; - -@@ -4417,7 +4440,7 @@ brcmf_sdio_prepare_fw_request(struct brc - - fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, - brcmf_sdio_fwnames, -- ARRAY_SIZE(brcmf_sdio_fwnames), -+ brcmf_sdio_fwnames_count, - fwnames, ARRAY_SIZE(fwnames)); - if (!fwreq) - return NULL; -@@ -4437,6 +4460,9 @@ struct brcmf_sdio *brcmf_sdio_probe(stru - struct brcmf_sdio *bus; - struct workqueue_struct *wq; - struct brcmf_fw_request *fwreq; -+ struct brcmf_firmware_mapping *of_fwnames, *fwnames = NULL; -+ const int fwname_size = sizeof(struct brcmf_firmware_mapping); -+ u32 of_fw_count; - - brcmf_dbg(TRACE, "Enter\n"); - -@@ -4519,6 +4545,21 @@ struct brcmf_sdio *brcmf_sdio_probe(stru - - brcmf_dbg(INFO, "completed!!\n"); - -+ of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count); -+ if (of_fwnames) -+ fwnames = devm_kcalloc(sdiodev->dev, -+ of_fw_count + brcmf_sdio_fwnames_count, -+ fwname_size, GFP_KERNEL); -+ -+ if (fwnames) { -+ /* The array is scanned in order, so overrides come first */ -+ memcpy(fwnames, of_fwnames, of_fw_count * fwname_size); -+ memcpy(fwnames + of_fw_count, sdio_fwnames, -+ brcmf_sdio_fwnames_count * fwname_size); -+ brcmf_sdio_fwnames = fwnames; -+ brcmf_sdio_fwnames_count += of_fw_count; -+ } -+ - fwreq = brcmf_sdio_prepare_fw_request(bus); - if (!fwreq) { - ret = -ENOMEM; diff --git a/package/kernel/mac80211/patches/brcm/998-survey.patch b/package/kernel/mac80211/patches/brcm/998-survey.patch new file mode 100644 index 000000000..d194e2517 --- /dev/null +++ b/package/kernel/mac80211/patches/brcm/998-survey.patch @@ -0,0 +1,148 @@ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2921,6 +2921,63 @@ done: + } + + static int ++brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev, ++ int idx, struct survey_info *survey) ++{ ++ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); ++ struct brcmf_if *ifp = netdev_priv(ndev); ++ struct brcmu_chan ch; ++ enum nl80211_band band = 0; ++ s32 err = 0; ++ int noise; ++ u32 freq; ++ u32 chanspec; ++ ++ memset(survey, 0, sizeof(struct survey_info)); ++ if (idx != 0) { ++ if (idx >= cfg->pub->num_chan_stats || cfg->pub->chan_stats == NULL) ++ return -ENOENT; ++ if (cfg->pub->chan_stats[idx].freq == 0) ++ return -ENOENT; ++ survey->filled = SURVEY_INFO_NOISE_DBM; ++ survey->channel = ieee80211_get_channel(wiphy, cfg->pub->chan_stats[idx].freq); ++ survey->noise = cfg->pub->chan_stats[idx].noise; ++ return 0; ++ } ++ ++ err = brcmf_fil_iovar_int_get(ifp, "chanspec", &chanspec); ++ if (err) { ++ brcmf_err("chanspec failed (%d)\n", err); ++ return err; ++ } ++ ++ ch.chspec = chanspec; ++ cfg->d11inf.decchspec(&ch); ++ ++ switch (ch.band) { ++ case BRCMU_CHAN_BAND_2G: ++ band = NL80211_BAND_2GHZ; ++ break; ++ case BRCMU_CHAN_BAND_5G: ++ band = NL80211_BAND_5GHZ; ++ break; ++ } ++ ++ freq = ieee80211_channel_to_frequency(ch.control_ch_num, band); ++ survey->channel = ieee80211_get_channel(wiphy, freq); ++ ++ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PHY_NOISE, &noise); ++ if (err) { ++ brcmf_err("Could not get noise (%d)\n", err); ++ return err; ++ } ++ ++ survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_IN_USE; ++ survey->noise = le32_to_cpu(noise); ++ return 0; ++} ++ ++static int + brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, + int idx, u8 *mac, struct station_info *sinfo) + { +@@ -3021,6 +3078,7 @@ static s32 brcmf_inform_single_bss(struc + struct brcmu_chan ch; + u16 channel; + u32 freq; ++ int i; + u16 notify_capability; + u16 notify_interval; + u8 *notify_ie; +@@ -3045,6 +3103,17 @@ static s32 brcmf_inform_single_bss(struc + band = NL80211_BAND_5GHZ; + + freq = ieee80211_channel_to_frequency(channel, band); ++ for (i = 0;i < cfg->pub->num_chan_stats;i++) { ++ if (freq == cfg->pub->chan_stats[i].freq) ++ break; ++ if (cfg->pub->chan_stats[i].freq == 0) ++ break; ++ } ++ if (i < cfg->pub->num_chan_stats) { ++ cfg->pub->chan_stats[i].freq = freq; ++ cfg->pub->chan_stats[i].noise = bi->phy_noise; ++ } ++ + bss_data.chan = ieee80211_get_channel(wiphy, freq); + bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20; + bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime()); +@@ -5573,6 +5642,7 @@ static struct cfg80211_ops brcmf_cfg8021 + .leave_ibss = brcmf_cfg80211_leave_ibss, + .get_station = brcmf_cfg80211_get_station, + .dump_station = brcmf_cfg80211_dump_station, ++ .dump_survey = brcmf_cfg80211_dump_survey, + .set_tx_power = brcmf_cfg80211_set_tx_power, + .get_tx_power = brcmf_cfg80211_get_tx_power, + .add_key = brcmf_cfg80211_add_key, +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1363,6 +1363,8 @@ int brcmf_attach(struct device *dev) + + /* Link to bus module */ + drvr->hdrlen = 0; ++ drvr->chan_stats = vzalloc(256 * sizeof(struct brcmf_chan_stats)); ++ drvr->num_chan_stats = 256; + + /* Attach and link in the protocol */ + ret = brcmf_proto_attach(drvr); +@@ -1445,6 +1447,12 @@ void brcmf_detach(struct device *dev) + if (drvr == NULL) + return; + ++ drvr->num_chan_stats = 0; ++ if (drvr->chan_stats) { ++ vfree(drvr->chan_stats); ++ drvr->chan_stats = NULL; ++ } ++ + #ifdef CONFIG_INET + unregister_inetaddr_notifier(&drvr->inetaddr_notifier); + #endif +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +@@ -91,6 +91,11 @@ struct brcmf_rev_info { + u32 nvramrev; + }; + ++struct brcmf_chan_stats { ++ u32 freq; ++ int noise; ++}; ++ + /* Common structure for module and instance linkage */ + struct brcmf_pub { + /* Linkage ponters */ +@@ -100,6 +105,9 @@ struct brcmf_pub { + struct cfg80211_ops *ops; + struct brcmf_cfg80211_info *config; + ++ int num_chan_stats; ++ struct brcmf_chan_stats *chan_stats; ++ + /* Internal brcmf items */ + uint hdrlen; /* Total BRCMF header length (proto + bus) */ + diff --git a/package/kernel/mac80211/patches/brcm/999-backport-to-linux-5.18.patch b/package/kernel/mac80211/patches/brcm/999-backport-to-linux-5.18.patch new file mode 100644 index 000000000..be3f5c502 --- /dev/null +++ b/package/kernel/mac80211/patches/brcm/999-backport-to-linux-5.18.patch @@ -0,0 +1,121 @@ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -245,7 +245,11 @@ static int brcmf_netdev_set_mac_address( + } else { + brcmf_dbg(TRACE, "updated to %pM\n", sa->sa_data); + memcpy(ifp->mac_addr, sa->sa_data, ETH_ALEN); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN); ++#else ++ eth_hw_addr_set(ifp->ndev, ifp->mac_addr); ++#endif + } + return err; + } +@@ -424,6 +428,7 @@ void brcmf_netif_rx(struct brcmf_if *ifp + ifp->ndev->stats.rx_packets++; + + brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol)); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + if (inirq) { + netif_rx(skb); + } else { +@@ -433,6 +438,9 @@ void brcmf_netif_rx(struct brcmf_if *ifp + */ + netif_rx_ni(skb); + } ++#else ++ netif_rx(skb); ++#endif + } + + void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb) +@@ -673,7 +681,11 @@ int brcmf_net_attach(struct brcmf_if *if + ndev->ethtool_ops = &brcmf_ethtool_ops; + + /* set the mac address & netns */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); ++#else ++ eth_hw_addr_set(ifp->ndev, ifp->mac_addr); ++#endif + dev_net_set(ndev, wiphy_net(cfg_to_wiphy(drvr->config))); + + INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); +@@ -848,7 +860,11 @@ static int brcmf_net_p2p_attach(struct b + ndev->netdev_ops = &brcmf_netdev_ops_p2p; + + /* set the mac address */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); ++#else ++ eth_hw_addr_set(ndev, ifp->mac_addr); ++#endif + + if (register_netdev(ndev) != 0) { + bphy_err(drvr, "couldn't register the p2p net device\n"); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -2125,7 +2125,7 @@ static int brcmf_p2p_disable_p2p_if(stru + struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); + struct net_device *pri_ndev = cfg_to_ndev(cfg); + struct brcmf_if *ifp = netdev_priv(pri_ndev); +- u8 *addr = vif->wdev.netdev->dev_addr; ++ const u8 *addr = vif->wdev.netdev->dev_addr; + + return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN); + } +@@ -2135,7 +2135,7 @@ static int brcmf_p2p_release_p2p_if(stru + struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); + struct net_device *pri_ndev = cfg_to_ndev(cfg); + struct brcmf_if *ifp = netdev_priv(pri_ndev); +- u8 *addr = vif->wdev.netdev->dev_addr; ++ const u8 *addr = vif->wdev.netdev->dev_addr; + + return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN); + } +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -5555,7 +5555,7 @@ struct wireless_dev { + unsigned long unprot_beacon_reported; + }; + +-static inline u8 *wdev_address(struct wireless_dev *wdev) ++static inline const u8 *wdev_address(struct wireless_dev *wdev) + { + if (wdev->netdev) + return wdev->netdev->dev_addr; +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -1274,9 +1274,13 @@ int ieee80211_do_open(struct wireless_de + * this interface, if it has the special null one. + */ + if (dev && is_zero_ether_addr(dev->dev_addr)) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + memcpy(dev->dev_addr, + local->hw.wiphy->perm_addr, + ETH_ALEN); ++#else ++ eth_hw_addr_set(dev, local->hw.wiphy->perm_addr); ++#endif + memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); + + if (!is_valid_ether_addr(dev->dev_addr)) { +@@ -2136,9 +2140,17 @@ int ieee80211_if_add(struct ieee80211_lo + + ieee80211_assign_perm_addr(local, ndev->perm_addr, type); + if (is_valid_ether_addr(params->macaddr)) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN); ++#else ++ eth_hw_addr_set(ndev, params->macaddr); ++#endif + else ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); ++#else ++ eth_hw_addr_set(ndev, ndev->perm_addr); ++#endif + SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); + + /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ diff --git a/package/kernel/mac80211/patches/build/015-ipw200-mtu.patch b/package/kernel/mac80211/patches/build/015-ipw200-mtu.patch new file mode 100644 index 000000000..68db4f72d --- /dev/null +++ b/package/kernel/mac80211/patches/build/015-ipw200-mtu.patch @@ -0,0 +1,34 @@ +--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c ++++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c +@@ -11470,6 +11470,15 @@ static const struct attribute_group ipw_ + .attrs = ipw_sysfs_entries, + }; + ++#if LINUX_VERSION_IS_LESS(4,10,0) ++static int __change_mtu(struct net_device *ndev, int new_mtu){ ++ if (new_mtu < 68 || new_mtu > LIBIPW_DATA_LEN) ++ return -EINVAL; ++ ndev->mtu = new_mtu; ++ return 0; ++} ++#endif ++ + #ifdef CPTCFG_IPW2200_PROMISCUOUS + static int ipw_prom_open(struct net_device *dev) + { +@@ -11518,15 +11527,6 @@ static netdev_tx_t ipw_prom_hard_start_x + return NETDEV_TX_OK; + } + +-#if LINUX_VERSION_IS_LESS(4,10,0) +-static int __change_mtu(struct net_device *ndev, int new_mtu){ +- if (new_mtu < 68 || new_mtu > LIBIPW_DATA_LEN) +- return -EINVAL; +- ndev->mtu = new_mtu; +- return 0; +-} +-#endif +- + static const struct net_device_ops ipw_prom_netdev_ops = { + #if LINUX_VERSION_IS_LESS(4,10,0) + .ndo_change_mtu = __change_mtu, diff --git a/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch b/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch index 4ad2ac081..19a60d795 100644 --- a/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch +++ b/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch @@ -1,6 +1,6 @@ --- a/local-symbols +++ b/local-symbols -@@ -470,43 +470,6 @@ USB_VL600= +@@ -428,43 +428,6 @@ USB_VL600= USB_NET_CH9200= USB_NET_AQC111= USB_RTL8153_ECM= @@ -99,7 +99,7 @@ return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev); #else return bus->chipco.dev; -@@ -4871,7 +4871,7 @@ static int b43_wireless_core_init(struct +@@ -4870,7 +4870,7 @@ static int b43_wireless_core_init(struct } if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW) hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */ @@ -158,6 +158,27 @@ pcidev = bus->pcicore.dev; #endif gpiodev = bus->chipco.dev ? : pcidev; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h +@@ -24,7 +24,7 @@ struct brcms_led { + struct gpio_desc *gpiod; + }; + +-#ifdef CPTCFG_BCMA_DRIVER_GPIO ++#ifdef CONFIG_BCMA_DRIVER_GPIO + void brcms_led_unregister(struct brcms_info *wl); + int brcms_led_register(struct brcms_info *wl); + #else +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile +@@ -42,6 +42,6 @@ brcmsmac-y := \ + brcms_trace_events.o \ + debug.o + +-brcmsmac-$(CPTCFG_BCMA_DRIVER_GPIO) += led.o ++brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o + + obj-$(CPTCFG_BRCMSMAC) += brcmsmac.o --- a/drivers/net/wireless/broadcom/brcm80211/Kconfig +++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig @@ -8,7 +8,7 @@ config BRCMSMAC @@ -166,12 +187,12 @@ depends on BCMA_POSSIBLE - select BCMA + depends on BCMA + select NEW_LEDS if BCMA_DRIVER_GPIO + select LEDS_CLASS if BCMA_DRIVER_GPIO select BRCMUTIL - depends on FW_LOADER - depends on CORDIC --- a/Kconfig.local +++ b/Kconfig.local -@@ -1414,117 +1414,6 @@ config BACKPORTED_USB_NET_AQC111 +@@ -1288,117 +1288,6 @@ config BACKPORTED_USB_NET_AQC111 config BACKPORTED_USB_RTL8153_ECM tristate default USB_RTL8153_ECM @@ -291,7 +312,7 @@ default USB_ACM --- a/Kconfig.sources +++ b/Kconfig.sources -@@ -10,9 +10,6 @@ source "$BACKPORT_DIR/drivers/soc/qcom/K +@@ -9,9 +9,6 @@ source "$BACKPORT_DIR/drivers/bus/mhi/Kc source "$BACKPORT_DIR/drivers/net/wireless/Kconfig" source "$BACKPORT_DIR/drivers/net/usb/Kconfig" @@ -303,8 +324,8 @@ source "$BACKPORT_DIR/drivers/staging/Kconfig" --- a/Makefile.kernel +++ b/Makefile.kernel -@@ -43,8 +43,6 @@ obj-$(CPTCFG_QRTR) += net/qrtr/ - obj-$(CPTCFG_QCOM_QMI_HELPERS) += drivers/soc/qcom/ +@@ -42,8 +42,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/ + obj-$(CPTCFG_QRTR) += net/qrtr/ obj-$(CPTCFG_MHI_BUS) += drivers/bus/mhi/ obj-$(CPTCFG_WLAN) += drivers/net/wireless/ -obj-$(CPTCFG_SSB) += drivers/ssb/ diff --git a/package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch b/package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch deleted file mode 100644 index 121b7faad..000000000 --- a/package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/drivers/staging/rtl8723bs/Kconfig -+++ b/drivers/staging/rtl8723bs/Kconfig -@@ -5,7 +5,6 @@ config RTL8723BS - depends on m - depends on WLAN && MMC && CFG80211 - depends on m -- select CFG80211_WEXT - depends on CRYPTO - select BPAUTO_CRYPTO_LIB_ARC4 - help diff --git a/package/kernel/mac80211/patches/build/080-resv_start_op.patch b/package/kernel/mac80211/patches/build/080-resv_start_op.patch deleted file mode 100644 index 67ccc73a4..000000000 --- a/package/kernel/mac80211/patches/build/080-resv_start_op.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/drivers/net/wireless/mac80211_hwsim.c -+++ b/drivers/net/wireless/mac80211_hwsim.c -@@ -5363,7 +5363,9 @@ static struct genl_family hwsim_genl_fam - .module = THIS_MODULE, - .small_ops = hwsim_ops, - .n_small_ops = ARRAY_SIZE(hwsim_ops), -+#if LINUX_VERSION_IS_GEQ(6,1,0) - .resv_start_op = HWSIM_CMD_DEL_MAC_ADDR + 1, -+#endif - .mcgrps = hwsim_mcgrps, - .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps), - }; ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -17232,7 +17232,9 @@ static struct genl_family nl80211_fam __ - .n_ops = ARRAY_SIZE(nl80211_ops), - .small_ops = nl80211_small_ops, - .n_small_ops = ARRAY_SIZE(nl80211_small_ops), -+#if LINUX_VERSION_IS_GEQ(6,1,0) - .resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1, -+#endif - .mcgrps = nl80211_mcgrps, - .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps), - .parallel_ops = true, diff --git a/package/kernel/mac80211/patches/build/090-bcma-otp.patch b/package/kernel/mac80211/patches/build/090-bcma-otp.patch deleted file mode 100644 index 397477612..000000000 --- a/package/kernel/mac80211/patches/build/090-bcma-otp.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- /dev/null -+++ b/backport-include/linux/bcma/bcma_driver_chipcommon.h -@@ -0,0 +1,10 @@ -+#ifndef __BACKPORT_BCMA_DRIVER_CHIPCOMMON_H -+#define __BACKPORT_BCMA_DRIVER_CHIPCOMMON_H -+ -+#include_next -+ -+#ifndef BCMA_CC_SROM_CONTROL_OTP_PRESENT -+#define BCMA_CC_SROM_CONTROL_OTP_PRESENT 0x00000020 -+#endif -+ -+#endif diff --git a/package/kernel/mac80211/patches/build/100-backports-drop-QRTR-and-MHI.patch b/package/kernel/mac80211/patches/build/100-backports-drop-QRTR-and-MHI.patch deleted file mode 100644 index b017a0ce1..000000000 --- a/package/kernel/mac80211/patches/build/100-backports-drop-QRTR-and-MHI.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 54e0f9aaf340377fb76acdffee9ec7372c4b70ae Mon Sep 17 00:00:00 2001 -From: Robert Marko -Date: Mon, 17 Oct 2022 11:35:36 +0200 -Subject: [PATCH] backports: drop QRTR and MHI - -Backports currently include QRTR and MHI due to ath11k-pci requiring them, -however this at the same time prevents us from adding ath11k-ahb as it -also requires QRTR however its AHB variant from the kernel will conflict -with the core provided by backports. - -Since MHI also conflicts with existing OpenWrt kmods providing MHI drop -both from backports and use the ones provided by OpenWrt kernel. - -Signed-off-by: Robert Marko ---- - Kconfig.sources | 2 -- - Makefile.kernel | 2 -- - drivers/net/wireless/ath/ath11k/Kconfig | 6 +++--- - local-symbols | 8 -------- - 4 files changed, 3 insertions(+), 15 deletions(-) - ---- a/Kconfig.sources -+++ b/Kconfig.sources -@@ -4,8 +4,6 @@ source "$BACKPORT_DIR/compat/Kconfig" - # these are copied from the kernel - source "$BACKPORT_DIR/net/wireless/Kconfig" - source "$BACKPORT_DIR/net/mac80211/Kconfig" --source "$BACKPORT_DIR/net/qrtr/Kconfig" --source "$BACKPORT_DIR/drivers/bus/mhi/Kconfig" - source "$BACKPORT_DIR/drivers/soc/qcom/Kconfig" - source "$BACKPORT_DIR/drivers/net/wireless/Kconfig" - source "$BACKPORT_DIR/drivers/net/usb/Kconfig" ---- a/Makefile.kernel -+++ b/Makefile.kernel -@@ -39,9 +39,7 @@ obj-y += compat/ - - obj-$(CPTCFG_CFG80211) += net/wireless/ - obj-$(CPTCFG_MAC80211) += net/mac80211/ --obj-$(CPTCFG_QRTR) += net/qrtr/ - obj-$(CPTCFG_QCOM_QMI_HELPERS) += drivers/soc/qcom/ --obj-$(CPTCFG_MHI_BUS) += drivers/bus/mhi/ - obj-$(CPTCFG_WLAN) += drivers/net/wireless/ - obj-$(CPTCFG_USB_NET_RNDIS_WLAN) += drivers/net/usb/ - ---- a/drivers/net/wireless/ath/ath11k/Kconfig -+++ b/drivers/net/wireless/ath/ath11k/Kconfig -@@ -25,9 +25,9 @@ config ATH11K_PCI - tristate "Atheros ath11k PCI support" - depends on m - depends on ATH11K && PCI -- select MHI_BUS -- select QRTR -- select QRTR_MHI -+ depends on MHI_BUS -+ depends on QRTR -+ depends on QRTR_MHI - help - This module adds support for PCIE bus - ---- a/local-symbols -+++ b/local-symbols -@@ -65,14 +65,6 @@ MAC80211_MESH_PS_DEBUG= - MAC80211_TDLS_DEBUG= - MAC80211_DEBUG_COUNTERS= - MAC80211_STA_HASH_MAX_SIZE= --QRTR= --QRTR_SMD= --QRTR_TUN= --QRTR_MHI= --MHI_BUS= --MHI_BUS_DEBUG= --MHI_BUS_PCI_GENERIC= --MHI_BUS_EP= - QCOM_AOSS_QMP= - QCOM_COMMAND_DB= - QCOM_CPR= diff --git a/package/kernel/mac80211/patches/build/267-rtl8723_5.18_support.patch b/package/kernel/mac80211/patches/build/267-rtl8723_5.18_support.patch new file mode 100644 index 000000000..918b12fa2 --- /dev/null +++ b/package/kernel/mac80211/patches/build/267-rtl8723_5.18_support.patch @@ -0,0 +1,14 @@ +--- a/drivers/staging/rtl8723bs/include/osdep_service_linux.h ++++ b/drivers/staging/rtl8723bs/include/osdep_service_linux.h +@@ -45,7 +45,11 @@ + spinlock_t lock; + }; + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) ++ #define thread_exit() kthread_complete_and_exit(NULL, 0) ++#else + #define thread_exit() complete_and_exit(NULL, 0) ++#endif + + static inline struct list_head *get_next(struct list_head *list) + { diff --git a/package/kernel/mac80211/patches/build/882-use-netif_rx.patch b/package/kernel/mac80211/patches/build/882-use-netif_rx.patch new file mode 100644 index 000000000..a7ef18d49 --- /dev/null +++ b/package/kernel/mac80211/patches/build/882-use-netif_rx.patch @@ -0,0 +1,14 @@ +--- a/net/wireless/util.c ++++ b/net/wireless/util.c +@@ -2149,7 +2149,11 @@ void cfg80211_send_layer2_update(struct + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + netif_rx_ni(skb); ++#else ++ netif_rx(skb); ++#endif + } + EXPORT_SYMBOL(cfg80211_send_layer2_update); + diff --git a/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch b/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch index 11536651b..140949f9a 100644 --- a/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch +++ b/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c -@@ -5703,6 +5703,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw") +@@ -5699,6 +5699,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw") MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); static const struct pci_device_id mwl8k_pci_id_table[] = { diff --git a/package/kernel/mac80211/patches/mwl/801-libertas-configure-sysfs-links.patch b/package/kernel/mac80211/patches/mwl/801-libertas-configure-sysfs-links.patch index 2c426ab82..dfa0e502f 100644 --- a/package/kernel/mac80211/patches/mwl/801-libertas-configure-sysfs-links.patch +++ b/package/kernel/mac80211/patches/mwl/801-libertas-configure-sysfs-links.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c -@@ -2052,6 +2052,8 @@ struct wireless_dev *lbs_cfg_alloc(struc +@@ -2053,6 +2053,8 @@ struct wireless_dev *lbs_cfg_alloc(struc goto err_wiphy_new; } @@ -11,7 +11,7 @@ err_wiphy_new: --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c -@@ -934,6 +934,7 @@ struct lbs_private *lbs_add_card(void *c +@@ -935,6 +935,7 @@ struct lbs_private *lbs_add_card(void *c goto err_adapter; } diff --git a/package/kernel/mac80211/patches/mwl/802-libertas-set-wireless-macaddr.patch b/package/kernel/mac80211/patches/mwl/802-libertas-set-wireless-macaddr.patch index b47aee549..c2d0a5890 100644 --- a/package/kernel/mac80211/patches/mwl/802-libertas-set-wireless-macaddr.patch +++ b/package/kernel/mac80211/patches/mwl/802-libertas-set-wireless-macaddr.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c -@@ -2128,6 +2128,8 @@ int lbs_cfg_register(struct lbs_private +@@ -2129,6 +2129,8 @@ int lbs_cfg_register(struct lbs_private wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wdev->wiphy->reg_notifier = lbs_reg_notifier; diff --git a/package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch b/package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch deleted file mode 100644 index caa139a2c..000000000 --- a/package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch +++ /dev/null @@ -1,41 +0,0 @@ -From ef8098cd6cb8b5989afef2e8461fe6ba9570a854 Mon Sep 17 00:00:00 2001 -From: Josef Schlehofer -Date: Wed, 24 Nov 2021 12:47:40 +0100 -Subject: [PATCH] mwifiex: increase the global limit up to 4 SSID - -Firmware for SDIO (88W8997), which is used in Turris MOX SDIO addon [1], -allows up to 4 SSID. Unfortunately, driver (even in mainline kernel) -has a global limit for all Marvell cards up to 3 SSID. - -Pali Rohár tested this patch and verified that the SDIO Wi-Fi addon works -with the 4 SSID. So, let's increase the global limit from 3 to 4. - -Ideally, this patch should be done differently before sending -it to Linux kernel. It means that limit definition should be moved to -the card-specific structure. - -[1] https://docs.turris.cz/hw/mox/addons/#wi-fi-sdio ---- - drivers/net/wireless/marvell/mwifiex/decl.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/net/wireless/marvell/mwifiex/decl.h -+++ b/drivers/net/wireless/marvell/mwifiex/decl.h -@@ -18,7 +18,7 @@ - #include - - #define MWIFIEX_BSS_COEX_COUNT 2 --#define MWIFIEX_MAX_BSS_NUM (3) -+#define MWIFIEX_MAX_BSS_NUM (4) - - #define MWIFIEX_DMA_ALIGN_SZ 64 - #define MWIFIEX_RX_HEADROOM 64 -@@ -100,7 +100,7 @@ - #define MWIFIEX_RATE_INDEX_OFDM0 4 - - #define MWIFIEX_MAX_STA_NUM 3 --#define MWIFIEX_MAX_UAP_NUM 3 -+#define MWIFIEX_MAX_UAP_NUM 4 - #define MWIFIEX_MAX_P2P_NUM 3 - - #define MWIFIEX_A_BAND_START_FREQ 5000 diff --git a/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch index c8d24283a..96b1ce77e 100644 --- a/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch +++ b/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c -@@ -6289,6 +6289,8 @@ static int mwl8k_probe(struct pci_dev *p +@@ -6285,6 +6285,8 @@ static int mwl8k_probe(struct pci_dev *p priv->running_bsses = 0; @@ -9,7 +9,7 @@ return rc; err_stop_firmware: -@@ -6322,8 +6324,6 @@ static void mwl8k_remove(struct pci_dev +@@ -6318,8 +6320,6 @@ static void mwl8k_remove(struct pci_dev return; priv = hw->priv; diff --git a/package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch b/package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch deleted file mode 100644 index 98ed9e60e..000000000 --- a/package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch +++ /dev/null @@ -1,189 +0,0 @@ -From f7252b1b5755150535af226e806594bbefd45e0f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Sun, 26 Sep 2021 14:39:44 +0200 -Subject: [PATCH] mwifiex: Print stringified name of command in error log -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Failed hex command number in error log is hard to understand. -So add also more human readable stringified command name into error log. - -Signed-off-by: Pali Rohár ---- - drivers/net/wireless/marvell/mwifiex/cmdevt.c | 96 +++++++++++++++++-- - drivers/net/wireless/marvell/mwifiex/main.h | 2 + - .../wireless/marvell/mwifiex/sta_cmdresp.c | 5 +- - .../net/wireless/marvell/mwifiex/uap_cmd.c | 3 +- - 4 files changed, 95 insertions(+), 11 deletions(-) - ---- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c -+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c -@@ -16,6 +16,85 @@ - - static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); - -+const char * -+mwifiex_cmd_to_str(u16 command) -+{ -+ switch (command) { -+ case HostCmd_CMD_GET_HW_SPEC: return "GET_HW_SPEC"; -+ case HostCmd_CMD_802_11_SCAN: return "SCAN"; -+ case HostCmd_CMD_802_11_GET_LOG: return "GET_LOG"; -+ case HostCmd_CMD_MAC_MULTICAST_ADR: return "MAC_MULTICAST_ADR"; -+ case HostCmd_CMD_802_11_EEPROM_ACCESS: return "EEPROM_ACCESS"; -+ case HostCmd_CMD_802_11_ASSOCIATE: return "ASSOCIATE"; -+ case HostCmd_CMD_802_11_SNMP_MIB: return "SNMP_MIB"; -+ case HostCmd_CMD_MAC_REG_ACCESS: return "MAC_REG_ACCESS"; -+ case HostCmd_CMD_BBP_REG_ACCESS: return "BBP_REG_ACCESS"; -+ case HostCmd_CMD_RF_REG_ACCESS: return "RF_REG_ACCESS"; -+ case HostCmd_CMD_PMIC_REG_ACCESS: return "PMIC_REG_ACCESS"; -+ case HostCmd_CMD_RF_TX_PWR: return "RF_TX_PWR"; -+ case HostCmd_CMD_RF_ANTENNA: return "RF_ANTENNA"; -+ case HostCmd_CMD_802_11_DEAUTHENTICATE: return "DEAUTHENTICATE"; -+ case HostCmd_CMD_MAC_CONTROL: return "MAC_CONTROL"; -+ case HostCmd_CMD_802_11_AD_HOC_START: return "AD_HOC_START"; -+ case HostCmd_CMD_802_11_AD_HOC_JOIN: return "AD_HOC_JOIN"; -+ case HostCmd_CMD_802_11_AD_HOC_STOP: return "AD_HOC_STOP"; -+ case HostCmd_CMD_802_11_MAC_ADDRESS: return "MAC_ADDRESS"; -+ case HostCmd_CMD_802_11D_DOMAIN_INFO: return "DOMAIN_INFO"; -+ case HostCmd_CMD_802_11_KEY_MATERIAL: return "KEY_MATERIAL"; -+ case HostCmd_CMD_802_11_BG_SCAN_CONFIG: return "BG_SCAN_CONFIG"; -+ case HostCmd_CMD_802_11_BG_SCAN_QUERY: return "BG_SCAN_QUERY"; -+ case HostCmd_CMD_WMM_GET_STATUS: return "WMM_GET_STATUS"; -+ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: return "SUBSCRIBE_EVENT"; -+ case HostCmd_CMD_802_11_TX_RATE_QUERY: return "TX_RATE_QUERY"; -+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: return "IBSS_COALESCING_STATUS"; -+ case HostCmd_CMD_MEM_ACCESS: return "MEM_ACCESS"; -+ case HostCmd_CMD_CFG_DATA: return "CFG_DATA"; -+ case HostCmd_CMD_VERSION_EXT: return "VERSION_EXT"; -+ case HostCmd_CMD_MEF_CFG: return "MEF_CFG"; -+ case HostCmd_CMD_RSSI_INFO: return "RSSI_INFO"; -+ case HostCmd_CMD_FUNC_INIT: return "FUNC_INIT"; -+ case HostCmd_CMD_FUNC_SHUTDOWN: return "FUNC_SHUTDOWN"; -+ case HOST_CMD_APCMD_SYS_RESET: return "SYS_RESET"; -+ case HostCmd_CMD_UAP_SYS_CONFIG: return "UAP_SYS_CONFIG"; -+ case HostCmd_CMD_UAP_BSS_START: return "UAP_BSS_START"; -+ case HostCmd_CMD_UAP_BSS_STOP: return "UAP_BSS_STOP"; -+ case HOST_CMD_APCMD_STA_LIST: return "STA_LIST"; -+ case HostCmd_CMD_UAP_STA_DEAUTH: return "UAP_STA_DEAUTH"; -+ case HostCmd_CMD_11N_CFG: return "11N_CFG"; -+ case HostCmd_CMD_11N_ADDBA_REQ: return "ADDBA_REQ"; -+ case HostCmd_CMD_11N_ADDBA_RSP: return "ADDBA_RSP"; -+ case HostCmd_CMD_11N_DELBA: return "DELBA"; -+ case HostCmd_CMD_RECONFIGURE_TX_BUFF: return "RECONFIGURE_TX_BUFF"; -+ case HostCmd_CMD_CHAN_REPORT_REQUEST: return "CHAN_REPORT_REQUEST"; -+ case HostCmd_CMD_AMSDU_AGGR_CTRL: return "AMSDU_AGGR_CTRL"; -+ case HostCmd_CMD_TXPWR_CFG: return "TXPWR_CFG"; -+ case HostCmd_CMD_TX_RATE_CFG: return "TX_RATE_CFG"; -+ case HostCmd_CMD_ROBUST_COEX: return "ROBUST_COEX"; -+ case HostCmd_CMD_802_11_PS_MODE_ENH: return "PS_MODE_ENH"; -+ case HostCmd_CMD_802_11_HS_CFG_ENH: return "HS_CFG_ENH"; -+ case HostCmd_CMD_P2P_MODE_CFG: return "P2P_MODE_CFG"; -+ case HostCmd_CMD_CAU_REG_ACCESS: return "CAU_REG_ACCESS"; -+ case HostCmd_CMD_SET_BSS_MODE: return "SET_BSS_MODE"; -+ case HostCmd_CMD_PCIE_DESC_DETAILS: return "PCIE_DESC_DETAILS"; -+ case HostCmd_CMD_802_11_SCAN_EXT: return "SCAN_EXT"; -+ case HostCmd_CMD_COALESCE_CFG: return "COALESCE_CFG"; -+ case HostCmd_CMD_MGMT_FRAME_REG: return "MGMT_FRAME_REG"; -+ case HostCmd_CMD_REMAIN_ON_CHAN: return "REMAIN_ON_CHAN"; -+ case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG: return "GTK_REKEY_OFFLOAD_CFG"; -+ case HostCmd_CMD_11AC_CFG: return "11AC_CFG"; -+ case HostCmd_CMD_HS_WAKEUP_REASON: return "HS_WAKEUP_REASON"; -+ case HostCmd_CMD_TDLS_CONFIG: return "TDLS_CONFIG"; -+ case HostCmd_CMD_MC_POLICY: return "MC_POLICY"; -+ case HostCmd_CMD_TDLS_OPER: return "TDLS_OPER"; -+ case HostCmd_CMD_FW_DUMP_EVENT: return "FW_DUMP_EVENT"; -+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: return "SDIO_SP_RX_AGGR_CFG"; -+ case HostCmd_CMD_STA_CONFIGURE: return "STA_CONFIGURE"; -+ case HostCmd_CMD_CHAN_REGION_CFG: return "CHAN_REGION_CFG"; -+ case HostCmd_CMD_PACKET_AGGR_CTRL: return "PACKET_AGGR_CTRL"; -+ default: return "UNKNOWN"; -+ } -+} -+ - /* - * This function initializes a command node. - * -@@ -193,8 +272,8 @@ static int mwifiex_dnld_cmd_to_fw(struct - cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && - cmd_code != HostCmd_CMD_FUNC_INIT) { - mwifiex_dbg(adapter, ERROR, -- "DNLD_CMD: FW in reset state, ignore cmd %#x\n", -- cmd_code); -+ "DNLD_CMD: FW in reset state, ignore cmd %s (%#x)\n", -+ mwifiex_cmd_to_str(cmd_code), cmd_code); - mwifiex_recycle_cmd_node(adapter, cmd_node); - queue_work(adapter->workqueue, &adapter->main_work); - return -1; -@@ -653,8 +732,8 @@ int mwifiex_send_cmd(struct mwifiex_priv - /* Return error, since the command preparation failed */ - if (ret) { - mwifiex_dbg(adapter, ERROR, -- "PREP_CMD: cmd %#x preparation failed\n", -- cmd_no); -+ "PREP_CMD: cmd %s (%#x) preparation failed\n", -+ mwifiex_cmd_to_str(cmd_no), cmd_no); - mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - return -1; - } -@@ -902,8 +981,9 @@ int mwifiex_process_cmdresp(struct mwifi - if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { - if (ret) { - mwifiex_dbg(adapter, ERROR, -- "%s: cmd %#x failed during\t" -- "initialization\n", __func__, cmdresp_no); -+ "%s: cmd %s (%#x) failed during\t" -+ "initialization\n", __func__, -+ mwifiex_cmd_to_str(cmdresp_no), cmdresp_no); - mwifiex_init_fw_complete(adapter); - return -1; - } else if (adapter->last_init_cmd == cmdresp_no) -@@ -1273,8 +1353,8 @@ mwifiex_process_sleep_confirm_resp(struc - - if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { - mwifiex_dbg(adapter, ERROR, -- "%s: rcvd unexpected resp for cmd %#x, result = %x\n", -- __func__, command, result); -+ "%s: rcvd unexpected resp for cmd %s (%#x), result = %x\n", -+ __func__, mwifiex_cmd_to_str(command), command, result); - return; - } - ---- a/drivers/net/wireless/marvell/mwifiex/main.h -+++ b/drivers/net/wireless/marvell/mwifiex/main.h -@@ -1099,6 +1099,8 @@ void mwifiex_cancel_all_pending_cmd(stru - void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter); - void mwifiex_cancel_scan(struct mwifiex_adapter *adapter); - -+const char *mwifiex_cmd_to_str(u16 command); -+ - void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter, - struct cmd_ctrl_node *cmd_node); - ---- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c -+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c -@@ -36,8 +36,9 @@ mwifiex_process_cmdresp_error(struct mwi - struct host_cmd_ds_802_11_ps_mode_enh *pm; - - mwifiex_dbg(adapter, ERROR, -- "CMD_RESP: cmd %#x error, result=%#x\n", -- resp->command, resp->result); -+ "CMD_RESP: cmd %s (%#x) error, result=%#x\n", -+ mwifiex_cmd_to_str(le16_to_cpu(resp->command)), -+ le16_to_cpu(resp->command), le16_to_cpu(resp->result)); - - if (adapter->curr_cmd->wait_q_enabled) - adapter->cmd_wait_q.status = -1; ---- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c -+++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c -@@ -794,7 +794,8 @@ int mwifiex_uap_prepare_cmd(struct mwifi - break; - default: - mwifiex_dbg(priv->adapter, ERROR, -- "PREP_CMD: unknown cmd %#x\n", cmd_no); -+ "PREP_CMD: unknown cmd (%s) %#x\n", -+ mwifiex_cmd_to_str(cmd_no), cmd_no); - return -1; - } - diff --git a/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch new file mode 100644 index 000000000..96eeb37dc --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch @@ -0,0 +1,51 @@ +From patchwork Thu Dec 27 14:05:26 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: Tom Psyborg +X-Patchwork-Id: 10743707 +X-Patchwork-Delegate: kvalo@adurom.com +From: =?utf-8?q?Tomislav_Po=C5=BEega?= +To: linux-wireless@vger.kernel.org +Cc: kvalo@codeaurora.org, hauke@hauke-m.de, nbd@nbd.name, + john@phrozen.org, sgruszka@redhat.com, daniel@makrotopia.org +Subject: [PATCH 2/2] rt2x00: define RF5592 in init_eeprom routine +Date: Thu, 27 Dec 2018 15:05:26 +0100 +Message-Id: <1545919526-4074-2-git-send-email-pozega.tomislav@gmail.com> +X-Mailer: git-send-email 1.7.0.4 +In-Reply-To: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com> +References: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com> +MIME-Version: 1.0 +Sender: linux-wireless-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-wireless@vger.kernel.org +X-Virus-Scanned: ClamAV using ClamSMTP + +This patch fixes following crash on Linksys EA2750 during 5GHz wifi +init: + +[ 7.955153] rt2800pci 0000:01:00.0: card - bus=0x1, slot = 0x0 irq=4 +[ 7.962259] rt2800pci 0000:01:00.0: loaded eeprom from mtd device "Factory" +[ 7.969435] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 5592, rev 0222 detected +[ 7.977348] ieee80211 phy0: rt2800_init_eeprom: Error - Invalid RF chipset 0x0000 detected +[ 7.985793] ieee80211 phy0: rt2x00lib_probe_dev: Error - Failed to allocate device +[ 7.993569] CPU 0 Unable to handle kernel paging request at virtual address 00000024, epc == 800c8f54, ra == 80249ff8 +[ 8.004408] Oops[#1]: + +Signed-off-by: Tomislav Požega +--- + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -9435,6 +9435,8 @@ static int rt2800_init_eeprom(struct rt2 + rf = RF3853; + else if (rt2x00_rt(rt2x00dev, RT5350)) + rf = RF5350; ++ else if (rt2x00_rt(rt2x00dev, RT5592)) ++ rf = RF5592; + else + rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE); + diff --git a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch index 7d6e0cef2..aeb950b49 100644 --- a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch +++ b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch @@ -1,6 +1,6 @@ --- a/local-symbols +++ b/local-symbols -@@ -354,6 +354,7 @@ RT2X00_LIB_FIRMWARE= +@@ -324,6 +324,7 @@ RT2X00_LIB_FIRMWARE= RT2X00_LIB_CRYPTO= RT2X00_LIB_LEDS= RT2X00_LIB_DEBUGFS= @@ -48,7 +48,7 @@ obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h -@@ -47,6 +47,8 @@ struct rt2800_drv_data { +@@ -37,6 +37,8 @@ struct rt2800_drv_data { struct ieee80211_sta *wcid_to_sta[STA_IDS_SIZE]; }; @@ -57,7 +57,7 @@ struct rt2800_ops { u32 (*register_read)(struct rt2x00_dev *rt2x00dev, const unsigned int offset); -@@ -145,6 +147,15 @@ static inline int rt2800_read_eeprom(str +@@ -135,6 +137,15 @@ static inline int rt2800_read_eeprom(str { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; @@ -95,7 +95,7 @@ /* Firmware functions */ static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev) { -@@ -168,7 +155,6 @@ static const struct rt2800_ops rt2800soc +@@ -167,7 +154,6 @@ static const struct rt2800_ops rt2800soc .register_multiread = rt2x00mmio_register_multiread, .register_multiwrite = rt2x00mmio_register_multiwrite, .regbusy_read = rt2x00mmio_regbusy_read, @@ -127,7 +127,7 @@ DECLARE_KFIFO_PTR(txstatus_fifo, u32); --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c -@@ -1419,6 +1419,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de +@@ -1401,6 +1401,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep); @@ -138,7 +138,7 @@ /* * Let the driver probe the device to detect the capabilities. */ -@@ -1559,6 +1563,11 @@ void rt2x00lib_remove_dev(struct rt2x00_ +@@ -1541,6 +1545,11 @@ void rt2x00lib_remove_dev(struct rt2x00_ * Free the driver data. */ kfree(rt2x00dev->drv_data); diff --git a/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch b/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch index 8964f8bf1..38f8b7717 100644 --- a/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch +++ b/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch @@ -13,7 +13,7 @@ Signed-off-by: John Crispin --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c -@@ -225,10 +225,17 @@ static int rt2800soc_probe(struct platfo +@@ -224,10 +224,17 @@ static int rt2800soc_probe(struct platfo return rt2x00soc_probe(pdev, &rt2800soc_ops); } diff --git a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch index acc8a8edb..d78b76d7f 100644 --- a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch +++ b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch @@ -8,7 +8,7 @@ #include "rt2x00.h" #include "rt2800lib.h" -@@ -11131,6 +11132,17 @@ static int rt2800_init_eeprom(struct rt2 +@@ -9549,6 +9550,17 @@ static int rt2800_init_eeprom(struct rt2 rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); diff --git a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch index 5ef5fc8de..0da9356e0 100644 --- a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch +++ b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c -@@ -1358,7 +1358,7 @@ static inline void rt2x00lib_set_if_comb +@@ -1340,7 +1340,7 @@ static inline void rt2x00lib_set_if_comb */ if_limit = &rt2x00dev->if_limits_ap; if_limit->max = rt2x00dev->ops->max_ap_intf; diff --git a/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch new file mode 100644 index 000000000..6e6564f87 --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch @@ -0,0 +1,44 @@ +From: David Bauer +Date: Mon, 16 Dec 2019 20:47:06 +0100 +Subject: [PATCH] rt2x00: add throughput LED trigger + +This adds a (currently missing) throughput LED trigger for the rt2x00 +driver. Previously, LED triggers had to be assigned to the netdev, which +was limited to a single VAP. + +Signed-off-by: David Bauer +Tested-by: Christoph Krapp + +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +@@ -1125,6 +1125,19 @@ static void rt2x00lib_remove_hw(struct r + kfree(rt2x00dev->spec.channels_info); + } + ++static const struct ieee80211_tpt_blink rt2x00_tpt_blink[] = { ++ { .throughput = 0 * 1024, .blink_time = 334 }, ++ { .throughput = 1 * 1024, .blink_time = 260 }, ++ { .throughput = 2 * 1024, .blink_time = 220 }, ++ { .throughput = 5 * 1024, .blink_time = 190 }, ++ { .throughput = 10 * 1024, .blink_time = 170 }, ++ { .throughput = 25 * 1024, .blink_time = 150 }, ++ { .throughput = 54 * 1024, .blink_time = 130 }, ++ { .throughput = 120 * 1024, .blink_time = 110 }, ++ { .throughput = 265 * 1024, .blink_time = 80 }, ++ { .throughput = 586 * 1024, .blink_time = 50 }, ++}; ++ + static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) + { + struct hw_mode_spec *spec = &rt2x00dev->spec; +@@ -1206,6 +1219,10 @@ static int rt2x00lib_probe_hw(struct rt2 + + #undef RT2X00_TASKLET_INIT + ++ ieee80211_create_tpt_led_trigger(rt2x00dev->hw, ++ IEEE80211_TPT_LEDTRIG_FL_RADIO, rt2x00_tpt_blink, ++ ARRAY_SIZE(rt2x00_tpt_blink)); ++ + /* + * Register HW. + */ diff --git a/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch new file mode 100644 index 000000000..8814c0253 --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch @@ -0,0 +1,107 @@ +From 9782a7f7488443568fa4d6088b73c9aff7eb8510 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 19 Apr 2017 16:14:53 +0200 +Subject: [PATCH] rt2x00: add support for external PA on MT7620 +To: Stanislaw Gruszka +Cc: Helmut Schaa , + linux-wireless@vger.kernel.org, + Kalle Valo +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +Signed-off-by: Daniel Golle +Signed-off-by: Tomislav Po=C5=BEega +[pozega.tomislav@gmail.com: use chanreg and dccal helpers.] + +--- + drivers/net/wireless/ralink/rt2x00/rt2800.h | 1 + + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 70 +++++++++++++++++++++++++- + 2 files changed, 70 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h +@@ -2739,6 +2739,7 @@ enum rt2800_eeprom_word { + #define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f) + #define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0) + #define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600) ++#define EEPROM_NIC_CONF2_EXTERNAL_PA FIELD16(0xc000) + + /* + * EEPROM LNA +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -4369,6 +4369,45 @@ static void rt2800_config_channel(struct + rt2800_iq_calibrate(rt2x00dev, rf->channel); + } + ++ if (rt2x00_rt(rt2x00dev, RT6352)) { ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, ++ &rt2x00dev->cap_flags)) { ++ rt2x00_warn(rt2x00dev, "Using incomplete support for " \ ++ "external PA\n"); ++ reg = rt2800_register_read(rt2x00dev, RF_CONTROL3); ++ reg |= 0x00000101; ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, reg); ++ ++ reg = rt2800_register_read(rt2x00dev, RF_BYPASS3); ++ reg |= 0x00000101; ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, reg); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x73); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x73); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x73); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0xC8); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xA4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x05); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0xC8); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xA4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x05); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0xC8); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xA4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x05); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 05, 0x00); ++ ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, ++ 0x36303636); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, ++ 0x6C6C6B6C); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, ++ 0x6C6C6B6C); ++ } ++ } ++ + bbp = rt2800_bbp_read(rt2x00dev, 4); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); + rt2800_bbp_write(rt2x00dev, 4, bbp); +@@ -9578,7 +9617,8 @@ static int rt2800_init_eeprom(struct rt2 + */ + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); + +- if (rt2x00_rt(rt2x00dev, RT3352)) { ++ if (rt2x00_rt(rt2x00dev, RT3352) || ++ rt2x00_rt(rt2x00dev, RT6352)) { + if (rt2x00_get_field16(eeprom, + EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352)) + __set_bit(CAPABILITY_EXTERNAL_PA_TX0, +@@ -9589,6 +9629,18 @@ static int rt2800_init_eeprom(struct rt2 + &rt2x00dev->cap_flags); + } + ++ eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF2); ++ ++ if (rt2x00_rt(rt2x00dev, RT6352) && eeprom != 0 && eeprom != 0xffff) { ++ if (rt2x00_get_field16(eeprom, ++ EEPROM_NIC_CONF2_EXTERNAL_PA)) { ++ __set_bit(CAPABILITY_EXTERNAL_PA_TX0, ++ &rt2x00dev->cap_flags); ++ __set_bit(CAPABILITY_EXTERNAL_PA_TX1, ++ &rt2x00dev->cap_flags); ++ } ++ } ++ + return 0; + } + diff --git a/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch new file mode 100644 index 000000000..b798dcc6d --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch @@ -0,0 +1,67 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -8438,6 +8438,56 @@ static void rt2800_init_rfcsr_5592(struc + rt2800_led_open_drain_enable(rt2x00dev); + } + ++static void rt2800_rf_self_txdc_cal(struct rt2x00_dev *rt2x00dev) ++{ ++ u8 rfb5r1_org, rfb7r1_org, rfvalue; ++ u32 mac0518, mac051c, mac0528, mac052c; ++ u8 i; ++ ++ rt2x00_info(rt2x00dev, "RF Tx self calibration start\n"); ++ mac0518 = rt2800_register_read(rt2x00dev, RF_CONTROL0); ++ mac051c = rt2800_register_read(rt2x00dev, RF_BYPASS0); ++ mac0528 = rt2800_register_read(rt2x00dev, RF_CONTROL2); ++ mac052c = rt2800_register_read(rt2x00dev, RF_BYPASS2); ++ ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x0); ++ rt2800_register_write(rt2x00dev, RF_BYPASS2, 0x0); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0xC); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x3306); ++ rt2800_register_write(rt2x00dev, RF_CONTROL2, 0x3330); ++ rt2800_register_write(rt2x00dev, RF_BYPASS2, 0xfffff); ++ rfb5r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); ++ rfb7r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, 0x4); ++ for (i = 0; i < 100; i = i + 1) { ++ udelay(50); ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); ++ if((rfvalue & 0x04) != 0x4) ++ break; ++ } ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, rfb5r1_org); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, 0x4); ++ for (i = 0; i < 100; i = i + 1) { ++ udelay(50); ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1); ++ if((rfvalue & 0x04) != 0x4) ++ break; ++ } ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, rfb7r1_org); ++ ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x0); ++ rt2800_register_write(rt2x00dev, RF_BYPASS2, 0x0); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, mac0518); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, mac051c); ++ rt2800_register_write(rt2x00dev, RF_CONTROL2, mac0528); ++ rt2800_register_write(rt2x00dev, RF_BYPASS2, mac052c); ++ ++ rt2x00_info(rt2x00dev, "RF Tx self calibration end\n"); ++} ++ + static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, + bool set_bw, bool is_ht40) + { +@@ -9045,6 +9095,7 @@ static void rt2800_init_rfcsr_6352(struc + rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); + rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); + ++ rt2800_rf_self_txdc_cal(rt2x00dev); + rt2800_bw_filter_calibration(rt2x00dev, true); + rt2800_bw_filter_calibration(rt2x00dev, false); + } diff --git a/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch b/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch new file mode 100644 index 000000000..cf21c39a6 --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch @@ -0,0 +1,166 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -8488,6 +8488,155 @@ static void rt2800_rf_self_txdc_cal(stru + rt2x00_info(rt2x00dev, "RF Tx self calibration end\n"); + } + ++static int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2) ++{ ++ int calcode; ++ calcode = ((d2 - d1) * 1000) / 43; ++ if ((calcode%10) >= 5) ++ calcode += 10; ++ calcode = (calcode / 10); ++ ++ return calcode; ++} ++ ++static void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev) ++{ ++ u32 savemacsysctrl; ++ u8 saverfb0r1, saverfb0r34, saverfb0r35; ++ u8 saverfb5r4, saverfb5r17, saverfb5r18; ++ u8 saverfb5r19, saverfb5r20; ++ u8 savebbpr22, savebbpr47, savebbpr49; ++ u8 bytevalue = 0; ++ int rcalcode; ++ u8 r_cal_code = 0; ++ char d1 = 0, d2 = 0; ++ u8 rfvalue; ++ u32 MAC_RF_BYPASS0, MAC_RF_CONTROL0, MAC_PWR_PIN_CFG; ++ u32 maccfg, macstatus; ++ int i; ++ ++ saverfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1); ++ saverfb0r34 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 34); ++ saverfb0r35 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35); ++ saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); ++ saverfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); ++ saverfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18); ++ saverfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19); ++ saverfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20); ++ ++ savebbpr22 = rt2800_bbp_read(rt2x00dev, 22); ++ savebbpr47 = rt2800_bbp_read(rt2x00dev, 47); ++ savebbpr49 = rt2800_bbp_read(rt2x00dev, 49); ++ ++ savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ MAC_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0); ++ MAC_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0); ++ MAC_PWR_PIN_CFG = rt2800_register_read(rt2x00dev, PWR_PIN_CFG); ++ ++ maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ maccfg &= (~0x04); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg); ++ ++ for (i = 0; i < 10000; i++) { ++ macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macstatus & 0x1) ++ udelay(50); ++ else ++ break; ++ } ++ ++ if (i == 10000) ++ rt2x00_warn(rt2x00dev, "Wait MAC Tx Status to MAX !!!\n"); ++ ++ maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ maccfg &= (~0x04); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg); ++ ++ for (i = 0; i < 10000; i++) { ++ macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macstatus & 0x2) ++ udelay(50); ++ else ++ break; ++ } ++ ++ if (i == 10000) ++ rt2x00_warn(rt2x00dev, "Wait MAC Rx Status to MAX !!!\n"); ++ ++ rfvalue = (MAC_RF_BYPASS0 | 0x3004); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, rfvalue); ++ rfvalue = (MAC_RF_CONTROL0 | (~0x3002)); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, rfvalue); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, 0x27); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, 0x80); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0x83); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x00); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x20); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x00); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 34, 0x13); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00); ++ ++ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x1); ++ ++ rt2800_bbp_write(rt2x00dev, 47, 0x04); ++ rt2800_bbp_write(rt2x00dev, 22, 0x80); ++ udelay(100); ++ bytevalue = rt2800_bbp_read(rt2x00dev, 49); ++ if (bytevalue > 128) ++ d1 = bytevalue - 256; ++ else ++ d1 = (char)bytevalue; ++ rt2800_bbp_write(rt2x00dev, 22, 0x0); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x01); ++ ++ rt2800_bbp_write(rt2x00dev, 22, 0x80); ++ udelay(100); ++ bytevalue = rt2800_bbp_read(rt2x00dev, 49); ++ if (bytevalue > 128) ++ d2 = bytevalue - 256; ++ else ++ d2 = (char)bytevalue; ++ rt2800_bbp_write(rt2x00dev, 22, 0x0); ++ ++ rcalcode = rt2800_calcrcalibrationcode(rt2x00dev, d1, d2); ++ if (rcalcode < 0) ++ r_cal_code = 256 + rcalcode; ++ else ++ r_cal_code = (u8)rcalcode; ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 7, r_cal_code); ++ ++ rt2800_bbp_write(rt2x00dev, 22, 0x0); ++ ++ bytevalue = rt2800_bbp_read(rt2x00dev, 21); ++ bytevalue |= 0x1; ++ rt2800_bbp_write(rt2x00dev, 21, bytevalue); ++ bytevalue = rt2800_bbp_read(rt2x00dev, 21); ++ bytevalue &= (~0x1); ++ rt2800_bbp_write(rt2x00dev, 21, bytevalue); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, saverfb0r1); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 34, saverfb0r34); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, saverfb0r35); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, saverfb5r17); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, saverfb5r18); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, saverfb5r19); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, saverfb5r20); ++ ++ rt2800_bbp_write(rt2x00dev, 22, savebbpr22); ++ rt2800_bbp_write(rt2x00dev, 47, savebbpr47); ++ rt2800_bbp_write(rt2x00dev, 49, savebbpr49); ++ ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, MAC_RF_BYPASS0); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, MAC_RF_CONTROL0); ++ ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl); ++ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG); ++} ++ + static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, + bool set_bw, bool is_ht40) + { +@@ -9095,6 +9244,7 @@ static void rt2800_init_rfcsr_6352(struc + rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); + rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); + ++ rt2800_r_calibration(rt2x00dev); + rt2800_rf_self_txdc_cal(rt2x00dev); + rt2800_bw_filter_calibration(rt2x00dev, true); + rt2800_bw_filter_calibration(rt2x00dev, false); diff --git a/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch new file mode 100644 index 000000000..1f8684b0b --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch @@ -0,0 +1,81 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -8637,6 +8637,70 @@ static void rt2800_r_calibration(struct + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG); + } + ++static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev) ++{ ++ u8 bbpreg = 0; ++ u32 macvalue = 0, macvalue1 = 0; ++ u8 saverfb0r2, saverfb5r4, saverfb7r4, rfvalue; ++ int i; ++ ++ saverfb0r2 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2); ++ rfvalue = saverfb0r2; ++ rfvalue |= 0x03; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfvalue); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 141); ++ bbpreg = rt2800_bbp_read(rt2x00dev, 159); ++ bbpreg |= 0x10; ++ rt2800_bbp_write(rt2x00dev, 159, bbpreg); ++ ++ macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x8); ++ ++ for (i = 0; i < 10000; i++) { ++ macvalue1 = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macvalue1 & 0x1) ++ udelay(50); ++ else ++ break; ++ } ++ ++ saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); ++ saverfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4); ++ saverfb5r4 = saverfb5r4 & (~0x40); ++ saverfb7r4 = saverfb7r4 & (~0x40); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x64); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 141); ++ bbpreg = rt2800_bbp_read(rt2x00dev, 159); ++ bbpreg = bbpreg & (~0x40); ++ rt2800_bbp_write(rt2x00dev, 159, bbpreg); ++ bbpreg |= 0x48; ++ rt2800_bbp_write(rt2x00dev, 159, bbpreg); ++ ++ for (i = 0; i < 10000; i++) { ++ bbpreg = rt2800_bbp_read(rt2x00dev, 159); ++ if ((bbpreg & 0x40)==0) ++ break; ++ udelay(50); ++ } ++ ++ bbpreg = rt2800_bbp_read(rt2x00dev, 159); ++ bbpreg = bbpreg & (~0x40); ++ rt2800_bbp_write(rt2x00dev, 159, bbpreg); ++ ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 141); ++ bbpreg = rt2800_bbp_read(rt2x00dev, 159); ++ bbpreg &= (~0x10); ++ rt2800_bbp_write(rt2x00dev, 159, bbpreg); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2); ++} ++ + static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, + bool set_bw, bool is_ht40) + { +@@ -9246,6 +9310,7 @@ static void rt2800_init_rfcsr_6352(struc + + rt2800_r_calibration(rt2x00dev); + rt2800_rf_self_txdc_cal(rt2x00dev); ++ rt2800_rxdcoc_calibration(rt2x00dev); + rt2800_bw_filter_calibration(rt2x00dev, true); + rt2800_bw_filter_calibration(rt2x00dev, false); + } diff --git a/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch b/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch new file mode 100644 index 000000000..98f2e245c --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch @@ -0,0 +1,395 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -8701,6 +8701,384 @@ static void rt2800_rxdcoc_calibration(st + rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2); + } + ++static u32 rt2800_do_sqrt_accumulation(u32 si) { ++ u32 root, root_pre, bit; ++ char i; ++ bit = 1 << 15; ++ root = 0; ++ for (i = 15; i >= 0; i = i - 1) { ++ root_pre = root + bit; ++ if ((root_pre*root_pre) <= si) ++ root = root_pre; ++ bit = bit >> 1; ++ } ++ ++ return root; ++} ++ ++static void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev) { ++ u8 rfb0r1, rfb0r2, rfb0r42; ++ u8 rfb4r0, rfb4r19; ++ u8 rfb5r3, rfb5r4, rfb5r17, rfb5r18, rfb5r19, rfb5r20; ++ u8 rfb6r0, rfb6r19; ++ u8 rfb7r3, rfb7r4, rfb7r17, rfb7r18, rfb7r19, rfb7r20; ++ ++ u8 bbp1, bbp4; ++ u8 bbpr241, bbpr242; ++ u32 i; ++ u8 ch_idx; ++ u8 bbpval; ++ u8 rfval, vga_idx = 0; ++ int mi = 0, mq = 0, si = 0, sq = 0, riq = 0; ++ int sigma_i, sigma_q, r_iq, g_rx; ++ int g_imb; ++ int ph_rx; ++ u32 savemacsysctrl = 0; ++ u32 orig_RF_CONTROL0 = 0; ++ u32 orig_RF_BYPASS0 = 0; ++ u32 orig_RF_CONTROL1 = 0; ++ u32 orig_RF_BYPASS1 = 0; ++ u32 orig_RF_CONTROL3 = 0; ++ u32 orig_RF_BYPASS3 = 0; ++ u32 macstatus, bbpval1 = 0; ++ u8 rf_vga_table[] = {0x20, 0x21, 0x22, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; ++ ++ savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ orig_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0); ++ orig_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0); ++ orig_RF_CONTROL1 = rt2800_register_read(rt2x00dev, RF_CONTROL1); ++ orig_RF_BYPASS1 = rt2800_register_read(rt2x00dev, RF_BYPASS1); ++ orig_RF_CONTROL3 = rt2800_register_read(rt2x00dev, RF_CONTROL3); ++ orig_RF_BYPASS3 = rt2800_register_read(rt2x00dev, RF_BYPASS3); ++ ++ bbp1 = rt2800_bbp_read(rt2x00dev, 1); ++ bbp4 = rt2800_bbp_read(rt2x00dev, 4); ++ ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x0); ++ ++ for (i = 0; i < 10000; i++) { ++ macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macstatus & 0x3) ++ udelay(50); ++ else ++ break; ++ } ++ ++ if (i == 10000) ++ rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n"); ++ ++ bbpval = bbp4 & (~0x18); ++ bbpval = bbp4 | 0x00; ++ rt2800_bbp_write(rt2x00dev, 4, bbpval); ++ ++ bbpval = rt2800_bbp_read(rt2x00dev, 21); ++ bbpval = bbpval | 1; ++ rt2800_bbp_write(rt2x00dev, 21, bbpval); ++ bbpval = bbpval & 0xfe; ++ rt2800_bbp_write(rt2x00dev, 21, bbpval); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL1, 0x00000202); ++ rt2800_register_write(rt2x00dev, RF_BYPASS1, 0x00000303); ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0101); ++ else ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0000); ++ ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, 0xf1f1); ++ ++ rfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1); ++ rfb0r2 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2); ++ rfb0r42 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42); ++ rfb4r0 = rt2800_rfcsr_read_bank(rt2x00dev, 4, 0); ++ rfb4r19 = rt2800_rfcsr_read_bank(rt2x00dev, 4, 19); ++ rfb5r3 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); ++ rfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); ++ rfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); ++ rfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18); ++ rfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19); ++ rfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20); ++ ++ rfb6r0 = rt2800_rfcsr_read_bank(rt2x00dev, 6, 0); ++ rfb6r19 = rt2800_rfcsr_read_bank(rt2x00dev, 6, 19); ++ rfb7r3 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 3); ++ rfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4); ++ rfb7r17 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 17); ++ rfb7r18 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 18); ++ rfb7r19 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 19); ++ rfb7r20 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 20); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x87); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0x27); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x38); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x38); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x80); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 18, 0xC1); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 19, 0x60); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 20, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 23, 0x0); ++ rt2800_bbp_write(rt2x00dev, 24, 0x0); ++ ++ rt2800_bbp_dcoc_write(rt2x00dev, 5, 0x0); ++ ++ bbpr241 = rt2800_bbp_read(rt2x00dev, 241); ++ bbpr242 = rt2800_bbp_read(rt2x00dev, 242); ++ ++ rt2800_bbp_write(rt2x00dev, 241, 0x10); ++ rt2800_bbp_write(rt2x00dev, 242, 0x84); ++ rt2800_bbp_write(rt2x00dev, 244, 0x31); ++ ++ bbpval = rt2800_bbp_dcoc_read(rt2x00dev, 3); ++ bbpval = bbpval & (~0x7); ++ rt2800_bbp_dcoc_write(rt2x00dev, 3, bbpval); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004); ++ udelay(1); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000006); ++ usleep_range(1, 200); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003376); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006); ++ udelay(1); ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_bbp_write(rt2x00dev, 23, 0x06); ++ rt2800_bbp_write(rt2x00dev, 24, 0x06); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 23, 0x02); ++ rt2800_bbp_write(rt2x00dev, 24, 0x02); ++ } ++ ++ for (ch_idx = 0; ch_idx < 2; ch_idx = ch_idx + 1) { ++ if (ch_idx == 0) { ++ rfval = rfb0r1 & (~0x3); ++ rfval = rfb0r1 | 0x1; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfval); ++ rfval = rfb0r2 & (~0x33); ++ rfval = rfb0r2 | 0x11; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfval); ++ rfval = rfb0r42 & (~0x50); ++ rfval = rfb0r42 | 0x10; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfval); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006); ++ udelay(1); ++ ++ bbpval = bbp1 & (~ 0x18); ++ bbpval = bbpval | 0x00; ++ rt2800_bbp_write(rt2x00dev, 1, bbpval); ++ ++ rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x00); ++ } else { ++ rfval = rfb0r1 & (~0x3); ++ rfval = rfb0r1 | 0x2; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfval); ++ rfval = rfb0r2 & (~0x33); ++ rfval = rfb0r2 | 0x22; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfval); ++ rfval = rfb0r42 & (~0x50); ++ rfval = rfb0r42 | 0x40; ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfval); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002006); ++ udelay(1); ++ ++ bbpval = bbp1 & (~ 0x18); ++ bbpval = bbpval | 0x08; ++ rt2800_bbp_write(rt2x00dev, 1, bbpval); ++ ++ rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x01); ++ } ++ udelay(500); ++ ++ vga_idx = 0; ++ while (vga_idx < 11) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, rf_vga_table[vga_idx]); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, rf_vga_table[vga_idx]); ++ ++ rt2800_bbp_dcoc_write(rt2x00dev, 0, 0x93); ++ ++ for (i = 0; i < 10000; i++) { ++ bbpval = rt2800_bbp_read(rt2x00dev, 159); ++ if ((bbpval & 0xff) == 0x93) ++ udelay(50); ++ else ++ break; ++ } ++ ++ if ((bbpval & 0xff) == 0x93) { ++ rt2x00_warn(rt2x00dev, "Fatal Error: Calibration doesn't finish"); ++ goto restore_value; ++ } ++ ++ for (i = 0; i < 5; i++) { ++ u32 bbptemp = 0; ++ u8 value = 0; ++ int result = 0; ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x1e); ++ rt2800_bbp_write(rt2x00dev, 159, i); ++ rt2800_bbp_write(rt2x00dev, 158, 0x22); ++ value = rt2800_bbp_read(rt2x00dev, 159); ++ bbptemp = bbptemp + (value << 24); ++ rt2800_bbp_write(rt2x00dev, 158, 0x21); ++ value = rt2800_bbp_read(rt2x00dev, 159); ++ bbptemp = bbptemp + (value << 16); ++ rt2800_bbp_write(rt2x00dev, 158, 0x20); ++ value = rt2800_bbp_read(rt2x00dev, 159); ++ bbptemp = bbptemp + (value << 8); ++ rt2800_bbp_write(rt2x00dev, 158, 0x1f); ++ value = rt2800_bbp_read(rt2x00dev, 159); ++ bbptemp = bbptemp + value; ++ ++ if ((i < 2) && (bbptemp & 0x800000)) ++ result = (bbptemp & 0xffffff) - 0x1000000; ++ else if (i == 4) ++ result = bbptemp; ++ else ++ result = bbptemp; ++ ++ if (i == 0) ++ mi = result/4096; ++ else if (i == 1) ++ mq = result/4096; ++ else if (i == 2) ++ si = bbptemp/4096; ++ else if (i == 3) ++ sq = bbptemp/4096; ++ else ++ riq = result/4096; ++ } ++ ++ bbpval1 = si - mi*mi; ++ rt2x00_dbg(rt2x00dev, "RXIQ si=%d, sq=%d, riq=%d, bbpval %d, vga_idx %d", si, sq, riq, bbpval1, vga_idx); ++ ++ if (bbpval1 >= (100*100)) ++ break; ++ ++ if (bbpval1 <= 100) ++ vga_idx = vga_idx + 9; ++ else if (bbpval1 <= 158) ++ vga_idx = vga_idx + 8; ++ else if (bbpval1 <= 251) ++ vga_idx = vga_idx + 7; ++ else if (bbpval1 <= 398) ++ vga_idx = vga_idx + 6; ++ else if (bbpval1 <= 630) ++ vga_idx = vga_idx + 5; ++ else if (bbpval1 <= 1000) ++ vga_idx = vga_idx + 4; ++ else if (bbpval1 <= 1584) ++ vga_idx = vga_idx + 3; ++ else if (bbpval1 <= 2511) ++ vga_idx = vga_idx + 2; ++ else ++ vga_idx = vga_idx + 1; ++ } ++ ++ sigma_i = rt2800_do_sqrt_accumulation(100*(si - mi*mi)); ++ sigma_q = rt2800_do_sqrt_accumulation(100*(sq - mq*mq)); ++ r_iq = 10*(riq-(mi*mq)); ++ ++ rt2x00_dbg(rt2x00dev, "Sigma_i=%d, Sigma_q=%d, R_iq=%d", sigma_i, sigma_q, r_iq); ++ ++ if (((sigma_i <= 1400 ) && (sigma_i >= 1000)) ++ && ((sigma_i - sigma_q) <= 112) ++ && ((sigma_i - sigma_q) >= -112) ++ && ((mi <= 32) && (mi >= -32)) ++ && ((mq <= 32) && (mq >= -32))) { ++ r_iq = 10*(riq-(mi*mq)); ++ rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq); ++ ++ g_rx = (1000 * sigma_q) / sigma_i; ++ g_imb = ((-2) * 128 * (1000 - g_rx)) / (1000 + g_rx); ++ ph_rx = (r_iq * 2292) / (sigma_i * sigma_q); ++ rt2x00_info(rt2x00dev, "RXIQ G_imb=%d, Ph_rx=%d\n", g_imb, ph_rx); ++ ++ if ((ph_rx > 20) || (ph_rx < -20)) { ++ ph_rx = 0; ++ rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL"); ++ } ++ ++ if ((g_imb > 12) || (g_imb < -12)) { ++ g_imb = 0; ++ rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL"); ++ } ++ } ++ else { ++ g_imb = 0; ++ ph_rx = 0; ++ rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq); ++ rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL"); ++ } ++ ++ if (ch_idx == 0) { ++ rt2800_bbp_write(rt2x00dev, 158, 0x37); ++ rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f); ++ rt2800_bbp_write(rt2x00dev, 158, 0x35); ++ rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 158, 0x55); ++ rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f); ++ rt2800_bbp_write(rt2x00dev, 158, 0x53); ++ rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f); ++ } ++ } ++ ++restore_value: ++ rt2800_bbp_write(rt2x00dev, 158, 0x3); ++ bbpval = rt2800_bbp_read(rt2x00dev, 159); ++ rt2800_bbp_write(rt2x00dev, 159, (bbpval | 0x07)); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x00); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ rt2800_bbp_write(rt2x00dev, 1, bbp1); ++ rt2800_bbp_write(rt2x00dev, 4, bbp4); ++ rt2800_bbp_write(rt2x00dev, 241, bbpr241); ++ rt2800_bbp_write(rt2x00dev, 242, bbpr242); ++ ++ rt2800_bbp_write(rt2x00dev, 244, 0x00); ++ bbpval = rt2800_bbp_read(rt2x00dev, 21); ++ bbpval |= 0x1; ++ rt2800_bbp_write(rt2x00dev, 21, bbpval); ++ usleep_range(10, 200); ++ bbpval &= 0xfe; ++ rt2800_bbp_write(rt2x00dev, 21, bbpval); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfb0r1); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfb0r2); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfb0r42); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 0, rfb4r0); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 19, rfb4r19); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rfb5r3); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rfb5r4); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, rfb5r17); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, rfb5r18); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, rfb5r19); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, rfb5r20); ++ ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 0, rfb6r0); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 19, rfb6r19); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 3, rfb7r3); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, rfb7r4); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 17, rfb7r17); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 18, rfb7r18); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 19, rfb7r19); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 20, rfb7r20); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000006); ++ udelay(1); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004); ++ udelay(1); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, orig_RF_CONTROL0); ++ udelay(1); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, orig_RF_BYPASS0); ++ rt2800_register_write(rt2x00dev, RF_CONTROL1, orig_RF_CONTROL1); ++ rt2800_register_write(rt2x00dev, RF_BYPASS1, orig_RF_BYPASS1); ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, orig_RF_CONTROL3); ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, orig_RF_BYPASS3); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl); ++} ++ + static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, + bool set_bw, bool is_ht40) + { +@@ -9313,6 +9691,7 @@ static void rt2800_init_rfcsr_6352(struc + rt2800_rxdcoc_calibration(rt2x00dev); + rt2800_bw_filter_calibration(rt2x00dev, true); + rt2800_bw_filter_calibration(rt2x00dev, false); ++ rt2800_rxiq_calibration(rt2x00dev); + } + + static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) diff --git a/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch b/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch new file mode 100644 index 000000000..6a685f80a --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch @@ -0,0 +1,973 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -9079,6 +9079,943 @@ restore_value: + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl); + } + ++static void rt2800_rf_configstore(struct rt2x00_dev *rt2x00dev, rf_reg_pair rf_reg_record[][13], u8 chain) ++{ ++ u8 rfvalue = 0; ++ ++ if (chain == CHAIN_0) { ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1); ++ rf_reg_record[CHAIN_0][0].bank = 0; ++ rf_reg_record[CHAIN_0][0].reg = 1; ++ rf_reg_record[CHAIN_0][0].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2); ++ rf_reg_record[CHAIN_0][1].bank = 0; ++ rf_reg_record[CHAIN_0][1].reg = 2; ++ rf_reg_record[CHAIN_0][1].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35); ++ rf_reg_record[CHAIN_0][2].bank = 0; ++ rf_reg_record[CHAIN_0][2].reg = 35; ++ rf_reg_record[CHAIN_0][2].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42); ++ rf_reg_record[CHAIN_0][3].bank = 0; ++ rf_reg_record[CHAIN_0][3].reg = 42; ++ rf_reg_record[CHAIN_0][3].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 4, 0); ++ rf_reg_record[CHAIN_0][4].bank = 4; ++ rf_reg_record[CHAIN_0][4].reg = 0; ++ rf_reg_record[CHAIN_0][4].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 4, 2); ++ rf_reg_record[CHAIN_0][5].bank = 4; ++ rf_reg_record[CHAIN_0][5].reg = 2; ++ rf_reg_record[CHAIN_0][5].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 4, 34); ++ rf_reg_record[CHAIN_0][6].bank = 4; ++ rf_reg_record[CHAIN_0][6].reg = 34; ++ rf_reg_record[CHAIN_0][6].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); ++ rf_reg_record[CHAIN_0][7].bank = 5; ++ rf_reg_record[CHAIN_0][7].reg = 3; ++ rf_reg_record[CHAIN_0][7].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); ++ rf_reg_record[CHAIN_0][8].bank = 5; ++ rf_reg_record[CHAIN_0][8].reg = 4; ++ rf_reg_record[CHAIN_0][8].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); ++ rf_reg_record[CHAIN_0][9].bank = 5; ++ rf_reg_record[CHAIN_0][9].reg = 17; ++ rf_reg_record[CHAIN_0][9].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18); ++ rf_reg_record[CHAIN_0][10].bank = 5; ++ rf_reg_record[CHAIN_0][10].reg = 18; ++ rf_reg_record[CHAIN_0][10].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19); ++ rf_reg_record[CHAIN_0][11].bank = 5; ++ rf_reg_record[CHAIN_0][11].reg = 19; ++ rf_reg_record[CHAIN_0][11].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20); ++ rf_reg_record[CHAIN_0][12].bank = 5; ++ rf_reg_record[CHAIN_0][12].reg = 20; ++ rf_reg_record[CHAIN_0][12].value = rfvalue; ++ } else if (chain == CHAIN_1) { ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1); ++ rf_reg_record[CHAIN_1][0].bank = 0; ++ rf_reg_record[CHAIN_1][0].reg = 1; ++ rf_reg_record[CHAIN_1][0].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2); ++ rf_reg_record[CHAIN_1][1].bank = 0; ++ rf_reg_record[CHAIN_1][1].reg = 2; ++ rf_reg_record[CHAIN_1][1].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35); ++ rf_reg_record[CHAIN_1][2].bank = 0; ++ rf_reg_record[CHAIN_1][2].reg = 35; ++ rf_reg_record[CHAIN_1][2].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42); ++ rf_reg_record[CHAIN_1][3].bank = 0; ++ rf_reg_record[CHAIN_1][3].reg = 42; ++ rf_reg_record[CHAIN_1][3].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 6, 0); ++ rf_reg_record[CHAIN_1][4].bank = 6; ++ rf_reg_record[CHAIN_1][4].reg = 0; ++ rf_reg_record[CHAIN_1][4].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 6, 2); ++ rf_reg_record[CHAIN_1][5].bank = 6; ++ rf_reg_record[CHAIN_1][5].reg = 2; ++ rf_reg_record[CHAIN_1][5].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 6, 34); ++ rf_reg_record[CHAIN_1][6].bank = 6; ++ rf_reg_record[CHAIN_1][6].reg = 34; ++ rf_reg_record[CHAIN_1][6].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 3); ++ rf_reg_record[CHAIN_1][7].bank = 7; ++ rf_reg_record[CHAIN_1][7].reg = 3; ++ rf_reg_record[CHAIN_1][7].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4); ++ rf_reg_record[CHAIN_1][8].bank = 7; ++ rf_reg_record[CHAIN_1][8].reg = 4; ++ rf_reg_record[CHAIN_1][8].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 17); ++ rf_reg_record[CHAIN_1][9].bank = 7; ++ rf_reg_record[CHAIN_1][9].reg = 17; ++ rf_reg_record[CHAIN_1][9].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 18); ++ rf_reg_record[CHAIN_1][10].bank = 7; ++ rf_reg_record[CHAIN_1][10].reg = 18; ++ rf_reg_record[CHAIN_1][10].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 19); ++ rf_reg_record[CHAIN_1][11].bank = 7; ++ rf_reg_record[CHAIN_1][11].reg = 19; ++ rf_reg_record[CHAIN_1][11].value = rfvalue; ++ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 20); ++ rf_reg_record[CHAIN_1][12].bank = 7; ++ rf_reg_record[CHAIN_1][12].reg = 20; ++ rf_reg_record[CHAIN_1][12].value = rfvalue; ++ } else { ++ rt2x00_warn(rt2x00dev, "Unknown chain = %u\n", chain); ++ return; ++ } ++ ++ return; ++} ++ ++static void rt2800_rf_configrecover(struct rt2x00_dev *rt2x00dev, rf_reg_pair rf_record[][13]) ++{ ++ u8 chain_index = 0, record_index = 0; ++ u8 bank = 0, rf_register = 0, value = 0; ++ ++ for (chain_index = 0; chain_index < 2; chain_index++) { ++ for (record_index = 0; record_index < 13; record_index++) { ++ bank = rf_record[chain_index][record_index].bank; ++ rf_register = rf_record[chain_index][record_index].reg; ++ value = rf_record[chain_index][record_index].value; ++ rt2800_rfcsr_write_bank(rt2x00dev, bank, rf_register, value); ++ rt2x00_dbg(rt2x00dev, "bank: %d, rf_register: %d, value: %x\n", bank, rf_register, value); ++ } ++ } ++ ++ return; ++} ++ ++static void rt2800_setbbptonegenerator(struct rt2x00_dev *rt2x00dev) ++{ ++ rt2800_bbp_write(rt2x00dev, 158, 0xAA); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xAB); ++ rt2800_bbp_write(rt2x00dev, 159, 0x0A); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xAC); ++ rt2800_bbp_write(rt2x00dev, 159, 0x3F); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xAD); ++ rt2800_bbp_write(rt2x00dev, 159, 0x3F); ++ ++ rt2800_bbp_write(rt2x00dev, 244, 0x40); ++ ++ return; ++} ++ ++static u32 rt2800_do_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx, u8 read_neg) ++{ ++ u32 macvalue = 0; ++ int fftout_i = 0, fftout_q = 0; ++ u32 ptmp=0, pint = 0; ++ u8 bbp = 0; ++ u8 tidxi; ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x00); ++ rt2800_bbp_write(rt2x00dev, 159, 0x9b); ++ ++ bbp = 0x9b; ++ ++ while (bbp == 0x9b) { ++ udelay(10); ++ bbp = rt2800_bbp_read(rt2x00dev, 159); ++ bbp = bbp & 0xff; ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xba); ++ rt2800_bbp_write(rt2x00dev, 159, tidx); ++ rt2800_bbp_write(rt2x00dev, 159, tidx); ++ rt2800_bbp_write(rt2x00dev, 159, tidx); ++ ++ macvalue = rt2800_register_read(rt2x00dev, 0x057C); ++ ++ fftout_i = (macvalue >> 16); ++ fftout_i = (fftout_i & 0x8000) ? (fftout_i - 0x10000) : fftout_i; ++ fftout_q = (macvalue & 0xffff); ++ fftout_q = (fftout_q & 0x8000) ? (fftout_q - 0x10000) : fftout_q; ++ ptmp = (fftout_i * fftout_i); ++ ptmp = ptmp + (fftout_q * fftout_q); ++ pint = ptmp; ++ rt2x00_dbg(rt2x00dev, "I = %d, Q = %d, power = %x\n", fftout_i, fftout_q, pint); ++ if (read_neg) { ++ pint = pint >> 1; ++ tidxi = 0x40 - tidx; ++ tidxi = tidxi & 0x3f; ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xba); ++ rt2800_bbp_write(rt2x00dev, 159, tidxi); ++ rt2800_bbp_write(rt2x00dev, 159, tidxi); ++ rt2800_bbp_write(rt2x00dev, 159, tidxi); ++ ++ macvalue = rt2800_register_read(rt2x00dev, 0x057C); ++ ++ fftout_i = (macvalue >> 16); ++ fftout_i = (fftout_i & 0x8000) ? (fftout_i - 0x10000) : fftout_i; ++ fftout_q = (macvalue & 0xffff); ++ fftout_q = (fftout_q & 0x8000) ? (fftout_q - 0x10000) : fftout_q; ++ ptmp = (fftout_i * fftout_i); ++ ptmp = ptmp + (fftout_q * fftout_q); ++ ptmp = ptmp >> 1; ++ pint = pint + ptmp; ++ } ++ ++ return pint; ++} ++ ++static u32 rt2800_read_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx) { ++ u32 macvalue = 0; ++ int fftout_i = 0, fftout_q = 0; ++ u32 ptmp=0, pint = 0; ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xBA); ++ rt2800_bbp_write(rt2x00dev, 159, tidx); ++ rt2800_bbp_write(rt2x00dev, 159, tidx); ++ rt2800_bbp_write(rt2x00dev, 159, tidx); ++ ++ macvalue = rt2800_register_read(rt2x00dev, 0x057C); ++ ++ fftout_i = (macvalue >> 16); ++ fftout_i = (fftout_i & 0x8000) ? (fftout_i - 0x10000) : fftout_i; ++ fftout_q = (macvalue & 0xffff); ++ fftout_q = (fftout_q & 0x8000) ? (fftout_q - 0x10000) : fftout_q; ++ ptmp = (fftout_i * fftout_i); ++ ptmp = ptmp + (fftout_q * fftout_q); ++ pint = ptmp; ++ rt2x00_info(rt2x00dev, "I = %d, Q = %d, power = %x\n", fftout_i, fftout_q, pint); ++ ++ return pint; ++} ++ ++static void rt2800_write_dc(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 alc, u8 iorq, u8 dc) ++{ ++ u8 bbp = 0; ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xb0); ++ bbp = alc | 0x80; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ ++ if (ch_idx == 0) ++ bbp = (iorq == 0) ? 0xb1: 0xb2; ++ else ++ bbp = (iorq == 0) ? 0xb8: 0xb9; ++ ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ bbp = dc; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ ++ return; ++} ++ ++static void rt2800_loft_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 alc_idx, u8 dc_result[][RF_ALC_NUM][2]) ++{ ++ u32 p0 = 0, p1 = 0, pf = 0; ++ char idx0 = 0, idx1 = 0; ++ u8 idxf[] = {0x00, 0x00}; ++ u8 ibit = 0x20; ++ u8 iorq; ++ char bidx; ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xb0); ++ rt2800_bbp_write(rt2x00dev, 159, 0x80); ++ ++ for (bidx = 5; bidx >= 0; bidx--) { ++ for (iorq = 0; iorq <= 1; iorq++) { ++ rt2x00_dbg(rt2x00dev, "\n========================================================\n"); ++ ++ if (idxf[iorq] == 0x20) { ++ idx0 = 0x20; ++ p0 = pf; ++ } else { ++ idx0 = idxf[iorq] - ibit; ++ idx0 = idx0 & 0x3F; ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idx0); ++ p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0); ++ } ++ ++ idx1 = idxf[iorq] + ((bidx == 5) ? 0 : ibit); ++ idx1 = idx1 & 0x3F; ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idx1); ++ p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0); ++ ++ rt2x00_dbg(rt2x00dev, "alc=%u, IorQ=%u, idx_final=%2x\n", alc_idx, iorq, idxf[iorq]); ++ rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pf=%x, idx_0=%x, idx_1=%x, ibit=%x !\n", p0, p1, pf, idx0, idx1, ibit); ++ ++ if ((bidx != 5) && (pf <= p0) && (pf < p1)) { ++ pf = pf; ++ idxf[iorq] = idxf[iorq]; ++ } else if (p0 < p1) { ++ pf = p0; ++ idxf[iorq] = idx0 & 0x3F; ++ } else { ++ pf = p1; ++ idxf[iorq] = idx1 & 0x3F; ++ } ++ rt2x00_dbg(rt2x00dev, "IorQ=%u, idx_final[%u]:%x, pf:%8x\n", iorq, iorq, idxf[iorq], pf); ++ ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idxf[iorq]); ++ ++ } ++ ibit = ibit >> 1; ++ } ++ dc_result[ch_idx][alc_idx][0] = idxf[0]; ++ dc_result[ch_idx][alc_idx][1] = idxf[1]; ++ ++ return; ++} ++ ++static void rt2800_iq_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 *ges, u8 *pes) ++{ ++ u32 p0 = 0, p1 = 0, pf = 0; ++ char perr = 0, gerr = 0, iq_err = 0; ++ char pef = 0, gef = 0; ++ char psta, pend; ++ char gsta, gend; ++ ++ u8 ibit = 0x20; ++ u8 first_search = 0x00, touch_neg_max = 0x00; ++ char idx0 = 0, idx1 = 0; ++ u8 gop; ++ u8 bbp = 0; ++ char bidx; ++ ++ rt2x00_info(rt2x00dev, "IQCalibration Start!\n"); ++ for (bidx = 5; bidx >= 1; bidx--) { ++ for (gop = 0; gop < 2; gop++) { ++ rt2x00_dbg(rt2x00dev, "\n========================================================\n"); ++ ++ if ((gop == 1) || (bidx < 4)) { ++ if (gop == 0) ++ iq_err = gerr; ++ else ++ iq_err = perr; ++ ++ first_search = (gop == 0) ? (bidx == 3) : (bidx == 5); ++ touch_neg_max = (gop) ? ((iq_err & 0x0F) == 0x08) : ((iq_err & 0x3F) == 0x20); ++ ++ if (touch_neg_max) { ++ p0 = pf; ++ idx0 = iq_err; ++ } else { ++ idx0 = iq_err - ibit; ++ bbp = (ch_idx == 0) ? ((gop == 0) ? 0x28 : 0x29): ((gop == 0) ? 0x46 : 0x47); ++ ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, idx0); ++ ++ p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1); ++ } ++ ++ idx1 = iq_err + (first_search ? 0 : ibit); ++ idx1 = (gop == 0) ? (idx1 & 0x0F) : (idx1 & 0x3F); ++ ++ bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 : (gop == 0) ? 0x46 : 0x47; ++ ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, idx1); ++ ++ p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1); ++ ++ rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pwer_final=%x, idx0=%x, idx1=%x, iq_err=%x, gop=%d, ibit=%x !\n", p0, p1, pf, idx0, idx1, iq_err, gop, ibit); ++ ++ if ((!first_search) && (pf <= p0) && (pf < p1)) { ++ pf = pf; ++ } else if (p0 < p1) { ++ pf = p0; ++ iq_err = idx0; ++ } else { ++ pf = p1; ++ iq_err = idx1; ++ } ++ ++ bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 : (gop == 0) ? 0x46 : 0x47; ++ ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, iq_err); ++ ++ if (gop == 0) ++ gerr = iq_err; ++ else ++ perr = iq_err; ++ ++ rt2x00_dbg(rt2x00dev, "IQCalibration pf=%8x (%2x, %2x) !\n", pf, gerr & 0x0F, perr & 0x3F); ++ ++ } ++ } ++ ++ if (bidx > 0) ++ ibit = (ibit >> 1); ++ } ++ gerr = (gerr & 0x08) ? (gerr & 0x0F) - 0x10 : (gerr & 0x0F); ++ perr = (perr & 0x20) ? (perr & 0x3F) - 0x40 : (perr & 0x3F); ++ ++ gerr = (gerr < -0x07) ? -0x07 : (gerr > 0x05) ? 0x05 : gerr; ++ gsta = gerr - 1; ++ gend = gerr + 2; ++ ++ perr = (perr < -0x1f) ? -0x1f : (perr > 0x1d) ? 0x1d : perr; ++ psta = perr - 1; ++ pend = perr + 2; ++ ++ for (gef = gsta; gef <= gend; gef = gef + 1) ++ for (pef = psta; pef <= pend; pef = pef + 1) { ++ bbp = (ch_idx == 0) ? 0x28 : 0x46; ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, gef & 0x0F); ++ ++ bbp = (ch_idx == 0) ? 0x29 : 0x47; ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, pef & 0x3F); ++ ++ p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1); ++ if ((gef == gsta) && (pef == psta)) { ++ pf = p1; ++ gerr = gef; ++ perr = pef; ++ } ++ else if (pf > p1){ ++ pf = p1; ++ gerr = gef; ++ perr = pef; ++ } ++ rt2x00_dbg(rt2x00dev, "Fine IQCalibration p1=%8x pf=%8x (%2x, %2x) !\n", p1, pf, gef & 0x0F, pef & 0x3F); ++ } ++ ++ ges[ch_idx] = gerr & 0x0F; ++ pes[ch_idx] = perr & 0x3F; ++ ++ rt2x00_info(rt2x00dev, "IQCalibration Done! CH = %u, (gain=%2x, phase=%2x)\n", ch_idx, gerr & 0x0F, perr & 0x3F); ++ ++ return; ++} ++ ++static void rt2800_rf_aux_tx0_loopback(struct rt2x00_dev *rt2x00dev) ++{ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x21); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, 0x10); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, 0x1b); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 0, 0x81); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 2, 0x81); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 34, 0xee); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, 0x2d); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, 0x2d); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, 0x80); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0xd7); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0xa2); ++ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x20); ++} ++ ++static void rt2800_rf_aux_tx1_loopback(struct rt2x00_dev *rt2x00dev) ++{ ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x22); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, 0x20); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, 0x4b); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 0, 0x81); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 2, 0x81); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 34, 0xee); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 3, 0x2d); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, 0x2d); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 17, 0x80); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 18, 0xd7); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 19, 0xa2); ++ rt2800_rfcsr_write_bank(rt2x00dev, 7, 20, 0x20); ++} ++ ++void rt2800_loft_iq_calibration(struct rt2x00_dev *rt2x00dev) ++{ ++ rf_reg_pair rf_store[CHAIN_NUM][13]; ++ u32 macorg1 = 0; ++ u32 macorg2 = 0; ++ u32 macorg3 = 0; ++ u32 macorg4 = 0; ++ u32 macorg5 = 0; ++ u32 orig528 = 0; ++ u32 orig52c = 0; ++ ++ u32 savemacsysctrl = 0, mtxcycle = 0; ++ u32 macvalue = 0; ++ u32 mac13b8 = 0; ++ u32 p0 = 0, p1 = 0; ++ u32 p0_idx10 = 0, p1_idx10 = 0; ++ ++ u8 rfvalue; ++ u8 loft_dc_search_result[CHAIN_NUM][RF_ALC_NUM][2]; ++ u8 ger[CHAIN_NUM], per[CHAIN_NUM]; ++ u8 rf_gain[] = {0x00, 0x01, 0x02, 0x04, 0x08, 0x0c}; ++ u8 rfvga_gain_table[] = {0x24, 0x25, 0x26, 0x27, 0x28, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3F}; ++ ++ u8 vga_gain[] = {14, 14}; ++ u8 bbp_2324gain[] = {0x16, 0x14, 0x12, 0x10, 0x0c, 0x08}; ++ u8 bbp = 0, ch_idx = 0, rf_alc_idx = 0, idx = 0; ++ u8 bbpr30, rfb0r39, rfb0r42; ++ u8 bbpr1; ++ u8 bbpr4; ++ u8 bbpr241, bbpr242; ++ u8 count_step; ++ ++ savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ macorg1 = rt2800_register_read(rt2x00dev, TX_PIN_CFG); ++ macorg2 = rt2800_register_read(rt2x00dev, RF_CONTROL0); ++ macorg3 = rt2800_register_read(rt2x00dev, RF_BYPASS0); ++ macorg4 = rt2800_register_read(rt2x00dev, RF_CONTROL3); ++ macorg5 = rt2800_register_read(rt2x00dev, RF_BYPASS3); ++ mac13b8 = rt2800_register_read(rt2x00dev, 0x13b8); ++ orig528 = rt2800_register_read(rt2x00dev, RF_CONTROL2); ++ orig52c = rt2800_register_read(rt2x00dev, RF_BYPASS2); ++ ++ macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ macvalue &= (~0x04); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue); ++ ++ for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) { ++ macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macvalue & 0x01) ++ udelay(50); ++ else ++ break; ++ } ++ ++ macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ macvalue &= (~0x08); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue); ++ ++ for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) { ++ macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macvalue & 0x02) ++ udelay(50); ++ else ++ break; ++ } ++ ++ for (ch_idx = 0; ch_idx < 2; ch_idx++) { ++ rt2800_rf_configstore(rt2x00dev, rf_store, ch_idx); ++ } ++ ++ bbpr30 = rt2800_bbp_read(rt2x00dev, 30); ++ rfb0r39 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 39); ++ rfb0r42 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42); ++ ++ rt2800_bbp_write(rt2x00dev, 30, 0x1F); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 39, 0x80); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, 0x5B); ++ ++ rt2800_bbp_write(rt2x00dev, 23, 0x00); ++ rt2800_bbp_write(rt2x00dev, 24, 0x00); ++ ++ rt2800_setbbptonegenerator(rt2x00dev); ++ ++ for (ch_idx = 0; ch_idx < 2; ch_idx ++) { ++ rt2800_bbp_write(rt2x00dev, 23, 0x00); ++ rt2800_bbp_write(rt2x00dev, 24, 0x00); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00); ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x0000000F); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003306); ++ rt2800_register_write(rt2x00dev, 0x13b8, 0x10); ++ udelay(1); ++ ++ if (ch_idx == 0) { ++ rt2800_rf_aux_tx0_loopback(rt2x00dev); ++ } else { ++ rt2800_rf_aux_tx1_loopback(rt2x00dev); ++ } ++ udelay(1); ++ ++ if (ch_idx == 0) { ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001004); ++ } else { ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002004); ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x05); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x01); ++ if (ch_idx == 0) ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ else ++ rt2800_bbp_write(rt2x00dev, 159, 0x01); ++ ++ vga_gain[ch_idx] = 18; ++ for (rf_alc_idx = 0; rf_alc_idx < 3; rf_alc_idx++) { ++ rt2800_bbp_write(rt2x00dev, 23, bbp_2324gain[rf_alc_idx]); ++ rt2800_bbp_write(rt2x00dev, 24, bbp_2324gain[rf_alc_idx]); ++ ++ macvalue = rt2800_register_read(rt2x00dev, RF_CONTROL3); ++ macvalue &= (~0x0000F1F1); ++ macvalue |= (rf_gain[rf_alc_idx] << 4); ++ macvalue |= (rf_gain[rf_alc_idx] << 12); ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, macvalue); ++ macvalue = (0x0000F1F1); ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, macvalue); ++ ++ if (rf_alc_idx == 0) { ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x21); ++ for (;vga_gain[ch_idx] > 0;vga_gain[ch_idx] = vga_gain[ch_idx] - 2) { ++ rfvalue = rfvga_gain_table[vga_gain[ch_idx]]; ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue); ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x00); ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x00); ++ p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0); ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x21); ++ p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0); ++ rt2x00_dbg(rt2x00dev, "LOFT AGC %d %d\n", p0, p1); ++ if ((p0 < 7000*7000) && (p1 < (7000*7000))) { ++ break; ++ } ++ } ++ ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x00); ++ rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x00); ++ ++ rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n",vga_gain[ch_idx], rfvga_gain_table[vga_gain[ch_idx]]); ++ ++ if (vga_gain[ch_idx] < 0) ++ vga_gain[ch_idx] = 0; ++ } ++ ++ rfvalue = rfvga_gain_table[vga_gain[ch_idx]]; ++ ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue); ++ ++ rt2800_loft_search(rt2x00dev, ch_idx, rf_alc_idx, loft_dc_search_result); ++ } ++ } ++ ++ for (rf_alc_idx = 0; rf_alc_idx < 3; rf_alc_idx++) { ++ for (idx = 0; idx < 4; idx++) { ++ rt2800_bbp_write(rt2x00dev, 158, 0xB0); ++ bbp = (idx<<2) + rf_alc_idx; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ rt2x00_dbg(rt2x00dev, " ALC %2x,", bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xb1); ++ bbp = loft_dc_search_result[CHAIN_0][rf_alc_idx][0x00]; ++ bbp = bbp & 0x3F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ rt2x00_dbg(rt2x00dev, " I0 %2x,", bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xb2); ++ bbp = loft_dc_search_result[CHAIN_0][rf_alc_idx][0x01]; ++ bbp = bbp & 0x3F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ rt2x00_dbg(rt2x00dev, " Q0 %2x,", bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xb8); ++ bbp = loft_dc_search_result[CHAIN_1][rf_alc_idx][0x00]; ++ bbp = bbp & 0x3F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ rt2x00_dbg(rt2x00dev, " I1 %2x,", bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0xb9); ++ bbp = loft_dc_search_result[CHAIN_1][rf_alc_idx][0x01]; ++ bbp = bbp & 0x3F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ rt2x00_dbg(rt2x00dev, " Q1 %2x\n", bbp); ++ } ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 23, 0x00); ++ rt2800_bbp_write(rt2x00dev, 24, 0x00); ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x04); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x00); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ ++ bbp = 0x00; ++ rt2800_bbp_write(rt2x00dev, 244, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 21, 0x01); ++ udelay(1); ++ rt2800_bbp_write(rt2x00dev, 21, 0x00); ++ ++ rt2800_rf_configrecover(rt2x00dev, rf_store); ++ ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, macorg1); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x04); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, macorg2); ++ udelay(1); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, macorg3); ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, macorg4); ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, macorg5); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl); ++ rt2800_register_write(rt2x00dev, RF_CONTROL2, orig528); ++ rt2800_register_write(rt2x00dev, RF_BYPASS2, orig52c); ++ rt2800_register_write(rt2x00dev, 0x13b8, mac13b8); ++ ++ rt2x00_info(rt2x00dev, "LOFT Calibration Done!\n"); ++ ++ savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ macorg1 = rt2800_register_read(rt2x00dev, TX_PIN_CFG); ++ macorg2 = rt2800_register_read(rt2x00dev, RF_CONTROL0); ++ macorg3 = rt2800_register_read(rt2x00dev, RF_BYPASS0); ++ macorg4 = rt2800_register_read(rt2x00dev, RF_CONTROL3); ++ macorg5 = rt2800_register_read(rt2x00dev, RF_BYPASS3); ++ ++ bbpr1 = rt2800_bbp_read(rt2x00dev, 1); ++ bbpr4 = rt2800_bbp_read(rt2x00dev, 4); ++ bbpr241 = rt2800_bbp_read(rt2x00dev, 241); ++ bbpr242 = rt2800_bbp_read(rt2x00dev, 242); ++ mac13b8 = rt2800_register_read(rt2x00dev, 0x13b8); ++ ++ macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ macvalue &= (~0x04); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue); ++ for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) { ++ macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macvalue & 0x01) ++ udelay(50); ++ else ++ break; ++ } ++ ++ macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); ++ macvalue &= (~0x08); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue); ++ for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) { ++ macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); ++ if (macvalue & 0x02) ++ udelay(50); ++ else ++ break; ++ } ++ ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x00000101); ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0000F1F1); ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 23, 0x00); ++ rt2800_bbp_write(rt2x00dev, 24, 0x00); ++ ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_bbp_write(rt2x00dev, 4, bbpr4 & (~0x18)); ++ rt2800_bbp_write(rt2x00dev, 21, 0x01); ++ udelay(1); ++ rt2800_bbp_write(rt2x00dev, 21, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 241, 0x14); ++ rt2800_bbp_write(rt2x00dev, 242, 0x80); ++ rt2800_bbp_write(rt2x00dev, 244, 0x31); ++ } else { ++ rt2800_setbbptonegenerator(rt2x00dev); ++ } ++ ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003306); ++ udelay(1); ++ ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x0000000F); ++ ++ if (!test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x00000000); ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0000F1F1); ++ } ++ ++ rt2800_register_write(rt2x00dev, 0x13b8, 0x00000010); ++ ++ for (ch_idx = 0; ch_idx < 2; ch_idx++) { ++ rt2800_rf_configstore(rt2x00dev, rf_store, ch_idx); ++ } ++ ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x3B); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x3B); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x03); ++ rt2800_bbp_write(rt2x00dev, 159, 0x60); ++ rt2800_bbp_write(rt2x00dev, 158, 0xB0); ++ rt2800_bbp_write(rt2x00dev, 159, 0x80); ++ ++ for (ch_idx = 0; ch_idx < 2; ch_idx ++) { ++ rt2800_bbp_write(rt2x00dev, 23, 0x00); ++ rt2800_bbp_write(rt2x00dev, 24, 0x00); ++ ++ if (ch_idx == 0) { ++ rt2800_bbp_write(rt2x00dev, 158, 0x01); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ bbp = bbpr1 & (~0x18); ++ bbp = bbp | 0x00; ++ rt2800_bbp_write(rt2x00dev, 1, bbp); ++ } ++ rt2800_rf_aux_tx0_loopback(rt2x00dev); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001004); ++ } else { ++ rt2800_bbp_write(rt2x00dev, 158, 0x01); ++ rt2800_bbp_write(rt2x00dev, 159, 0x01); ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags)) { ++ bbp = bbpr1 & (~0x18); ++ bbp = bbp | 0x08; ++ rt2800_bbp_write(rt2x00dev, 1, bbp); ++ } ++ rt2800_rf_aux_tx1_loopback(rt2x00dev); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002004); ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x05); ++ rt2800_bbp_write(rt2x00dev, 159, 0x04); ++ ++ bbp = (ch_idx == 0) ? 0x28 : 0x46; ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_bbp_write(rt2x00dev, 23, 0x06); ++ rt2800_bbp_write(rt2x00dev, 24, 0x06); ++ count_step = 1; ++ } else { ++ rt2800_bbp_write(rt2x00dev, 23, 0x1F); ++ rt2800_bbp_write(rt2x00dev, 24, 0x1F); ++ count_step = 2; ++ } ++ ++ for (;vga_gain[ch_idx] < 19; vga_gain[ch_idx]=(vga_gain[ch_idx] + count_step)) { ++ rfvalue = rfvga_gain_table[vga_gain[ch_idx]]; ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue); ++ ++ bbp = (ch_idx == 0) ? 0x29 : 0x47; ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 0); ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ p0_idx10 = rt2800_read_fft_accumulation(rt2x00dev, 0x0A); ++ } ++ ++ bbp = (ch_idx == 0) ? 0x29 : 0x47; ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, 0x21); ++ p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 0); ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags)) { ++ p1_idx10 = rt2800_read_fft_accumulation(rt2x00dev, 0x0A); ++ } ++ ++ rt2x00_dbg(rt2x00dev, "IQ AGC %d %d\n", p0, p1); ++ ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2x00_dbg(rt2x00dev, "IQ AGC IDX 10 %d %d\n", p0_idx10, p1_idx10); ++ if ((p0_idx10 > 7000*7000) || (p1_idx10 > 7000*7000)) { ++ if (vga_gain[ch_idx]!=0) ++ vga_gain[ch_idx] = vga_gain[ch_idx]-1; ++ break; ++ } ++ } ++ ++ if ((p0 > 2500*2500) || (p1 > 2500*2500)) { ++ break; ++ } ++ } ++ ++ if (vga_gain[ch_idx] > 18) ++ vga_gain[ch_idx] = 18; ++ rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n",vga_gain[ch_idx], rfvga_gain_table[vga_gain[ch_idx]]); ++ ++ bbp = (ch_idx == 0) ? 0x29 : 0x47; ++ rt2800_bbp_write(rt2x00dev, 158, bbp); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ ++ rt2800_iq_search(rt2x00dev, ch_idx, ger, per); ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 23, 0x00); ++ rt2800_bbp_write(rt2x00dev, 24, 0x00); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x04); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x28); ++ bbp = ger[CHAIN_0] & 0x0F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x29); ++ bbp = per[CHAIN_0] & 0x3F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x46); ++ bbp = ger[CHAIN_1] & 0x0F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x47); ++ bbp = per[CHAIN_1] & 0x3F; ++ rt2800_bbp_write(rt2x00dev, 159, bbp); ++ ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_bbp_write(rt2x00dev, 1, bbpr1); ++ rt2800_bbp_write(rt2x00dev, 241, bbpr241); ++ rt2800_bbp_write(rt2x00dev, 242, bbpr242); ++ } ++ rt2800_bbp_write(rt2x00dev, 244, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 158, 0x00); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ rt2800_bbp_write(rt2x00dev, 158, 0xB0); ++ rt2800_bbp_write(rt2x00dev, 159, 0x00); ++ ++ rt2800_bbp_write(rt2x00dev, 30, bbpr30); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 39, rfb0r39); ++ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfb0r42); ++ ++ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) { ++ rt2800_bbp_write(rt2x00dev, 4, bbpr4); ++ } ++ ++ rt2800_bbp_write(rt2x00dev, 21, 0x01); ++ udelay(1); ++ rt2800_bbp_write(rt2x00dev, 21, 0x00); ++ ++ rt2800_rf_configrecover(rt2x00dev, rf_store); ++ ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, macorg1); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00); ++ rt2800_register_write(rt2x00dev, RF_CONTROL0, macorg2); ++ udelay(1); ++ rt2800_register_write(rt2x00dev, RF_BYPASS0, macorg3); ++ rt2800_register_write(rt2x00dev, RF_CONTROL3, macorg4); ++ rt2800_register_write(rt2x00dev, RF_BYPASS3, macorg5); ++ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl); ++ rt2800_register_write(rt2x00dev, 0x13b8, mac13b8); ++ ++ rt2x00_info(rt2x00dev, "TX IQ Calibration Done!\n"); ++ ++ return; ++} ++ + static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, + bool set_bw, bool is_ht40) + { +@@ -9691,6 +10628,7 @@ static void rt2800_init_rfcsr_6352(struc + rt2800_rxdcoc_calibration(rt2x00dev); + rt2800_bw_filter_calibration(rt2x00dev, true); + rt2800_bw_filter_calibration(rt2x00dev, false); ++ rt2800_loft_iq_calibration(rt2x00dev); + rt2800_rxiq_calibration(rt2x00dev); + } + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +@@ -17,6 +17,16 @@ + #define WCID_START 33 + #define WCID_END 222 + #define STA_IDS_SIZE (WCID_END - WCID_START + 2) ++#define CHAIN_0 0x0 ++#define CHAIN_1 0x1 ++#define RF_ALC_NUM 6 ++#define CHAIN_NUM 2 ++ ++typedef struct rf_reg_pair { ++ u8 bank; ++ u8 reg; ++ u8 value; ++} rf_reg_pair; + + /* RT2800 driver data structure */ + struct rt2800_drv_data { diff --git a/package/kernel/mac80211/patches/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch b/package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch similarity index 92% rename from package/kernel/mac80211/patches/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch rename to package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch index 97a56de2b..76114fe9a 100644 --- a/package/kernel/mac80211/patches/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch +++ b/package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch @@ -50,8 +50,8 @@ + static const struct ieee80211_ops rt2800pci_mac80211_ops = { .tx = rt2x00mac_tx, - .wake_tx_queue = ieee80211_handle_wake_tx_queue, -@@ -329,6 +333,9 @@ static const struct rt2800_ops rt2800pci + .start = rt2x00mac_start, +@@ -328,6 +332,9 @@ static const struct rt2800_ops rt2800pci .drv_init_registers = rt2800mmio_init_registers, .drv_get_txwi = rt2800mmio_get_txwi, .drv_get_dma_done = rt2800mmio_get_dma_done, @@ -103,8 +103,8 @@ + static const struct ieee80211_ops rt2800soc_mac80211_ops = { .tx = rt2x00mac_tx, - .wake_tx_queue = ieee80211_handle_wake_tx_queue, -@@ -160,6 +187,9 @@ static const struct rt2800_ops rt2800soc + .start = rt2x00mac_start, +@@ -159,6 +186,9 @@ static const struct rt2800_ops rt2800soc .drv_init_registers = rt2800mmio_init_registers, .drv_get_txwi = rt2800mmio_get_txwi, .drv_get_dma_done = rt2800mmio_get_dma_done, @@ -126,8 +126,8 @@ + static const struct ieee80211_ops rt2800usb_mac80211_ops = { .tx = rt2x00mac_tx, - .wake_tx_queue = ieee80211_handle_wake_tx_queue, -@@ -672,6 +676,9 @@ static const struct rt2800_ops rt2800usb + .start = rt2x00mac_start, +@@ -671,6 +675,9 @@ static const struct rt2800_ops rt2800usb .drv_init_registers = rt2800usb_init_registers, .drv_get_txwi = rt2800usb_get_txwi, .drv_get_dma_done = rt2800usb_get_dma_done, diff --git a/package/kernel/mac80211/patches/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch b/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch similarity index 95% rename from package/kernel/mac80211/patches/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch rename to package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch index dab6e05ff..40b20ec59 100644 --- a/package/kernel/mac80211/patches/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch +++ b/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h -@@ -1044,6 +1044,11 @@ +@@ -1042,6 +1042,11 @@ #define MIMO_PS_CFG_RX_STBY_POL FIELD32(0x00000010) #define MIMO_PS_CFG_RX_RX_STBY0 FIELD32(0x00000020) @@ -14,7 +14,7 @@ */ --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c -@@ -3778,14 +3778,16 @@ static void rt2800_config_channel_rf7620 +@@ -3698,14 +3698,16 @@ static void rt2800_config_channel_rf7620 rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4); rt2800_rfcsr_write(rt2x00dev, 19, rfcsr); @@ -39,7 +39,7 @@ rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620, -@@ -3819,18 +3821,23 @@ static void rt2800_config_channel_rf7620 +@@ -3739,18 +3741,23 @@ static void rt2800_config_channel_rf7620 rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20); } @@ -73,9 +73,9 @@ if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) { if (conf_is_ht40(conf)) { -@@ -3929,25 +3936,29 @@ static void rt2800_config_alc(struct rt2 - if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY))) - rt2x00_warn(rt2x00dev, "RF busy while configuring ALC\n"); +@@ -3850,25 +3857,29 @@ static void rt2800_config_alc(struct rt2 + if (i == 10000) + rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n"); - if (chan->center_freq > 2457) { - bbp = rt2800_bbp_read(rt2x00dev, 30); @@ -121,12 +121,12 @@ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl); rt2800_vco_calibration(rt2x00dev); -@@ -6011,18 +6022,33 @@ static int rt2800_init_registers(struct +@@ -5906,18 +5917,33 @@ static int rt2800_init_registers(struct } else if (rt2x00_rt(rt2x00dev, RT5350)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); } else if (rt2x00_rt(rt2x00dev, RT6352)) { - rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); -- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001); +- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000); - rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); - rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000); - rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); @@ -150,7 +150,7 @@ + 0x00550055); + } else { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); -+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000); + rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); + rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000); + rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); @@ -167,7 +167,7 @@ reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); rt2x00_set_field32(®, TX_ALC_CFG_1_ROS_BUSY_EN, 0); rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); -@@ -7127,14 +7153,16 @@ static void rt2800_init_bbp_6352(struct +@@ -7061,14 +7087,16 @@ static void rt2800_init_bbp_6352(struct rt2800_bbp_write(rt2x00dev, 188, 0x00); rt2800_bbp_write(rt2x00dev, 189, 0x00); @@ -192,7 +192,7 @@ /* BBP for G band GLRT function (BBP_128 ~ BBP_221) */ rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00); -@@ -10408,31 +10436,36 @@ static void rt2800_init_rfcsr_6352(struc +@@ -10407,31 +10435,36 @@ static void rt2800_init_rfcsr_6352(struc rt2800_rfcsr_write(rt2x00dev, 42, 0x5B); rt2800_rfcsr_write(rt2x00dev, 43, 0x00); @@ -254,7 +254,7 @@ /* Initialize RF channel register to default value */ rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03); -@@ -10498,63 +10531,71 @@ static void rt2800_init_rfcsr_6352(struc +@@ -10497,63 +10530,71 @@ static void rt2800_init_rfcsr_6352(struc rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5); @@ -383,7 +383,7 @@ /* Initialize RF DC calibration register to default value */ rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47); -@@ -10617,12 +10658,17 @@ static void rt2800_init_rfcsr_6352(struc +@@ -10616,12 +10657,17 @@ static void rt2800_init_rfcsr_6352(struc rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00); rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00); @@ -404,5 +404,5 @@ + rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); + } - rt6352_enable_pa_pin(rt2x00dev, 0); rt2800_r_calibration(rt2x00dev); + rt2800_rf_self_txdc_cal(rt2x00dev); diff --git a/package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch deleted file mode 100644 index deaa03be6..000000000 --- a/package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 0fce1109f894ec7fcd72cb098843a1eff786716a Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Fri, 16 Sep 2022 20:49:42 +0100 -Subject: [PATCH 16/16] rt2x00: import support for external LNA on MT7620 -To: linux-wireless@vger.kernel.org, - Stanislaw Gruszka , - Helmut Schaa -Cc: Kalle Valo , - David S. Miller , - Eric Dumazet , - Jakub Kicinski , - Paolo Abeni , - Johannes Berg - -In order to carry out calibration on boards with ePA or eLNA the PA pin -needs to be switch to GPIO mode on MT7620. Implement that by selecting -pinctrl state "pa_gpio" which should be defined for MT7620 boards with -eLNA or ePA beside the "default" state. - -Reported-by: Serge Vasilugin -Signed-off-by: Daniel Golle ---- - .../net/wireless/ralink/rt2x00/rt2800lib.c | 58 +++++++++++++++++++ - drivers/net/wireless/ralink/rt2x00/rt2x00.h | 5 ++ - .../net/wireless/ralink/rt2x00/rt2x00soc.c | 15 +++++ - 3 files changed, 78 insertions(+) - ---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c -@@ -304,6 +304,24 @@ static void rt2800_rf_write(struct rt2x0 - mutex_unlock(&rt2x00dev->csr_mutex); - } - -+void rt6352_enable_pa_pin(struct rt2x00_dev *rt2x00dev, int enable) -+{ -+ if (!rt2x00dev->pinctrl) -+ return; -+ -+ if (enable) { -+ if (!rt2x00dev->pins_default) -+ return; -+ -+ pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_default); -+ } else { -+ if (!rt2x00dev->pins_pa_gpio) -+ return; -+ -+ pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_pa_gpio); -+ } -+} -+ - static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = { - [EEPROM_CHIP_ID] = 0x0000, - [EEPROM_VERSION] = 0x0001, -@@ -4469,6 +4487,29 @@ static void rt2800_config_channel(struct - rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, - 0x6C6C6B6C); - } -+ -+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { -+ reg = rt2800_register_read(rt2x00dev, RF_CONTROL3); -+ reg |= 0x00000101; -+ rt2800_register_write(rt2x00dev, RF_CONTROL3, reg); -+ -+ reg = rt2800_register_read(rt2x00dev, RF_BYPASS3); -+ reg |= 0x00000101; -+ rt2800_register_write(rt2x00dev, RF_BYPASS3, reg); -+ -+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66); -+ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20); -+ rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42); -+ rt2800_bbp_write(rt2x00dev, 75, 0x68); -+ rt2800_bbp_write(rt2x00dev, 76, 0x4C); -+ rt2800_bbp_write(rt2x00dev, 79, 0x1C); -+ rt2800_bbp_write(rt2x00dev, 80, 0x0C); -+ rt2800_bbp_write(rt2x00dev, 82, 0xB6); -+ /* bank 0 RF reg 42 and glrt BBP reg 141 will be set in -+ * config channel function in dependence of channel and -+ * HT20/HT40 so don't touch it -+ */ -+ } - } - - bbp = rt2800_bbp_read(rt2x00dev, 4); -@@ -10583,6 +10624,7 @@ static void rt2800_init_rfcsr_6352(struc - rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); - rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); - -+ rt6352_enable_pa_pin(rt2x00dev, 0); - rt2800_r_calibration(rt2x00dev); - rt2800_rf_self_txdc_cal(rt2x00dev); - rt2800_rxdcoc_calibration(rt2x00dev); -@@ -10590,6 +10632,22 @@ static void rt2800_init_rfcsr_6352(struc - rt2800_bw_filter_calibration(rt2x00dev, false); - rt2800_loft_iq_calibration(rt2x00dev); - rt2800_rxiq_calibration(rt2x00dev); -+ rt6352_enable_pa_pin(rt2x00dev, 1); -+ -+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { -+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66); -+ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20); -+ rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42); -+ rt2800_bbp_write(rt2x00dev, 75, 0x68); -+ rt2800_bbp_write(rt2x00dev, 76, 0x4C); -+ rt2800_bbp_write(rt2x00dev, 79, 0x1C); -+ rt2800_bbp_write(rt2x00dev, 80, 0x0C); -+ rt2800_bbp_write(rt2x00dev, 82, 0xB6); -+ /* bank 0 RF reg 42 and glrt BBP reg 141 will be set in config -+ * channel function in dependence of channel and HT20/HT40, -+ * so don't touch them here. -+ */ -+ } - } - - static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) ---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h -+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -1029,6 +1030,11 @@ struct rt2x00_dev { - - /* Clock for System On Chip devices. */ - struct clk *clk; -+ -+ /* pinctrl and states for System On Chip devices with PA/LNA. */ -+ struct pinctrl *pinctrl; -+ struct pinctrl_state *pins_default; -+ struct pinctrl_state *pins_pa_gpio; - }; - - struct rt2x00_bar_list_entry { ---- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c -@@ -97,6 +97,21 @@ int rt2x00soc_probe(struct platform_devi - if (retval) - goto exit_free_reg; - -+ rt2x00dev->pinctrl = devm_pinctrl_get(&pdev->dev); -+ if (IS_ERR(rt2x00dev->pinctrl)) { -+ rt2x00dev->pinctrl = NULL; -+ rt2x00dev->pins_default = NULL; -+ rt2x00dev->pins_pa_gpio = NULL; -+ } else { -+ rt2x00dev->pins_default = pinctrl_lookup_state(rt2x00dev->pinctrl, "default"); -+ if (IS_ERR(rt2x00dev->pins_default)) -+ rt2x00dev->pins_default = NULL; -+ -+ rt2x00dev->pins_pa_gpio = pinctrl_lookup_state(rt2x00dev->pinctrl, "pa_gpio"); -+ if (IS_ERR(rt2x00dev->pins_pa_gpio)) -+ rt2x00dev->pins_pa_gpio = NULL; -+ } -+ - return 0; - - exit_free_reg: diff --git a/package/kernel/mac80211/patches/rt2x00/999-backport-to-linux-5.18.patch b/package/kernel/mac80211/patches/rt2x00/999-backport-to-linux-5.18.patch new file mode 100644 index 000000000..baf83376d --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/999-backport-to-linux-5.18.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +@@ -586,10 +586,18 @@ static void rt2x00usb_assign_endpoint(st + + if (queue->qid == QID_RX) { + pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,19,0) + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0); ++#else ++ queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe); ++#endif + } else { + pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,19,0) + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1); ++#else ++ queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe); ++#endif + } + + if (!queue->usb_maxpacket) diff --git a/package/kernel/mac80211/patches/subsys/0001-v5.16-ieee80211-Add-new-A-MPDU-factor-macro-for-HE-6-GHz-p.patch b/package/kernel/mac80211/patches/subsys/0001-v5.16-ieee80211-Add-new-A-MPDU-factor-macro-for-HE-6-GHz-p.patch new file mode 100644 index 000000000..3092d9c47 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/0001-v5.16-ieee80211-Add-new-A-MPDU-factor-macro-for-HE-6-GHz-p.patch @@ -0,0 +1,27 @@ +From 62b8963cd84df1fc04986cd9b27586acce758f36 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ieee80211: Add new A-MPDU factor macro for HE 6 GHz peer caps + +Add IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR as per IEEE Std 802.11ax-2021, +9.4.2.263 to use for peer max A-MPDU factor in 6 GHz band. + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Acked-by: Johannes Berg +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913175510.193005-1-jouni@codeaurora.org +--- + include/linux/ieee80211.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -2084,6 +2084,7 @@ int ieee80211_get_vht_max_nss(struct iee + + #define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20 + #define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16 ++#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13 + + /* 802.11ax HE PHY capabilities */ + #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02 diff --git a/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch b/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch index 4dd26da2e..5307fd355 100644 --- a/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch +++ b/package/kernel/mac80211/patches/subsys/110-mac80211_keep_keys_on_stop_ap.patch @@ -1,19 +1,12 @@ -From: Felix Fietkau -Date: Mon, 27 Oct 2014 00:00:00 +0100 -Subject: [PATCH] mac80211: preseve AP mode keys across STA reconnect - -Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnect ---- - net/mac80211/cfg.c | 1 - - 1 file changed, 1 deletion(-) +Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -1512,7 +1512,6 @@ static int ieee80211_stop_ap(struct wiph - link_conf->ftmr_params = NULL; +@@ -1319,7 +1319,6 @@ static int ieee80211_stop_ap(struct wiph + sdata->vif.bss_conf.ftmr_params = NULL; __sta_info_flush(sdata, true); - ieee80211_free_keys(sdata, true); - link_conf->enable_beacon = false; + sdata->vif.bss_conf.enable_beacon = false; sdata->beacon_rate_set = false; diff --git a/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch b/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch index f315ae5ca..ffd8807cc 100644 --- a/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch +++ b/package/kernel/mac80211/patches/subsys/120-cfg80211_allow_perm_addr_change.patch @@ -1,12 +1,3 @@ -From: Felix Fietkau -Date: Thu, 11 Dec 2014 00:00:00 +0100 -Subject: [PATCH] cfg80211: add support for changing the device mac address via - sysfs - ---- - net/wireless/sysfs.c | 27 ++++++++++++++++++++++----- - 1 file changed, 22 insertions(+), 5 deletions(-) - --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -24,18 +24,35 @@ static inline struct cfg80211_registered diff --git a/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch b/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch new file mode 100644 index 000000000..2dc6ab360 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch @@ -0,0 +1,67 @@ +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -337,7 +337,7 @@ void ieee80211_restart_hw(struct ieee802 + } + EXPORT_SYMBOL(ieee80211_restart_hw); + +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + static int ieee80211_ifa_changed(struct notifier_block *nb, + unsigned long data, void *arg) + { +@@ -396,7 +396,7 @@ static int ieee80211_ifa_changed(struct + } + #endif + +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + static int ieee80211_ifa6_changed(struct notifier_block *nb, + unsigned long data, void *arg) + { +@@ -1321,14 +1321,14 @@ int ieee80211_register_hw(struct ieee802 + wiphy_unlock(hw->wiphy); + rtnl_unlock(); + +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + local->ifa_notifier.notifier_call = ieee80211_ifa_changed; + result = register_inetaddr_notifier(&local->ifa_notifier); + if (result) + goto fail_ifa; + #endif + +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; + result = register_inet6addr_notifier(&local->ifa6_notifier); + if (result) +@@ -1337,13 +1337,13 @@ int ieee80211_register_hw(struct ieee802 + + return 0; + +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + fail_ifa6: +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + unregister_inetaddr_notifier(&local->ifa_notifier); + #endif + #endif +-#if defined(CONFIG_INET) || defined(CONFIG_IPV6) ++#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6) + fail_ifa: + #endif + wiphy_unregister(local->hw.wiphy); +@@ -1371,10 +1371,10 @@ void ieee80211_unregister_hw(struct ieee + tasklet_kill(&local->tx_pending_tasklet); + tasklet_kill(&local->tasklet); + +-#ifdef CONFIG_INET ++#ifdef __disabled__CONFIG_INET + unregister_inetaddr_notifier(&local->ifa_notifier); + #endif +-#if IS_ENABLED(CONFIG_IPV6) ++#if IS_ENABLED(__disabled__CONFIG_IPV6) + unregister_inet6addr_notifier(&local->ifa6_notifier); + #endif + diff --git a/package/kernel/mac80211/patches/subsys/210-ap_scan.patch b/package/kernel/mac80211/patches/subsys/210-ap_scan.patch index bfbb28c55..0c06829ce 100644 --- a/package/kernel/mac80211/patches/subsys/210-ap_scan.patch +++ b/package/kernel/mac80211/patches/subsys/210-ap_scan.patch @@ -1,19 +1,11 @@ -From: Felix Fietkau -Date: Wed, 3 Oct 2012 00:00:00 +0200 -Subject: [PATCH] mac80211: allow scans in access point mode (for site survey) - ---- - net/mac80211/cfg.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2720,6 +2720,8 @@ static int ieee80211_scan(struct wiphy * +@@ -2497,7 +2497,7 @@ static int ieee80211_scan(struct wiphy * + * the frames sent while scanning on other channel will be + * lost) */ - fallthrough; - case NL80211_IFTYPE_AP: -+ /* skip check */ -+ break; - /* - * If the scan has been forced (and the driver supports - * forcing), don't care about being beaconing already. +- if (sdata->u.ap.beacon && ++ if (0 && sdata->u.ap.beacon && + (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || + !(req->flags & NL80211_SCAN_FLAG_AP))) + return -EOPNOTSUPP; diff --git a/package/kernel/mac80211/patches/subsys/250-drivers-make-clear-mmc_hw_reset-is-for-cards.patch b/package/kernel/mac80211/patches/subsys/250-drivers-make-clear-mmc_hw_reset-is-for-cards.patch new file mode 100644 index 000000000..bfd37fa3f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/250-drivers-make-clear-mmc_hw_reset-is-for-cards.patch @@ -0,0 +1,56 @@ +--- a/drivers/net/wireless/ath/ath10k/sdio.c ++++ b/drivers/net/wireless/ath/ath10k/sdio.c +@@ -1633,7 +1633,11 @@ static void ath10k_sdio_hif_power_down(struct ath10k *ar) + return; + } + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + ret = mmc_hw_reset(ar_sdio->func->card->host); ++#else ++ ret = mmc_hw_reset(ar_sdio->func->card); ++#endif + if (ret) + ath10k_warn(ar, "unable to reset sdio: %d\n", ret); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -4164,7 +4164,11 @@ static int brcmf_sdio_bus_reset(struct device *dev) + + /* reset the adapter */ + sdio_claim_host(sdiodev->func1); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + mmc_hw_reset(sdiodev->func1->card->host); ++#else ++ mmc_hw_reset(sdiodev->func1->card); ++#endif + sdio_release_host(sdiodev->func1); + + brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN); +--- a/drivers/net/wireless/marvell/mwifiex/sdio.c ++++ b/drivers/net/wireless/marvell/mwifiex/sdio.c +@@ -2643,7 +2643,11 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) + + /* Run a HW reset of the SDIO interface. */ + sdio_claim_host(func); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + ret = mmc_hw_reset(func->card->host); ++#else ++ ret = mmc_hw_reset(func->card); ++#endif + sdio_release_host(func); + + switch (ret) { +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -146,7 +146,11 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) + * To guarantee that the SDIO card is power cycled, as required to make + * the FW programming to succeed, let's do a brute force HW reset. + */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + mmc_hw_reset(card->host); ++#else ++ mmc_hw_reset(card); ++#endif + + sdio_enable_func(func); + sdio_release_host(func); diff --git a/package/kernel/mac80211/patches/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch b/package/kernel/mac80211/patches/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch index 63b217747..d09d70725 100644 --- a/package/kernel/mac80211/patches/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch +++ b/package/kernel/mac80211/patches/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch @@ -28,7 +28,7 @@ Signed-off-by: Johannes Berg --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c -@@ -554,6 +554,7 @@ __sta_info_alloc(struct ieee80211_sub_if +@@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct i INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); diff --git a/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch b/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch new file mode 100644 index 000000000..777c93cb9 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch @@ -0,0 +1,62 @@ +From: Xing Song +Date: Tue, 23 Nov 2021 11:31:23 +0800 +Subject: [PATCH] mac80211: set up the fwd_skb->dev for mesh forwarding + +Mesh forwarding requires that the fwd_skb->dev is set up for TX handling, +otherwise the following warning will be generated, so set it up for the +pending frames. + +[ 72.835674 ] WARNING: CPU: 0 PID: 1193 at __skb_flow_dissect+0x284/0x1298 +[ 72.842379 ] Modules linked in: ksmbd pppoe ppp_async l2tp_ppp ... +[ 72.962020 ] CPU: 0 PID: 1193 Comm: kworker/u5:1 Tainted: P S 5.4.137 #0 +[ 72.969938 ] Hardware name: MT7622_MT7531 RFB (DT) +[ 72.974659 ] Workqueue: napi_workq napi_workfn +[ 72.979025 ] pstate: 60000005 (nZCv daif -PAN -UAO) +[ 72.983822 ] pc : __skb_flow_dissect+0x284/0x1298 +[ 72.988444 ] lr : __skb_flow_dissect+0x54/0x1298 +[ 72.992977 ] sp : ffffffc010c738c0 +[ 72.996293 ] x29: ffffffc010c738c0 x28: 0000000000000000 +[ 73.001615 ] x27: 000000000000ffc2 x26: ffffff800c2eb818 +[ 73.006937 ] x25: ffffffc010a987c8 x24: 00000000000000ce +[ 73.012259 ] x23: ffffffc010c73a28 x22: ffffffc010a99c60 +[ 73.017581 ] x21: 000000000000ffc2 x20: ffffff80094da800 +[ 73.022903 ] x19: 0000000000000000 x18: 0000000000000014 +[ 73.028226 ] x17: 00000000084d16af x16: 00000000d1fc0bab +[ 73.033548 ] x15: 00000000715f6034 x14: 000000009dbdd301 +[ 73.038870 ] x13: 00000000ea4dcbc3 x12: 0000000000000040 +[ 73.044192 ] x11: 000000000eb00ff0 x10: 0000000000000000 +[ 73.049513 ] x9 : 000000000eb00073 x8 : 0000000000000088 +[ 73.054834 ] x7 : 0000000000000000 x6 : 0000000000000001 +[ 73.060155 ] x5 : 0000000000000000 x4 : 0000000000000000 +[ 73.065476 ] x3 : ffffffc010a98000 x2 : 0000000000000000 +[ 73.070797 ] x1 : 0000000000000000 x0 : 0000000000000000 +[ 73.076120 ] Call trace: +[ 73.078572 ] __skb_flow_dissect+0x284/0x1298 +[ 73.082846 ] __skb_get_hash+0x7c/0x228 +[ 73.086629 ] ieee80211_txq_may_transmit+0x7fc/0x17b8 [mac80211] +[ 73.092564 ] ieee80211_tx_prepare_skb+0x20c/0x268 [mac80211] +[ 73.098238 ] ieee80211_tx_pending+0x144/0x330 [mac80211] +[ 73.103560 ] tasklet_action_common.isra.16+0xb4/0x158 +[ 73.108618 ] tasklet_action+0x2c/0x38 +[ 73.112286 ] __do_softirq+0x168/0x3b0 +[ 73.115954 ] do_softirq.part.15+0x88/0x98 +[ 73.119969 ] __local_bh_enable_ip+0xb0/0xb8 +[ 73.124156 ] napi_workfn+0x58/0x90 +[ 73.127565 ] process_one_work+0x20c/0x478 +[ 73.131579 ] worker_thread+0x50/0x4f0 +[ 73.135249 ] kthread+0x124/0x128 +[ 73.138484 ] ret_from_fork+0x10/0x1c + +Signed-off-by: Xing Song +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2949,6 +2949,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 + if (!fwd_skb) + goto out; + ++ fwd_skb->dev = sdata->dev; + fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; + fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); + info = IEEE80211_SKB_CB(fwd_skb); diff --git a/package/kernel/mac80211/patches/subsys/306-01-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch b/package/kernel/mac80211/patches/subsys/306-01-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch deleted file mode 100644 index 76869830c..000000000 --- a/package/kernel/mac80211/patches/subsys/306-01-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch +++ /dev/null @@ -1,192 +0,0 @@ -From: Alexander Wetzel -Date: Sun, 9 Oct 2022 18:30:38 +0200 -Subject: [PATCH] wifi: mac80211: add internal handler for wake_tx_queue - -Start to align the TX handling to only use internal TX queues (iTXQs): - -Provide a handler for drivers not having a custom wake_tx_queue -callback and update the documentation. - -Signed-off-by: Alexander Wetzel -Signed-off-by: Johannes Berg ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -89,15 +89,13 @@ - /** - * DOC: mac80211 software tx queueing - * -- * mac80211 provides an optional intermediate queueing implementation designed -- * to allow the driver to keep hardware queues short and provide some fairness -- * between different stations/interfaces. -- * In this model, the driver pulls data frames from the mac80211 queue instead -- * of letting mac80211 push them via drv_tx(). -- * Other frames (e.g. control or management) are still pushed using drv_tx(). -+ * mac80211 uses an intermediate queueing implementation, designed to allow the -+ * driver to keep hardware queues short and to provide some fairness between -+ * different stations/interfaces. - * -- * Drivers indicate that they use this model by implementing the .wake_tx_queue -- * driver operation. -+ * Drivers must provide the .wake_tx_queue driver operation by either -+ * linking it to ieee80211_handle_wake_tx_queue() or implementing a custom -+ * handler. - * - * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with - * another per-sta for non-data/non-mgmt and bufferable management frames, and -@@ -106,9 +104,12 @@ - * The driver is expected to initialize its private per-queue data for stations - * and interfaces in the .add_interface and .sta_add ops. - * -- * The driver can't access the queue directly. To dequeue a frame from a -- * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a -- * queue, it calls the .wake_tx_queue driver op. -+ * The driver can't access the internal TX queues (iTXQs) directly. -+ * Whenever mac80211 adds a new frame to a queue, it calls the .wake_tx_queue -+ * driver op. -+ * Drivers implementing a custom .wake_tx_queue op can get them by calling -+ * ieee80211_tx_dequeue(). Drivers using ieee80211_handle_wake_tx_queue() will -+ * simply get the individual frames pushed via the .tx driver operation. - * - * Drivers can optionally delegate responsibility for scheduling queues to - * mac80211, to take advantage of airtime fairness accounting. In this case, to -@@ -1826,7 +1827,7 @@ struct ieee80211_vif_cfg { - * for this interface. - * @drv_priv: data area for driver use, will always be aligned to - * sizeof(void \*). -- * @txq: the multicast data TX queue (if driver uses the TXQ abstraction) -+ * @txq: the multicast data TX queue - * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped, - * protected by fq->lock. - * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see -@@ -2252,8 +2253,8 @@ struct ieee80211_link_sta { - * For non MLO STA it will point to the deflink data. For MLO STA - * ieee80211_sta_recalc_aggregates() must be called to update it. - * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not. -- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that -- * the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames -+ * @txq: per-TID data TX queues; note that the last entry (%IEEE80211_NUM_TIDS) -+ * is used for non-data frames - * @deflink: This holds the default link STA information, for non MLO STA all link - * specific STA information is accessed through @deflink or through - * link[0] which points to address of @deflink. For MLO Link STA -@@ -5691,7 +5692,7 @@ void ieee80211_key_replay(struct ieee802 - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @queue: queue number (counted from zero). - * -- * Drivers should use this function instead of netif_wake_queue. -+ * Drivers must use this function instead of netif_wake_queue. - */ - void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue); - -@@ -5700,7 +5701,7 @@ void ieee80211_wake_queue(struct ieee802 - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @queue: queue number (counted from zero). - * -- * Drivers should use this function instead of netif_stop_queue. -+ * Drivers must use this function instead of netif_stop_queue. - */ - void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); - -@@ -5709,7 +5710,7 @@ void ieee80211_stop_queue(struct ieee802 - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @queue: queue number (counted from zero). - * -- * Drivers should use this function instead of netif_stop_queue. -+ * Drivers must use this function instead of netif_queue_stopped. - * - * Return: %true if the queue is stopped. %false otherwise. - */ -@@ -5720,7 +5721,7 @@ int ieee80211_queue_stopped(struct ieee8 - * ieee80211_stop_queues - stop all queues - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * -- * Drivers should use this function instead of netif_stop_queue. -+ * Drivers must use this function instead of netif_tx_stop_all_queues. - */ - void ieee80211_stop_queues(struct ieee80211_hw *hw); - -@@ -5728,7 +5729,7 @@ void ieee80211_stop_queues(struct ieee80 - * ieee80211_wake_queues - wake all queues - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * -- * Drivers should use this function instead of netif_wake_queue. -+ * Drivers must use this function instead of netif_tx_wake_all_queues. - */ - void ieee80211_wake_queues(struct ieee80211_hw *hw); - -@@ -6950,6 +6951,18 @@ static inline struct sk_buff *ieee80211_ - } - - /** -+ * ieee80211_handle_wake_tx_queue - mac80211 handler for wake_tx_queue callback -+ * -+ * @hw: pointer as obtained from wake_tx_queue() callback(). -+ * @txq: pointer as obtained from wake_tx_queue() callback(). -+ * -+ * Drivers can use this function for the mandatory mac80211 wake_tx_queue -+ * callback in struct ieee80211_ops. They should not call this function. -+ */ -+void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq); -+ -+/** - * ieee80211_next_txq - get next tx queue to pull packets from - * - * @hw: pointer as obtained from ieee80211_alloc_hw() ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -288,6 +288,52 @@ __le16 ieee80211_ctstoself_duration(stru - } - EXPORT_SYMBOL(ieee80211_ctstoself_duration); - -+static void wake_tx_push_queue(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct ieee80211_txq *queue) -+{ -+ int q = sdata->vif.hw_queue[queue->ac]; -+ struct ieee80211_tx_control control = { -+ .sta = queue->sta, -+ }; -+ struct sk_buff *skb; -+ unsigned long flags; -+ bool q_stopped; -+ -+ while (1) { -+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags); -+ q_stopped = local->queue_stop_reasons[q]; -+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); -+ -+ if (q_stopped) -+ break; -+ -+ skb = ieee80211_tx_dequeue(&local->hw, queue); -+ if (!skb) -+ break; -+ -+ drv_tx(local, &control, skb); -+ } -+} -+ -+/* wake_tx_queue handler for driver not implementing a custom one*/ -+void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq) -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif); -+ struct ieee80211_txq *queue; -+ -+ /* Use ieee80211_next_txq() for airtime fairness accounting */ -+ ieee80211_txq_schedule_start(hw, txq->ac); -+ while ((queue = ieee80211_next_txq(hw, txq->ac))) { -+ wake_tx_push_queue(local, sdata, queue); -+ ieee80211_return_txq(hw, queue, false); -+ } -+ ieee80211_txq_schedule_end(hw, txq->ac); -+} -+EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue); -+ - static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac) - { - struct ieee80211_local *local = sdata->local; diff --git a/package/kernel/mac80211/patches/subsys/306-02-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch b/package/kernel/mac80211/patches/subsys/306-02-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch deleted file mode 100644 index 8e2c20505..000000000 --- a/package/kernel/mac80211/patches/subsys/306-02-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch +++ /dev/null @@ -1,396 +0,0 @@ -From: Alexander Wetzel -Date: Sun, 9 Oct 2022 18:30:39 +0200 -Subject: [PATCH] wifi: mac80211: add wake_tx_queue callback to drivers - -mac80211 is fully switching over to the internal TX queue (iTXQ) -implementation. Update all drivers not yet providing the now mandatory -wake_tx_queue() callback. - -As an side effect the netdev interfaces of all updated drivers will -switch to the noqueue qdisc. - -Signed-off-by: Alexander Wetzel -[add staging drivers] -Signed-off-by: Johannes Berg ---- - ---- a/drivers/net/wireless/admtek/adm8211.c -+++ b/drivers/net/wireless/admtek/adm8211.c -@@ -1760,6 +1760,7 @@ static int adm8211_alloc_rings(struct ie - - static const struct ieee80211_ops adm8211_ops = { - .tx = adm8211_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = adm8211_start, - .stop = adm8211_stop, - .add_interface = adm8211_add_interface, ---- a/drivers/net/wireless/ath/ar5523/ar5523.c -+++ b/drivers/net/wireless/ath/ar5523/ar5523.c -@@ -1355,6 +1355,7 @@ static const struct ieee80211_ops ar5523 - .start = ar5523_start, - .stop = ar5523_stop, - .tx = ar5523_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .set_rts_threshold = ar5523_set_rts_threshold, - .add_interface = ar5523_add_interface, - .remove_interface = ar5523_remove_interface, ---- a/drivers/net/wireless/ath/ath11k/mac.c -+++ b/drivers/net/wireless/ath/ath11k/mac.c -@@ -8539,6 +8539,7 @@ err_fallback: - - static const struct ieee80211_ops ath11k_ops = { - .tx = ath11k_mac_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = ath11k_mac_op_start, - .stop = ath11k_mac_op_stop, - .reconfig_complete = ath11k_mac_op_reconfig_complete, ---- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c -+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c -@@ -781,6 +781,7 @@ static int ath5k_set_ringparam(struct ie - - const struct ieee80211_ops ath5k_hw_ops = { - .tx = ath5k_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = ath5k_start, - .stop = ath5k_stop, - .add_interface = ath5k_add_interface, ---- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c -+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c -@@ -1870,6 +1870,7 @@ static void ath9k_htc_channel_switch_bea - - struct ieee80211_ops ath9k_htc_ops = { - .tx = ath9k_htc_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = ath9k_htc_start, - .stop = ath9k_htc_stop, - .add_interface = ath9k_htc_add_interface, ---- a/drivers/net/wireless/ath/carl9170/main.c -+++ b/drivers/net/wireless/ath/carl9170/main.c -@@ -1715,6 +1715,7 @@ static const struct ieee80211_ops carl91 - .start = carl9170_op_start, - .stop = carl9170_op_stop, - .tx = carl9170_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .flush = carl9170_op_flush, - .add_interface = carl9170_op_add_interface, - .remove_interface = carl9170_op_remove_interface, ---- a/drivers/net/wireless/ath/wcn36xx/main.c -+++ b/drivers/net/wireless/ath/wcn36xx/main.c -@@ -1362,6 +1362,7 @@ static const struct ieee80211_ops wcn36x - .prepare_multicast = wcn36xx_prepare_multicast, - .configure_filter = wcn36xx_configure_filter, - .tx = wcn36xx_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .set_key = wcn36xx_set_key, - .hw_scan = wcn36xx_hw_scan, - .cancel_hw_scan = wcn36xx_cancel_hw_scan, ---- a/drivers/net/wireless/atmel/at76c50x-usb.c -+++ b/drivers/net/wireless/atmel/at76c50x-usb.c -@@ -2187,6 +2187,7 @@ static int at76_set_key(struct ieee80211 - - static const struct ieee80211_ops at76_ops = { - .tx = at76_mac80211_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .add_interface = at76_add_interface, - .remove_interface = at76_remove_interface, - .config = at76_config, ---- a/drivers/net/wireless/broadcom/b43/main.c -+++ b/drivers/net/wireless/broadcom/b43/main.c -@@ -5171,6 +5171,7 @@ static int b43_op_get_survey(struct ieee - - static const struct ieee80211_ops b43_hw_ops = { - .tx = b43_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .conf_tx = b43_op_conf_tx, - .add_interface = b43_op_add_interface, - .remove_interface = b43_op_remove_interface, ---- a/drivers/net/wireless/broadcom/b43legacy/main.c -+++ b/drivers/net/wireless/broadcom/b43legacy/main.c -@@ -3532,6 +3532,7 @@ static int b43legacy_op_get_survey(struc - - static const struct ieee80211_ops b43legacy_hw_ops = { - .tx = b43legacy_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .conf_tx = b43legacy_op_conf_tx, - .add_interface = b43legacy_op_add_interface, - .remove_interface = b43legacy_op_remove_interface, ---- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c -@@ -962,6 +962,7 @@ static int brcms_ops_beacon_set_tim(stru - - static const struct ieee80211_ops brcms_ops = { - .tx = brcms_ops_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = brcms_ops_start, - .stop = brcms_ops_stop, - .add_interface = brcms_ops_add_interface, ---- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c -+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c -@@ -3435,6 +3435,7 @@ static const struct attribute_group il39 - - static struct ieee80211_ops il3945_mac_ops __ro_after_init = { - .tx = il3945_mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = il3945_mac_start, - .stop = il3945_mac_stop, - .add_interface = il_mac_add_interface, ---- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c -+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c -@@ -6304,6 +6304,7 @@ il4965_tx_queue_set_status(struct il_pri - - static const struct ieee80211_ops il4965_mac_ops = { - .tx = il4965_mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = il4965_mac_start, - .stop = il4965_mac_stop, - .add_interface = il_mac_add_interface, ---- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c -+++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c -@@ -1571,6 +1571,7 @@ static void iwlagn_mac_sta_notify(struct - - const struct ieee80211_ops iwlagn_hw_ops = { - .tx = iwlagn_mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = iwlagn_mac_start, - .stop = iwlagn_mac_stop, - #ifdef CONFIG_PM_SLEEP ---- a/drivers/net/wireless/intersil/p54/main.c -+++ b/drivers/net/wireless/intersil/p54/main.c -@@ -705,6 +705,7 @@ static void p54_set_coverage_class(struc - - static const struct ieee80211_ops p54_ops = { - .tx = p54_tx_80211, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = p54_start, - .stop = p54_stop, - .add_interface = p54_add_interface, ---- a/drivers/net/wireless/mac80211_hwsim.c -+++ b/drivers/net/wireless/mac80211_hwsim.c -@@ -3109,6 +3109,7 @@ static int mac80211_hwsim_change_sta_lin - - #define HWSIM_COMMON_OPS \ - .tx = mac80211_hwsim_tx, \ -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, \ - .start = mac80211_hwsim_start, \ - .stop = mac80211_hwsim_stop, \ - .add_interface = mac80211_hwsim_add_interface, \ ---- a/drivers/net/wireless/marvell/libertas_tf/main.c -+++ b/drivers/net/wireless/marvell/libertas_tf/main.c -@@ -474,6 +474,7 @@ static int lbtf_op_get_survey(struct iee - - static const struct ieee80211_ops lbtf_ops = { - .tx = lbtf_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = lbtf_op_start, - .stop = lbtf_op_stop, - .add_interface = lbtf_op_add_interface, ---- a/drivers/net/wireless/marvell/mwl8k.c -+++ b/drivers/net/wireless/marvell/mwl8k.c -@@ -5611,6 +5611,7 @@ static void mwl8k_sw_scan_complete(struc - - static const struct ieee80211_ops mwl8k_ops = { - .tx = mwl8k_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = mwl8k_start, - .stop = mwl8k_stop, - .add_interface = mwl8k_add_interface, ---- a/drivers/net/wireless/mediatek/mt7601u/main.c -+++ b/drivers/net/wireless/mediatek/mt7601u/main.c -@@ -406,6 +406,7 @@ out: - - const struct ieee80211_ops mt7601u_ops = { - .tx = mt7601u_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = mt7601u_start, - .stop = mt7601u_stop, - .add_interface = mt7601u_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c -@@ -1706,6 +1706,7 @@ static int rt2400pci_tx_last_beacon(stru - - static const struct ieee80211_ops rt2400pci_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c -@@ -2004,6 +2004,7 @@ static int rt2500pci_tx_last_beacon(stru - - static const struct ieee80211_ops rt2500pci_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c -@@ -1795,6 +1795,7 @@ static int rt2500usb_probe_hw(struct rt2 - - static const struct ieee80211_ops rt2500usb_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c -@@ -288,6 +288,7 @@ static int rt2800pci_read_eeprom(struct - - static const struct ieee80211_ops rt2800pci_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c -@@ -133,6 +133,7 @@ static int rt2800soc_write_firmware(stru - - static const struct ieee80211_ops rt2800soc_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c -@@ -630,6 +630,7 @@ static int rt2800usb_probe_hw(struct rt2 - - static const struct ieee80211_ops rt2800usb_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c -@@ -2873,6 +2873,7 @@ static u64 rt61pci_get_tsf(struct ieee80 - - static const struct ieee80211_ops rt61pci_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c -+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c -@@ -2292,6 +2292,7 @@ static u64 rt73usb_get_tsf(struct ieee80 - - static const struct ieee80211_ops rt73usb_mac80211_ops = { - .tx = rt2x00mac_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, ---- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c -+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c -@@ -1608,6 +1608,7 @@ static void rtl8180_configure_filter(str - - static const struct ieee80211_ops rtl8180_ops = { - .tx = rtl8180_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rtl8180_start, - .stop = rtl8180_stop, - .add_interface = rtl8180_add_interface, ---- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c -+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c -@@ -1378,6 +1378,7 @@ static int rtl8187_conf_tx(struct ieee80 - - static const struct ieee80211_ops rtl8187_ops = { - .tx = rtl8187_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rtl8187_start, - .stop = rtl8187_stop, - .add_interface = rtl8187_add_interface, ---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c -+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c -@@ -6561,6 +6561,7 @@ static void rtl8xxxu_stop(struct ieee802 - - static const struct ieee80211_ops rtl8xxxu_ops = { - .tx = rtl8xxxu_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .add_interface = rtl8xxxu_add_interface, - .remove_interface = rtl8xxxu_remove_interface, - .config = rtl8xxxu_config, ---- a/drivers/net/wireless/realtek/rtlwifi/core.c -+++ b/drivers/net/wireless/realtek/rtlwifi/core.c -@@ -1912,6 +1912,7 @@ const struct ieee80211_ops rtl_ops = { - .start = rtl_op_start, - .stop = rtl_op_stop, - .tx = rtl_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .add_interface = rtl_op_add_interface, - .remove_interface = rtl_op_remove_interface, - .change_interface = rtl_op_change_interface, ---- a/drivers/net/wireless/realtek/rtw88/mac80211.c -+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c -@@ -896,6 +896,7 @@ static void rtw_ops_sta_rc_update(struct - - const struct ieee80211_ops rtw_ops = { - .tx = rtw_ops_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .wake_tx_queue = rtw_ops_wake_tx_queue, - .start = rtw_ops_start, - .stop = rtw_ops_stop, ---- a/drivers/net/wireless/realtek/rtw89/mac80211.c -+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c -@@ -918,6 +918,7 @@ static int rtw89_ops_set_tid_config(stru - - const struct ieee80211_ops rtw89_ops = { - .tx = rtw89_ops_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .wake_tx_queue = rtw89_ops_wake_tx_queue, - .start = rtw89_ops_start, - .stop = rtw89_ops_stop, ---- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c -+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c -@@ -1958,6 +1958,7 @@ static int rsi_mac80211_resume(struct ie - - static const struct ieee80211_ops mac80211_ops = { - .tx = rsi_mac80211_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = rsi_mac80211_start, - .stop = rsi_mac80211_stop, - .add_interface = rsi_mac80211_add_interface, ---- a/drivers/net/wireless/st/cw1200/main.c -+++ b/drivers/net/wireless/st/cw1200/main.c -@@ -209,6 +209,7 @@ static const struct ieee80211_ops cw1200 - .remove_interface = cw1200_remove_interface, - .change_interface = cw1200_change_interface, - .tx = cw1200_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .hw_scan = cw1200_hw_scan, - .set_tim = cw1200_set_tim, - .sta_notify = cw1200_sta_notify, ---- a/drivers/net/wireless/ti/wl1251/main.c -+++ b/drivers/net/wireless/ti/wl1251/main.c -@@ -1359,6 +1359,7 @@ static const struct ieee80211_ops wl1251 - .prepare_multicast = wl1251_op_prepare_multicast, - .configure_filter = wl1251_op_configure_filter, - .tx = wl1251_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .set_key = wl1251_op_set_key, - .hw_scan = wl1251_op_hw_scan, - .bss_info_changed = wl1251_op_bss_info_changed, ---- a/drivers/net/wireless/ti/wlcore/main.c -+++ b/drivers/net/wireless/ti/wlcore/main.c -@@ -5942,6 +5942,7 @@ static const struct ieee80211_ops wl1271 - .prepare_multicast = wl1271_op_prepare_multicast, - .configure_filter = wl1271_op_configure_filter, - .tx = wl1271_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .set_key = wlcore_op_set_key, - .hw_scan = wl1271_op_hw_scan, - .cancel_hw_scan = wl1271_op_cancel_hw_scan, ---- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c -+++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c -@@ -1344,6 +1344,7 @@ static u64 zd_op_get_tsf(struct ieee8021 - - static const struct ieee80211_ops zd_ops = { - .tx = zd_op_tx, -+ .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = zd_op_start, - .stop = zd_op_stop, - .add_interface = zd_op_add_interface, diff --git a/package/kernel/mac80211/patches/subsys/306-03-wifi-mac80211-Drop-support-for-TX-push-path.patch b/package/kernel/mac80211/patches/subsys/306-03-wifi-mac80211-Drop-support-for-TX-push-path.patch deleted file mode 100644 index 9d5834555..000000000 --- a/package/kernel/mac80211/patches/subsys/306-03-wifi-mac80211-Drop-support-for-TX-push-path.patch +++ /dev/null @@ -1,655 +0,0 @@ -From: Alexander Wetzel -Date: Sun, 9 Oct 2022 18:30:40 +0200 -Subject: [PATCH] wifi: mac80211: Drop support for TX push path - -All drivers are now using mac80211 internal queues (iTXQs). -Drop mac80211 internal support for the old push path. - -Signed-off-by: Alexander Wetzel -Signed-off-by: Johannes Berg ---- - ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -4339,9 +4339,6 @@ static int ieee80211_get_txq_stats(struc - struct ieee80211_sub_if_data *sdata; - int ret = 0; - -- if (!local->ops->wake_tx_queue) -- return 1; -- - spin_lock_bh(&local->fq.lock); - rcu_read_lock(); - ---- a/net/mac80211/debugfs.c -+++ b/net/mac80211/debugfs.c -@@ -663,9 +663,7 @@ void debugfs_hw_add(struct ieee80211_loc - DEBUGFS_ADD_MODE(force_tx_status, 0600); - DEBUGFS_ADD_MODE(aql_enable, 0600); - DEBUGFS_ADD(aql_pending); -- -- if (local->ops->wake_tx_queue) -- DEBUGFS_ADD_MODE(aqm, 0600); -+ DEBUGFS_ADD_MODE(aqm, 0600); - - DEBUGFS_ADD_MODE(airtime_flags, 0600); - ---- a/net/mac80211/debugfs_netdev.c -+++ b/net/mac80211/debugfs_netdev.c -@@ -677,8 +677,7 @@ static void add_common_files(struct ieee - DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz); - DEBUGFS_ADD(hw_queues); - -- if (sdata->local->ops->wake_tx_queue && -- sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && -+ if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && - sdata->vif.type != NL80211_IFTYPE_NAN) - DEBUGFS_ADD(aqm); - } ---- a/net/mac80211/debugfs_sta.c -+++ b/net/mac80211/debugfs_sta.c -@@ -1056,10 +1056,8 @@ void ieee80211_sta_debugfs_add(struct st - DEBUGFS_ADD_COUNTER(rx_fragments, deflink.rx_stats.fragments); - DEBUGFS_ADD_COUNTER(tx_filtered, deflink.status_stats.filtered); - -- if (local->ops->wake_tx_queue) { -- DEBUGFS_ADD(aqm); -- DEBUGFS_ADD(airtime); -- } -+ DEBUGFS_ADD(aqm); -+ DEBUGFS_ADD(airtime); - - if (wiphy_ext_feature_isset(local->hw.wiphy, - NL80211_EXT_FEATURE_AQL)) ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -2290,7 +2290,6 @@ void ieee80211_wake_queue_by_reason(stru - void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason, - bool refcounted); --void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); - void ieee80211_add_pending_skb(struct ieee80211_local *local, - struct sk_buff *skb); - void ieee80211_add_pending_skbs(struct ieee80211_local *local, ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -458,12 +458,6 @@ static void ieee80211_do_stop(struct iee - if (cancel_scan) - ieee80211_scan_cancel(local); - -- /* -- * Stop TX on this interface first. -- */ -- if (!local->ops->wake_tx_queue && sdata->dev) -- netif_tx_stop_all_queues(sdata->dev); -- - ieee80211_roc_purge(local, sdata); - - switch (sdata->vif.type) { -@@ -811,13 +805,6 @@ static void ieee80211_uninit(struct net_ - ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); - } - --static u16 ieee80211_netdev_select_queue(struct net_device *dev, -- struct sk_buff *skb, -- struct net_device *sb_dev) --{ -- return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); --} -- - static void - ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) - { -@@ -831,7 +818,6 @@ static const struct net_device_ops ieee8 - .ndo_start_xmit = ieee80211_subif_start_xmit, - .ndo_set_rx_mode = ieee80211_set_multicast_list, - .ndo_set_mac_address = ieee80211_change_mac, -- .ndo_select_queue = ieee80211_netdev_select_queue, - .ndo_get_stats64 = ieee80211_get_stats64, - }; - -@@ -939,7 +925,6 @@ static const struct net_device_ops ieee8 - .ndo_start_xmit = ieee80211_subif_start_xmit_8023, - .ndo_set_rx_mode = ieee80211_set_multicast_list, - .ndo_set_mac_address = ieee80211_change_mac, -- .ndo_select_queue = ieee80211_netdev_select_queue, - .ndo_get_stats64 = ieee80211_get_stats64, - .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path, - }; -@@ -1441,35 +1426,6 @@ int ieee80211_do_open(struct wireless_de - - ieee80211_recalc_ps(local); - -- if (sdata->vif.type == NL80211_IFTYPE_MONITOR || -- sdata->vif.type == NL80211_IFTYPE_AP_VLAN || -- local->ops->wake_tx_queue) { -- /* XXX: for AP_VLAN, actually track AP queues */ -- if (dev) -- netif_tx_start_all_queues(dev); -- } else if (dev) { -- unsigned long flags; -- int n_acs = IEEE80211_NUM_ACS; -- int ac; -- -- if (local->hw.queues < IEEE80211_NUM_ACS) -- n_acs = 1; -- -- spin_lock_irqsave(&local->queue_stop_reason_lock, flags); -- if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE || -- (local->queue_stop_reasons[sdata->vif.cab_queue] == 0 && -- skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) { -- for (ac = 0; ac < n_acs; ac++) { -- int ac_queue = sdata->vif.hw_queue[ac]; -- -- if (local->queue_stop_reasons[ac_queue] == 0 && -- skb_queue_empty(&local->pending[ac_queue])) -- netif_start_subqueue(dev, ac); -- } -- } -- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); -- } -- - set_bit(SDATA_STATE_RUNNING, &sdata->state); - - return 0; -@@ -1499,17 +1455,12 @@ static void ieee80211_if_setup(struct ne - { - ether_setup(dev); - dev->priv_flags &= ~IFF_TX_SKB_SHARING; -+ dev->priv_flags |= IFF_NO_QUEUE; - dev->netdev_ops = &ieee80211_dataif_ops; - dev->needs_free_netdev = true; - dev->priv_destructor = ieee80211_if_free; - } - --static void ieee80211_if_setup_no_queue(struct net_device *dev) --{ -- ieee80211_if_setup(dev); -- dev->priv_flags |= IFF_NO_QUEUE; --} -- - static void ieee80211_iface_process_skb(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) -@@ -2094,9 +2045,7 @@ int ieee80211_if_add(struct ieee80211_lo - struct net_device *ndev = NULL; - struct ieee80211_sub_if_data *sdata = NULL; - struct txq_info *txqi; -- void (*if_setup)(struct net_device *dev); - int ret, i; -- int txqs = 1; - - ASSERT_RTNL(); - -@@ -2119,30 +2068,18 @@ int ieee80211_if_add(struct ieee80211_lo - sizeof(void *)); - int txq_size = 0; - -- if (local->ops->wake_tx_queue && -- type != NL80211_IFTYPE_AP_VLAN && -+ if (type != NL80211_IFTYPE_AP_VLAN && - (type != NL80211_IFTYPE_MONITOR || - (params->flags & MONITOR_FLAG_ACTIVE))) - txq_size += sizeof(struct txq_info) + - local->hw.txq_data_size; - -- if (local->ops->wake_tx_queue) { -- if_setup = ieee80211_if_setup_no_queue; -- } else { -- if_setup = ieee80211_if_setup; -- if (local->hw.queues >= IEEE80211_NUM_ACS) -- txqs = IEEE80211_NUM_ACS; -- } -- - ndev = alloc_netdev_mqs(size + txq_size, - name, name_assign_type, -- if_setup, txqs, 1); -+ ieee80211_if_setup, 1, 1); - if (!ndev) - return -ENOMEM; - -- if (!local->ops->wake_tx_queue && local->hw.wiphy->tx_queue_len) -- ndev->tx_queue_len = local->hw.wiphy->tx_queue_len; -- - dev_net_set(ndev, wiphy_net(local->hw.wiphy)); - - ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -630,7 +630,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - - if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || - !ops->add_interface || !ops->remove_interface || -- !ops->configure_filter)) -+ !ops->configure_filter || !ops->wake_tx_queue)) - return NULL; - - if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) -@@ -719,9 +719,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - if (!ops->set_key) - wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - -- if (ops->wake_tx_queue) -- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS); -- -+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS); - wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM); - - wiphy->bss_priv_size = sizeof(struct ieee80211_bss); -@@ -834,10 +832,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - atomic_set(&local->agg_queue_stop[i], 0); - } - tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending); -- -- if (ops->wake_tx_queue) -- tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs); -- -+ tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs); - tasklet_setup(&local->tasklet, ieee80211_tasklet_handler); - - skb_queue_head_init(&local->skb_queue); ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -1571,9 +1571,6 @@ static void sta_ps_start(struct sta_info - - ieee80211_clear_fast_xmit(sta); - -- if (!sta->sta.txq[0]) -- return; -- - for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { - struct ieee80211_txq *txq = sta->sta.txq[tid]; - struct txq_info *txqi = to_txq_info(txq); ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -140,17 +140,15 @@ static void __cleanup_single_sta(struct - atomic_dec(&ps->num_sta_ps); - } - -- if (sta->sta.txq[0]) { -- for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { -- struct txq_info *txqi; -+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { -+ struct txq_info *txqi; - -- if (!sta->sta.txq[i]) -- continue; -+ if (!sta->sta.txq[i]) -+ continue; - -- txqi = to_txq_info(sta->sta.txq[i]); -+ txqi = to_txq_info(sta->sta.txq[i]); - -- ieee80211_txq_purge(local, txqi); -- } -+ ieee80211_txq_purge(local, txqi); - } - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -@@ -425,8 +423,7 @@ void sta_info_free(struct ieee80211_loca - - sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); - -- if (sta->sta.txq[0]) -- kfree(to_txq_info(sta->sta.txq[0])); -+ kfree(to_txq_info(sta->sta.txq[0])); - kfree(rcu_dereference_raw(sta->sta.rates)); - #ifdef CPTCFG_MAC80211_MESH - kfree(sta->mesh); -@@ -527,6 +524,8 @@ __sta_info_alloc(struct ieee80211_sub_if - struct ieee80211_local *local = sdata->local; - struct ieee80211_hw *hw = &local->hw; - struct sta_info *sta; -+ void *txq_data; -+ int size; - int i; - - sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); -@@ -597,21 +596,18 @@ __sta_info_alloc(struct ieee80211_sub_if - - sta->last_connected = ktime_get_seconds(); - -- if (local->ops->wake_tx_queue) { -- void *txq_data; -- int size = sizeof(struct txq_info) + -- ALIGN(hw->txq_data_size, sizeof(void *)); -+ size = sizeof(struct txq_info) + -+ ALIGN(hw->txq_data_size, sizeof(void *)); - -- txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp); -- if (!txq_data) -- goto free; -+ txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp); -+ if (!txq_data) -+ goto free; - -- for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { -- struct txq_info *txq = txq_data + i * size; -+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { -+ struct txq_info *txq = txq_data + i * size; - -- /* might not do anything for the bufferable MMPDU TXQ */ -- ieee80211_txq_init(sdata, sta, txq, i); -- } -+ /* might not do anything for the (bufferable) MMPDU TXQ */ -+ ieee80211_txq_init(sdata, sta, txq, i); - } - - if (sta_prepare_rate_control(local, sta, gfp)) -@@ -685,8 +681,7 @@ __sta_info_alloc(struct ieee80211_sub_if - return sta; - - free_txq: -- if (sta->sta.txq[0]) -- kfree(to_txq_info(sta->sta.txq[0])); -+ kfree(to_txq_info(sta->sta.txq[0])); - free: - sta_info_free_link(&sta->deflink); - #ifdef CPTCFG_MAC80211_MESH -@@ -1959,9 +1954,6 @@ ieee80211_sta_ps_deliver_response(struct - * TIM recalculation. - */ - -- if (!sta->sta.txq[0]) -- return; -- - for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { - if (!sta->sta.txq[tid] || - !(driver_release_tids & BIT(tid)) || -@@ -2446,7 +2438,7 @@ static void sta_set_tidstats(struct sta_ - tidstats->tx_msdu_failed = sta->deflink.status_stats.msdu_failed[tid]; - } - -- if (local->ops->wake_tx_queue && tid < IEEE80211_NUM_TIDS) { -+ if (tid < IEEE80211_NUM_TIDS) { - spin_lock_bh(&local->fq.lock); - rcu_read_lock(); - -@@ -2774,9 +2766,6 @@ unsigned long ieee80211_sta_last_active( - - static void sta_update_codel_params(struct sta_info *sta, u32 thr) - { -- if (!sta->sdata->local->ops->wake_tx_queue) -- return; -- - if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) { - sta->cparams.target = MS2TIME(50); - sta->cparams.interval = MS2TIME(300); ---- a/net/mac80211/tdls.c -+++ b/net/mac80211/tdls.c -@@ -1016,7 +1016,6 @@ ieee80211_tdls_prep_mgmt_packet(struct w - skb->priority = 256 + 5; - break; - } -- skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb)); - - /* - * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress. ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1599,9 +1599,6 @@ int ieee80211_txq_setup_flows(struct iee - bool supp_vht = false; - enum nl80211_band band; - -- if (!local->ops->wake_tx_queue) -- return 0; -- - ret = fq_init(fq, 4096); - if (ret) - return ret; -@@ -1649,9 +1646,6 @@ void ieee80211_txq_teardown_flows(struct - { - struct fq *fq = &local->fq; - -- if (!local->ops->wake_tx_queue) -- return; -- - kfree(local->cvars); - local->cvars = NULL; - -@@ -1668,8 +1662,7 @@ static bool ieee80211_queue_skb(struct i - struct ieee80211_vif *vif; - struct txq_info *txqi; - -- if (!local->ops->wake_tx_queue || -- sdata->vif.type == NL80211_IFTYPE_MONITOR) -+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR) - return false; - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -@@ -4185,12 +4178,7 @@ void __ieee80211_subif_start_xmit(struct - if (IS_ERR(sta)) - sta = NULL; - -- if (local->ops->wake_tx_queue) { -- u16 queue = __ieee80211_select_queue(sdata, sta, skb); -- skb_set_queue_mapping(skb, queue); -- skb_get_hash(skb); -- } -- -+ skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb)); - ieee80211_aggr_check(sdata, sta, skb); - - sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift); -@@ -4501,11 +4489,7 @@ static void ieee80211_8023_xmit(struct i - struct tid_ampdu_tx *tid_tx; - u8 tid; - -- if (local->ops->wake_tx_queue) { -- u16 queue = __ieee80211_select_queue(sdata, sta, skb); -- skb_set_queue_mapping(skb, queue); -- skb_get_hash(skb); -- } -+ skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb)); - - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) && - test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) -@@ -4759,9 +4743,6 @@ void ieee80211_tx_pending(struct tasklet - if (!txok) - break; - } -- -- if (skb_queue_empty(&local->pending[i])) -- ieee80211_propagate_queue_wake(local, i); - } - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - -@@ -5954,10 +5935,9 @@ int ieee80211_tx_control_port(struct wip - } - - if (!IS_ERR(sta)) { -- u16 queue = __ieee80211_select_queue(sdata, sta, skb); -+ u16 queue = ieee80211_select_queue(sdata, sta, skb); - - skb_set_queue_mapping(skb, queue); -- skb_get_hash(skb); - - /* - * for MLO STA, the SA should be the AP MLD address, but ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -446,39 +446,6 @@ void ieee80211_wake_txqs(struct tasklet_ - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - } - --void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) --{ -- struct ieee80211_sub_if_data *sdata; -- int n_acs = IEEE80211_NUM_ACS; -- -- if (local->ops->wake_tx_queue) -- return; -- -- if (local->hw.queues < IEEE80211_NUM_ACS) -- n_acs = 1; -- -- list_for_each_entry_rcu(sdata, &local->interfaces, list) { -- int ac; -- -- if (!sdata->dev) -- continue; -- -- if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE && -- local->queue_stop_reasons[sdata->vif.cab_queue] != 0) -- continue; -- -- for (ac = 0; ac < n_acs; ac++) { -- int ac_queue = sdata->vif.hw_queue[ac]; -- -- if (ac_queue == queue || -- (sdata->vif.cab_queue == queue && -- local->queue_stop_reasons[ac_queue] == 0 && -- skb_queue_empty(&local->pending[ac_queue]))) -- netif_wake_subqueue(sdata->dev, ac); -- } -- } --} -- - static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason, - bool refcounted, -@@ -509,11 +476,7 @@ static void __ieee80211_wake_queue(struc - /* someone still has this queue stopped */ - return; - -- if (skb_queue_empty(&local->pending[queue])) { -- rcu_read_lock(); -- ieee80211_propagate_queue_wake(local, queue); -- rcu_read_unlock(); -- } else -+ if (!skb_queue_empty(&local->pending[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - - /* -@@ -523,12 +486,10 @@ static void __ieee80211_wake_queue(struc - * release someone's lock, but it is fine because all the callers of - * __ieee80211_wake_queue call it right before releasing the lock. - */ -- if (local->ops->wake_tx_queue) { -- if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER) -- tasklet_schedule(&local->wake_txqs_tasklet); -- else -- _ieee80211_wake_txqs(local, flags); -- } -+ if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER) -+ tasklet_schedule(&local->wake_txqs_tasklet); -+ else -+ _ieee80211_wake_txqs(local, flags); - } - - void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, -@@ -585,10 +546,6 @@ static void __ieee80211_stop_queue(struc - for (ac = 0; ac < n_acs; ac++) { - if (sdata->vif.hw_queue[ac] == queue || - sdata->vif.cab_queue == queue) { -- if (!local->ops->wake_tx_queue) { -- netif_stop_subqueue(sdata->dev, ac); -- continue; -- } - spin_lock(&local->fq.lock); - sdata->vif.txqs_stopped[ac] = true; - spin_unlock(&local->fq.lock); ---- a/net/mac80211/wme.c -+++ b/net/mac80211/wme.c -@@ -122,6 +122,9 @@ u16 ieee80211_select_queue_80211(struct - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u8 *p; - -+ /* Ensure hash is set prior to potential SW encryption */ -+ skb_get_hash(skb); -+ - if ((info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) || - local->hw.queues < IEEE80211_NUM_ACS) - return 0; -@@ -141,12 +144,15 @@ u16 ieee80211_select_queue_80211(struct - return ieee80211_downgrade_queue(sdata, NULL, skb); - } - --u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -- struct sta_info *sta, struct sk_buff *skb) -+u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -+ struct sta_info *sta, struct sk_buff *skb) - { - struct mac80211_qos_map *qos_map; - bool qos; - -+ /* Ensure hash is set prior to potential SW encryption */ -+ skb_get_hash(skb); -+ - /* all mesh/ocb stations are required to support WME */ - if (sta && (sdata->vif.type == NL80211_IFTYPE_MESH_POINT || - sdata->vif.type == NL80211_IFTYPE_OCB)) -@@ -176,59 +182,6 @@ u16 __ieee80211_select_queue(struct ieee - return ieee80211_downgrade_queue(sdata, sta, skb); - } - -- --/* Indicate which queue to use. */ --u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -- struct sk_buff *skb) --{ -- struct ieee80211_local *local = sdata->local; -- struct sta_info *sta = NULL; -- const u8 *ra = NULL; -- u16 ret; -- -- /* when using iTXQ, we can do this later */ -- if (local->ops->wake_tx_queue) -- return 0; -- -- if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { -- skb->priority = 0; /* required for correct WPA/11i MIC */ -- return 0; -- } -- -- rcu_read_lock(); -- switch (sdata->vif.type) { -- case NL80211_IFTYPE_AP_VLAN: -- sta = rcu_dereference(sdata->u.vlan.sta); -- if (sta) -- break; -- fallthrough; -- case NL80211_IFTYPE_AP: -- ra = skb->data; -- break; -- case NL80211_IFTYPE_STATION: -- /* might be a TDLS station */ -- sta = sta_info_get(sdata, skb->data); -- if (sta) -- break; -- -- ra = sdata->deflink.u.mgd.bssid; -- break; -- case NL80211_IFTYPE_ADHOC: -- ra = skb->data; -- break; -- default: -- break; -- } -- -- if (!sta && ra && !is_multicast_ether_addr(ra)) -- sta = sta_info_get(sdata, ra); -- -- ret = __ieee80211_select_queue(sdata, sta, skb); -- -- rcu_read_unlock(); -- return ret; --} -- - /** - * ieee80211_set_qos_hdr - Fill in the QoS header if there is one. - * ---- a/net/mac80211/wme.h -+++ b/net/mac80211/wme.h -@@ -13,10 +13,8 @@ - u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_hdr *hdr); --u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -- struct sta_info *sta, struct sk_buff *skb); - u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -- struct sk_buff *skb); -+ struct sta_info *sta, struct sk_buff *skb); - void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb); - diff --git a/package/kernel/mac80211/patches/subsys/306-04-wifi-realtek-remove-duplicated-wake_tx_queue.patch b/package/kernel/mac80211/patches/subsys/306-04-wifi-realtek-remove-duplicated-wake_tx_queue.patch deleted file mode 100644 index f0dfc75a7..000000000 --- a/package/kernel/mac80211/patches/subsys/306-04-wifi-realtek-remove-duplicated-wake_tx_queue.patch +++ /dev/null @@ -1,32 +0,0 @@ -From: Johannes Berg -Date: Mon, 10 Oct 2022 19:17:46 +0200 -Subject: [PATCH] wifi: realtek: remove duplicated wake_tx_queue - -By accident, the previous patch duplicated the initialization -of the wake_tx_queue callback. Fix that by removing the new -initializations. - -Fixes: a790cc3a4fad ("wifi: mac80211: add wake_tx_queue callback to drivers") -Signed-off-by: Johannes Berg ---- - ---- a/drivers/net/wireless/realtek/rtw88/mac80211.c -+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c -@@ -896,7 +896,6 @@ static void rtw_ops_sta_rc_update(struct - - const struct ieee80211_ops rtw_ops = { - .tx = rtw_ops_tx, -- .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .wake_tx_queue = rtw_ops_wake_tx_queue, - .start = rtw_ops_start, - .stop = rtw_ops_stop, ---- a/drivers/net/wireless/realtek/rtw89/mac80211.c -+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c -@@ -918,7 +918,6 @@ static int rtw89_ops_set_tid_config(stru - - const struct ieee80211_ops rtw89_ops = { - .tx = rtw89_ops_tx, -- .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .wake_tx_queue = rtw89_ops_wake_tx_queue, - .start = rtw89_ops_start, - .stop = rtw89_ops_stop, diff --git a/package/kernel/mac80211/patches/subsys/306-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch b/package/kernel/mac80211/patches/subsys/306-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch new file mode 100644 index 000000000..c43cd3acb --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/306-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch @@ -0,0 +1,60 @@ +From: Felix Fietkau +Date: Tue, 14 Dec 2021 17:53:12 +0100 +Subject: [PATCH] mac80211: use coarse boottime for airtime fairness code + +The time values used by the airtime fairness code only need to be accurate +enough to cover station activity detection. +Using ktime_get_coarse_boottime_ns instead of ktime_get_boottime_ns will +drop the accuracy down to jiffies intervals, but at the same time saves +a lot of CPU cycles in a hot path + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3820,7 +3820,7 @@ struct ieee80211_txq *ieee80211_next_txq + { + struct ieee80211_local *local = hw_to_local(hw); + struct airtime_sched_info *air_sched; +- u64 now = ktime_get_boottime_ns(); ++ u64 now = ktime_get_coarse_boottime_ns(); + struct ieee80211_txq *ret = NULL; + struct airtime_info *air_info; + struct txq_info *txqi = NULL; +@@ -3947,7 +3947,7 @@ void ieee80211_update_airtime_weight(str + u64 weight_sum = 0; + + if (unlikely(!now)) +- now = ktime_get_boottime_ns(); ++ now = ktime_get_coarse_boottime_ns(); + + lockdep_assert_held(&air_sched->lock); + +@@ -3973,7 +3973,7 @@ void ieee80211_schedule_txq(struct ieee8 + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); + struct airtime_sched_info *air_sched; +- u64 now = ktime_get_boottime_ns(); ++ u64 now = ktime_get_coarse_boottime_ns(); + struct airtime_info *air_info; + u8 ac = txq->ac; + bool was_active; +@@ -4031,7 +4031,7 @@ static void __ieee80211_unschedule_txq(s + + if (!purge) + airtime_set_active(air_sched, air_info, +- ktime_get_boottime_ns()); ++ ktime_get_coarse_boottime_ns()); + + rb_erase_cached(&txqi->schedule_order, + &air_sched->active_txqs); +@@ -4119,7 +4119,7 @@ bool ieee80211_txq_may_transmit(struct i + if (RB_EMPTY_NODE(&txqi->schedule_order)) + goto out; + +- now = ktime_get_boottime_ns(); ++ now = ktime_get_coarse_boottime_ns(); + + /* Like in ieee80211_next_txq(), make sure the first station in the + * scheduling order is eligible for transmission to avoid starvation. diff --git a/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch b/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch new file mode 100644 index 000000000..c534d1570 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch @@ -0,0 +1,74 @@ +From: Felix Fietkau +Date: Mon, 24 May 2021 11:46:09 +0200 +Subject: [PATCH] mac80211_hwsim: make 6 GHz channels usable + +The previous commit that claimed to add 6 GHz channels didn't actually make +them usable, since the 6 GHz band was not registered with mac80211. + +Fixes: 28881922abd7 ("mac80211_hwsim: add 6GHz channels") +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -3001,15 +3001,19 @@ static void mac80211_hwsim_he_capab(stru + { + u16 n_iftype_data; + +- if (sband->band == NL80211_BAND_2GHZ) { ++ switch (sband->band) { ++ case NL80211_BAND_2GHZ: + n_iftype_data = ARRAY_SIZE(he_capa_2ghz); + sband->iftype_data = + (struct ieee80211_sband_iftype_data *)he_capa_2ghz; +- } else if (sband->band == NL80211_BAND_5GHZ) { ++ break; ++ case NL80211_BAND_5GHZ: ++ case NL80211_BAND_6GHZ: + n_iftype_data = ARRAY_SIZE(he_capa_5ghz); + sband->iftype_data = + (struct ieee80211_sband_iftype_data *)he_capa_5ghz; +- } else { ++ break; ++ default: + return; + } + +@@ -3299,6 +3303,12 @@ static int mac80211_hwsim_new_radio(stru + sband->vht_cap.vht_mcs.tx_mcs_map = + sband->vht_cap.vht_mcs.rx_mcs_map; + break; ++ case NL80211_BAND_6GHZ: ++ sband->channels = data->channels_6ghz; ++ sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz); ++ sband->bitrates = data->rates + 4; ++ sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; ++ break; + case NL80211_BAND_S1GHZ: + memcpy(&sband->s1g_cap, &hwsim_s1g_cap, + sizeof(sband->s1g_cap)); +@@ -3309,6 +3319,13 @@ static int mac80211_hwsim_new_radio(stru + continue; + } + ++ mac80211_hwsim_he_capab(sband); ++ ++ hw->wiphy->bands[band] = sband; ++ ++ if (band == NL80211_BAND_6GHZ) ++ continue; ++ + sband->ht_cap.ht_supported = true; + sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | +@@ -3322,10 +3339,6 @@ static int mac80211_hwsim_new_radio(stru + sband->ht_cap.mcs.rx_mask[0] = 0xff; + sband->ht_cap.mcs.rx_mask[1] = 0xff; + sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +- +- mac80211_hwsim_he_capab(sband); +- +- hw->wiphy->bands[band] = sband; + } + + /* By default all radios belong to the first group */ diff --git a/package/kernel/mac80211/patches/subsys/307-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch b/package/kernel/mac80211/patches/subsys/307-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch deleted file mode 100644 index 857c1c844..000000000 --- a/package/kernel/mac80211/patches/subsys/307-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch +++ /dev/null @@ -1,406 +0,0 @@ -From: Felix Fietkau -Date: Tue, 13 Dec 2022 21:03:19 +0100 -Subject: [PATCH] wifi: mac80211: fix initialization of rx->link and - rx->link_sta - -There are some codepaths that do not initialize rx->link_sta properly. This -causes a crash in places which assume that rx->link_sta is valid if rx->sta -is valid. -One known instance is triggered by __ieee80211_rx_h_amsdu being called from -fast-rx. - -Since the initialization of rx->link and rx->link_sta is rather convoluted -and duplicated in many places, clean it up by using a helper function to -set it. - -Fixes: ccdde7c74ffd ("wifi: mac80211: properly implement MLO key handling") -Fixes: b320d6c456ff ("wifi: mac80211: use correct rx link_sta instead of default") -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -4067,6 +4067,56 @@ static void ieee80211_invoke_rx_handlers - #undef CALL_RXH - } - -+static bool -+ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id) -+{ -+ if (!sta->mlo) -+ return false; -+ -+ return !!(sta->valid_links & BIT(link_id)); -+} -+ -+static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx, -+ u8 link_id) -+{ -+ if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id)) -+ return false; -+ -+ rx->link_id = link_id; -+ rx->link = rcu_dereference(rx->sdata->link[link_id]); -+ rx->link_sta = rcu_dereference(rx->sta->link[link_id]); -+ -+ return rx->link && rx->link_sta; -+} -+ -+static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx, -+ struct ieee80211_sta *pubsta, -+ int link_id) -+{ -+ struct sta_info *sta; -+ -+ sta = container_of(pubsta, struct sta_info, sta); -+ -+ rx->link_id = link_id; -+ rx->sta = sta; -+ -+ if (sta) { -+ rx->local = sta->sdata->local; -+ if (!rx->sdata) -+ rx->sdata = sta->sdata; -+ rx->link_sta = &sta->deflink; -+ -+ if (link_id >= 0 && -+ !ieee80211_rx_data_set_link(rx, link_id)) -+ return false; -+ } -+ -+ if (link_id < 0) -+ rx->link = &rx->sdata->deflink; -+ -+ return true; -+} -+ - /* - * This function makes calls into the RX path, therefore - * it has to be invoked under RCU read lock. -@@ -4075,16 +4125,19 @@ void ieee80211_release_reorder_timeout(s - { - struct sk_buff_head frames; - struct ieee80211_rx_data rx = { -- .sta = sta, -- .sdata = sta->sdata, -- .local = sta->local, - /* This is OK -- must be QoS data frame */ - .security_idx = tid, - .seqno_idx = tid, -- .link_id = -1, - }; - struct tid_ampdu_rx *tid_agg_rx; -- u8 link_id; -+ int link_id = -1; -+ -+ /* FIXME: statistics won't be right with this */ -+ if (sta->sta.valid_links) -+ link_id = ffs(sta->sta.valid_links) - 1; -+ -+ if (!ieee80211_rx_data_set_sta(&rx, &sta->sta, link_id)) -+ return; - - tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); - if (!tid_agg_rx) -@@ -4104,10 +4157,6 @@ void ieee80211_release_reorder_timeout(s - }; - drv_event_callback(rx.local, rx.sdata, &event); - } -- /* FIXME: statistics won't be right with this */ -- link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0; -- rx.link = rcu_dereference(sta->sdata->link[link_id]); -- rx.link_sta = rcu_dereference(sta->link[link_id]); - - ieee80211_rx_handlers(&rx, &frames); - } -@@ -4123,7 +4172,6 @@ void ieee80211_mark_rx_ba_filtered_frame - /* This is OK -- must be QoS data frame */ - .security_idx = tid, - .seqno_idx = tid, -- .link_id = -1, - }; - int i, diff; - -@@ -4134,10 +4182,8 @@ void ieee80211_mark_rx_ba_filtered_frame - - sta = container_of(pubsta, struct sta_info, sta); - -- rx.sta = sta; -- rx.sdata = sta->sdata; -- rx.link = &rx.sdata->deflink; -- rx.local = sta->local; -+ if (!ieee80211_rx_data_set_sta(&rx, pubsta, -1)) -+ return; - - rcu_read_lock(); - tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); -@@ -4524,15 +4570,6 @@ void ieee80211_check_fast_rx_iface(struc - mutex_unlock(&local->sta_mtx); - } - --static bool --ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id) --{ -- if (!sta->mlo) -- return false; -- -- return !!(sta->valid_links & BIT(link_id)); --} -- - static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, - struct ieee80211_fast_rx *fast_rx, - int orig_len) -@@ -4643,7 +4680,6 @@ static bool ieee80211_invoke_fast_rx(str - struct sk_buff *skb = rx->skb; - struct ieee80211_hdr *hdr = (void *)skb->data; - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); -- struct sta_info *sta = rx->sta; - int orig_len = skb->len; - int hdrlen = ieee80211_hdrlen(hdr->frame_control); - int snap_offs = hdrlen; -@@ -4655,7 +4691,6 @@ static bool ieee80211_invoke_fast_rx(str - u8 da[ETH_ALEN]; - u8 sa[ETH_ALEN]; - } addrs __aligned(2); -- struct link_sta_info *link_sta; - struct ieee80211_sta_rx_stats *stats; - - /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write -@@ -4758,18 +4793,10 @@ static bool ieee80211_invoke_fast_rx(str - drop: - dev_kfree_skb(skb); - -- if (rx->link_id >= 0) { -- link_sta = rcu_dereference(sta->link[rx->link_id]); -- if (!link_sta) -- return true; -- } else { -- link_sta = &sta->deflink; -- } -- - if (fast_rx->uses_rss) -- stats = this_cpu_ptr(link_sta->pcpu_rx_stats); -+ stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats); - else -- stats = &link_sta->rx_stats; -+ stats = &rx->link_sta->rx_stats; - - stats->dropped++; - return true; -@@ -4787,8 +4814,8 @@ static bool ieee80211_prepare_and_rx_han - struct ieee80211_local *local = rx->local; - struct ieee80211_sub_if_data *sdata = rx->sdata; - struct ieee80211_hdr *hdr = (void *)skb->data; -- struct link_sta_info *link_sta = NULL; -- struct ieee80211_link_data *link; -+ struct link_sta_info *link_sta = rx->link_sta; -+ struct ieee80211_link_data *link = rx->link; - - rx->skb = skb; - -@@ -4810,35 +4837,6 @@ static bool ieee80211_prepare_and_rx_han - if (!ieee80211_accept_frame(rx)) - return false; - -- if (rx->link_id >= 0) { -- link = rcu_dereference(rx->sdata->link[rx->link_id]); -- -- /* we might race link removal */ -- if (!link) -- return true; -- rx->link = link; -- -- if (rx->sta) { -- rx->link_sta = -- rcu_dereference(rx->sta->link[rx->link_id]); -- if (!rx->link_sta) -- return true; -- } -- } else { -- if (rx->sta) -- rx->link_sta = &rx->sta->deflink; -- -- rx->link = &sdata->deflink; -- } -- -- if (unlikely(!is_multicast_ether_addr(hdr->addr1) && -- rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) { -- link_sta = rcu_dereference(rx->sta->link[rx->link_id]); -- -- if (WARN_ON_ONCE(!link_sta)) -- return true; -- } -- - if (!consume) { - struct skb_shared_hwtstamps *shwt; - -@@ -4858,7 +4856,7 @@ static bool ieee80211_prepare_and_rx_han - shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp; - } - -- if (unlikely(link_sta)) { -+ if (unlikely(rx->sta && rx->sta->sta.mlo)) { - /* translate to MLD addresses */ - if (ether_addr_equal(link->conf->addr, hdr->addr1)) - ether_addr_copy(hdr->addr1, rx->sdata->vif.addr); -@@ -4888,6 +4886,7 @@ static void __ieee80211_rx_handle_8023(s - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_fast_rx *fast_rx; - struct ieee80211_rx_data rx; -+ int link_id = -1; - - memset(&rx, 0, sizeof(rx)); - rx.skb = skb; -@@ -4904,12 +4903,8 @@ static void __ieee80211_rx_handle_8023(s - if (!pubsta) - goto drop; - -- rx.sta = container_of(pubsta, struct sta_info, sta); -- rx.sdata = rx.sta->sdata; -- -- if (status->link_valid && -- !ieee80211_rx_is_valid_sta_link_id(pubsta, status->link_id)) -- goto drop; -+ if (status->link_valid) -+ link_id = status->link_id; - - /* - * TODO: Should the frame be dropped if the right link_id is not -@@ -4918,19 +4913,8 @@ static void __ieee80211_rx_handle_8023(s - * link_id is used only for stats purpose and updating the stats on - * the deflink is fine? - */ -- if (status->link_valid) -- rx.link_id = status->link_id; -- -- if (rx.link_id >= 0) { -- struct ieee80211_link_data *link; -- -- link = rcu_dereference(rx.sdata->link[rx.link_id]); -- if (!link) -- goto drop; -- rx.link = link; -- } else { -- rx.link = &rx.sdata->deflink; -- } -+ if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id)) -+ goto drop; - - fast_rx = rcu_dereference(rx.sta->fast_rx); - if (!fast_rx) -@@ -4948,6 +4932,8 @@ static bool ieee80211_rx_for_interface(s - { - struct link_sta_info *link_sta; - struct ieee80211_hdr *hdr = (void *)skb->data; -+ struct sta_info *sta; -+ int link_id = -1; - - /* - * Look up link station first, in case there's a -@@ -4957,24 +4943,19 @@ static bool ieee80211_rx_for_interface(s - */ - link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2); - if (link_sta) { -- rx->sta = link_sta->sta; -- rx->link_id = link_sta->link_id; -+ sta = link_sta->sta; -+ link_id = link_sta->link_id; - } else { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - -- rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2); -- if (rx->sta) { -- if (status->link_valid && -- !ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, -- status->link_id)) -- return false; -- -- rx->link_id = status->link_valid ? status->link_id : -1; -- } else { -- rx->link_id = -1; -- } -+ sta = sta_info_get_bss(rx->sdata, hdr->addr2); -+ if (status->link_valid) -+ link_id = status->link_id; - } - -+ if (!ieee80211_rx_data_set_sta(rx, &sta->sta, link_id)) -+ return false; -+ - return ieee80211_prepare_and_rx_handle(rx, skb, consume); - } - -@@ -5033,19 +5014,15 @@ static void __ieee80211_rx_handle_packet - - if (ieee80211_is_data(fc)) { - struct sta_info *sta, *prev_sta; -- u8 link_id = status->link_id; -+ int link_id = -1; - -- if (pubsta) { -- rx.sta = container_of(pubsta, struct sta_info, sta); -- rx.sdata = rx.sta->sdata; -+ if (status->link_valid) -+ link_id = status->link_id; - -- if (status->link_valid && -- !ieee80211_rx_is_valid_sta_link_id(pubsta, link_id)) -+ if (pubsta) { -+ if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id)) - goto out; - -- if (status->link_valid) -- rx.link_id = status->link_id; -- - /* - * In MLO connection, fetch the link_id using addr2 - * when the driver does not pass link_id in status. -@@ -5063,7 +5040,7 @@ static void __ieee80211_rx_handle_packet - if (!link_sta) - goto out; - -- rx.link_id = link_sta->link_id; -+ ieee80211_rx_data_set_link(&rx, link_sta->link_id); - } - - if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) -@@ -5079,30 +5056,25 @@ static void __ieee80211_rx_handle_packet - continue; - } - -- if ((status->link_valid && -- !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta, -- link_id)) || -- (!status->link_valid && prev_sta->sta.mlo)) -+ if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta, -+ link_id)) -+ goto out; -+ -+ if (!status->link_valid && prev_sta->sta.mlo) - continue; - -- rx.link_id = status->link_valid ? link_id : -1; -- rx.sta = prev_sta; -- rx.sdata = prev_sta->sdata; - ieee80211_prepare_and_rx_handle(&rx, skb, false); - - prev_sta = sta; - } - - if (prev_sta) { -- if ((status->link_valid && -- !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta, -- link_id)) || -- (!status->link_valid && prev_sta->sta.mlo)) -+ if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta, -+ link_id)) - goto out; - -- rx.link_id = status->link_valid ? link_id : -1; -- rx.sta = prev_sta; -- rx.sdata = prev_sta->sdata; -+ if (!status->link_valid && prev_sta->sta.mlo) -+ goto out; - - if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) - return; diff --git a/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch new file mode 100644 index 000000000..272d84f35 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch @@ -0,0 +1,178 @@ +From: Felix Fietkau +Date: Fri, 12 Nov 2021 12:22:23 +0100 +Subject: [PATCH] mac80211: add support for .ndo_fill_forward_path + +This allows drivers to provide a destination device + info for flow offload +Only supported in combination with 802.3 encap offload + +Signed-off-by: Felix Fietkau +Tested-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/20211112112223.1209-1-nbd@nbd.name +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3937,6 +3937,8 @@ struct ieee80211_prep_tx_info { + * twt structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. ++ * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to ++ * resolve a path for hardware flow offloading + */ + struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, +@@ -4265,6 +4267,13 @@ struct ieee80211_ops { + struct ieee80211_twt_setup *twt); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++ int (*net_fill_forward_path)(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct net_device_path_ctx *ctx, ++ struct net_device_path *path); ++#endif + }; + + /** +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1486,4 +1486,28 @@ static inline void drv_twt_teardown_requ + trace_drv_return_void(local); + } + ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++static inline int drv_net_fill_forward_path(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ struct net_device_path_ctx *ctx, ++ struct net_device_path *path) ++{ ++ int ret = -EOPNOTSUPP; ++ ++ sdata = get_bss_sdata(sdata); ++ if (!check_sdata_in_driver(sdata)) ++ return -EIO; ++ ++ trace_drv_net_fill_forward_path(local, sdata, sta); ++ if (local->ops->net_fill_forward_path) ++ ret = local->ops->net_fill_forward_path(&local->hw, ++ &sdata->vif, sta, ++ ctx, path); ++ trace_drv_return_int(local, ret); ++ ++ return ret; ++} ++#endif ++ + #endif /* __MAC80211_DRIVER_OPS */ +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1485,7 +1485,7 @@ struct ieee80211_local { + }; + + static inline struct ieee80211_sub_if_data * +-IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) ++IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev) + { + return netdev_priv(dev); + } +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -822,6 +822,66 @@ static const struct net_device_ops ieee8 + + }; + ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx, ++ struct net_device_path *path) ++{ ++ struct ieee80211_sub_if_data *sdata; ++ struct ieee80211_local *local; ++ struct sta_info *sta; ++ int ret = -ENOENT; ++ ++ sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev); ++ local = sdata->local; ++ ++ if (!local->ops->net_fill_forward_path) ++ return -EOPNOTSUPP; ++ ++ rcu_read_lock(); ++ switch (sdata->vif.type) { ++ case NL80211_IFTYPE_AP_VLAN: ++ sta = rcu_dereference(sdata->u.vlan.sta); ++ if (sta) ++ break; ++ if (sdata->wdev.use_4addr) ++ goto out; ++ if (is_multicast_ether_addr(ctx->daddr)) ++ goto out; ++ sta = sta_info_get_bss(sdata, ctx->daddr); ++ break; ++ case NL80211_IFTYPE_AP: ++ if (is_multicast_ether_addr(ctx->daddr)) ++ goto out; ++ sta = sta_info_get(sdata, ctx->daddr); ++ break; ++ case NL80211_IFTYPE_STATION: ++ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { ++ sta = sta_info_get(sdata, ctx->daddr); ++ if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { ++ if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) ++ goto out; ++ ++ break; ++ } ++ } ++ ++ sta = sta_info_get(sdata, sdata->u.mgd.bssid); ++ break; ++ default: ++ goto out; ++ } ++ ++ if (!sta) ++ goto out; ++ ++ ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path); ++out: ++ rcu_read_unlock(); ++ ++ return ret; ++} ++#endif ++ + static const struct net_device_ops ieee80211_dataif_8023_ops = { + #if LINUX_VERSION_IS_LESS(4,10,0) + .ndo_change_mtu = __change_mtu, +@@ -839,7 +899,9 @@ static const struct net_device_ops ieee8 + #else + .ndo_get_stats64 = bp_ieee80211_get_stats64, + #endif +- ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++ .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path, ++#endif + }; + + static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -2892,6 +2892,15 @@ TRACE_EVENT(drv_twt_teardown_request, + ) + ); + ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++DEFINE_EVENT(sta_event, drv_net_fill_forward_path, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta), ++ TP_ARGS(local, sdata, sta) ++); ++#endif ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/308-wifi-mac80211-fix-MLO-AP_VLAN-check.patch b/package/kernel/mac80211/patches/subsys/308-wifi-mac80211-fix-MLO-AP_VLAN-check.patch deleted file mode 100644 index 2d181e3a6..000000000 --- a/package/kernel/mac80211/patches/subsys/308-wifi-mac80211-fix-MLO-AP_VLAN-check.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Felix Fietkau -Date: Wed, 14 Dec 2022 13:46:38 +0100 -Subject: [PATCH] wifi: mac80211: fix MLO + AP_VLAN check - -Instead of preventing adding AP_VLAN to MLO enabled APs, this check was -preventing adding more than one 4-addr AP_VLAN regardless of the MLO status. -Fix this by adding missing extra checks. - -Fixes: ae960ee90bb1 ("wifi: mac80211: prevent VLANs on MLDs") -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -364,7 +364,9 @@ static int ieee80211_check_concurrent_if - - /* No support for VLAN with MLO yet */ - if (iftype == NL80211_IFTYPE_AP_VLAN && -- nsdata->wdev.use_4addr) -+ sdata->wdev.use_4addr && -+ nsdata->vif.type == NL80211_IFTYPE_AP && -+ nsdata->vif.valid_links) - return -EOPNOTSUPP; - - /* diff --git a/package/kernel/mac80211/patches/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch b/package/kernel/mac80211/patches/subsys/309-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch similarity index 100% rename from package/kernel/mac80211/patches/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch rename to package/kernel/mac80211/patches/subsys/309-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch diff --git a/package/kernel/mac80211/patches/subsys/310-mac80211-add-support-for-restricting-netdev-features.patch b/package/kernel/mac80211/patches/subsys/310-mac80211-add-support-for-restricting-netdev-features.patch deleted file mode 100644 index 3d286d080..000000000 --- a/package/kernel/mac80211/patches/subsys/310-mac80211-add-support-for-restricting-netdev-features.patch +++ /dev/null @@ -1,506 +0,0 @@ -From: Felix Fietkau -Date: Sun, 9 Oct 2022 20:15:46 +0200 -Subject: [PATCH] mac80211: add support for restricting netdev features per vif - -This can be used to selectively disable feature flags for checksum offload, -scatter/gather or GSO by changing vif->netdev_features. -Removing features from vif->netdev_features does not affect the netdev -features themselves, but instead fixes up skbs in the tx path so that the -offloads are not needed in the driver. - -Aside from making it easier to deal with vif type based hardware limitations, -this also makes it possible to optimize performance on hardware without native -GSO support by declaring GSO support in hw->netdev_features and removing it -from vif->netdev_features. This allows mac80211 to handle GSO segmentation -after the sta lookup, but before itxq enqueue, thus reducing the number of -unnecessary sta lookups, as well as some other per-packet processing. - -Signed-off-by: Felix Fietkau ---- - ---- a/include/net/fq_impl.h -+++ b/include/net/fq_impl.h -@@ -200,6 +200,7 @@ static void fq_tin_enqueue(struct fq *fq - fq_skb_free_t free_func) - { - struct fq_flow *flow; -+ struct sk_buff *next; - bool oom; - - lockdep_assert_held(&fq->lock); -@@ -214,11 +215,15 @@ static void fq_tin_enqueue(struct fq *fq - } - - flow->tin = tin; -- flow->backlog += skb->len; -- tin->backlog_bytes += skb->len; -- tin->backlog_packets++; -- fq->memory_usage += skb->truesize; -- fq->backlog++; -+ skb_list_walk_safe(skb, skb, next) { -+ skb_mark_not_on_list(skb); -+ flow->backlog += skb->len; -+ tin->backlog_bytes += skb->len; -+ tin->backlog_packets++; -+ fq->memory_usage += skb->truesize; -+ fq->backlog++; -+ __skb_queue_tail(&flow->queue, skb); -+ } - - if (list_empty(&flow->flowchain)) { - flow->deficit = fq->quantum; -@@ -226,7 +231,6 @@ static void fq_tin_enqueue(struct fq *fq - &tin->new_flows); - } - -- __skb_queue_tail(&flow->queue, skb); - oom = (fq->memory_usage > fq->memory_limit); - while (fq->backlog > fq->limit || oom) { - flow = fq_find_fattest_flow(fq); ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -1807,6 +1807,10 @@ struct ieee80211_vif_cfg { - * @addr: address of this interface - * @p2p: indicates whether this AP or STA interface is a p2p - * interface, i.e. a GO or p2p-sta respectively -+ * @netdev_features: tx netdev features supported by the hardware for this -+ * vif. mac80211 initializes this to hw->netdev_features, and the driver -+ * can mask out specific tx features. mac80211 will handle software fixup -+ * for masked offloads (GSO, CSUM) - * @driver_flags: flags/capabilities the driver has for this interface, - * these need to be set (or cleared) when the interface is added - * or, if supported by the driver, the interface type is changed -@@ -1848,6 +1852,7 @@ struct ieee80211_vif { - - struct ieee80211_txq *txq; - -+ netdev_features_t netdev_features; - u32 driver_flags; - u32 offload_flags; - ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -2181,6 +2181,7 @@ int ieee80211_if_add(struct ieee80211_lo - ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - ndev->hw_features |= ndev->features & - MAC80211_SUPPORTED_FEATURES_TX; -+ sdata->vif.netdev_features = local->hw.netdev_features; - - netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops); - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1355,7 +1355,11 @@ static struct txq_info *ieee80211_get_tx - - static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb) - { -- IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time(); -+ struct sk_buff *next; -+ codel_time_t now = codel_get_time(); -+ -+ skb_list_walk_safe(skb, skb, next) -+ IEEE80211_SKB_CB(skb)->control.enqueue_time = now; - } - - static u32 codel_skb_len_func(const struct sk_buff *skb) -@@ -3578,55 +3582,79 @@ ieee80211_xmit_fast_finish(struct ieee80 - return TX_CONTINUE; - } - --static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -- struct sta_info *sta, -- struct ieee80211_fast_tx *fast_tx, -- struct sk_buff *skb) -+static netdev_features_t -+ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata) - { -- struct ieee80211_local *local = sdata->local; -- u16 ethertype = (skb->data[12] << 8) | skb->data[13]; -- int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2); -- int hw_headroom = sdata->local->hw.extra_tx_headroom; -- struct ethhdr eth; -- struct ieee80211_tx_info *info; -- struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; -- struct ieee80211_tx_data tx; -- ieee80211_tx_result r; -- struct tid_ampdu_tx *tid_tx = NULL; -- u8 tid = IEEE80211_NUM_TIDS; -+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN) -+ return sdata->vif.netdev_features; - -- /* control port protocol needs a lot of special handling */ -- if (cpu_to_be16(ethertype) == sdata->control_port_protocol) -- return false; -+ if (!sdata->bss) -+ return 0; - -- /* only RFC 1042 SNAP */ -- if (ethertype < ETH_P_802_3_MIN) -- return false; -+ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); -+ return sdata->vif.netdev_features; -+} - -- /* don't handle TX status request here either */ -- if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS) -- return false; -+static struct sk_buff * -+ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features) -+{ -+ if (skb_is_gso(skb)) { -+ struct sk_buff *segs; - -- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -- tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); -- if (tid_tx) { -- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) -- return false; -- if (tid_tx->timeout) -- tid_tx->last_tx = jiffies; -- } -+ segs = skb_gso_segment(skb, features); -+ if (!segs) -+ return skb; -+ if (IS_ERR(segs)) -+ goto free; -+ -+ consume_skb(skb); -+ return segs; - } - -- /* after this point (skb is modified) we cannot return false */ -+ if (skb_needs_linearize(skb, features) && __skb_linearize(skb)) -+ goto free; -+ -+ if (skb->ip_summed == CHECKSUM_PARTIAL) { -+ int ofs = skb_checksum_start_offset(skb); -+ -+ if (skb->encapsulation) -+ skb_set_inner_transport_header(skb, ofs); -+ else -+ skb_set_transport_header(skb, ofs); -+ -+ if (skb_csum_hwoffload_help(skb, features)) -+ goto free; -+ } -+ -+ skb_mark_not_on_list(skb); -+ return skb; -+ -+free: -+ kfree_skb(skb); -+ return NULL; -+} -+ -+static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -+ struct sta_info *sta, -+ struct ieee80211_fast_tx *fast_tx, -+ struct sk_buff *skb, u8 tid, bool ampdu) -+{ -+ struct ieee80211_local *local = sdata->local; -+ struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; -+ struct ieee80211_tx_info *info; -+ struct ieee80211_tx_data tx; -+ ieee80211_tx_result r; -+ int hw_headroom = sdata->local->hw.extra_tx_headroom; -+ int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2); -+ struct ethhdr eth; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (unlikely(!skb)) -- return true; -+ return; - - if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && - ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) -- return true; -+ return; - - /* will not be crypto-handled beyond what we do here, so use false - * as the may-encrypt argument for the resize to not account for -@@ -3635,10 +3663,8 @@ static bool ieee80211_xmit_fast(struct i - if (unlikely(ieee80211_skb_resize(sdata, skb, - max_t(int, extra_head + hw_headroom - - skb_headroom(skb), 0), -- ENCRYPT_NO))) { -- kfree_skb(skb); -- return true; -- } -+ ENCRYPT_NO))) -+ goto free; - - memcpy(ð, skb->data, ETH_HLEN - 2); - hdr = skb_push(skb, extra_head); -@@ -3652,7 +3678,7 @@ static bool ieee80211_xmit_fast(struct i - info->control.vif = &sdata->vif; - info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | - IEEE80211_TX_CTL_DONTFRAG | -- (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); -+ (ampdu ? IEEE80211_TX_CTL_AMPDU : 0); - info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT | - u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, - IEEE80211_TX_CTRL_MLO_LINK); -@@ -3676,16 +3702,14 @@ static bool ieee80211_xmit_fast(struct i - tx.key = fast_tx->key; - - if (ieee80211_queue_skb(local, sdata, sta, skb)) -- return true; -+ return; - - tx.skb = skb; - r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, - fast_tx->key, &tx); - tx.skb = NULL; -- if (r == TX_DROP) { -- kfree_skb(skb); -- return true; -- } -+ if (r == TX_DROP) -+ goto free; - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, -@@ -3693,6 +3717,56 @@ static bool ieee80211_xmit_fast(struct i - - __skb_queue_tail(&tx.skbs, skb); - ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false); -+ return; -+ -+free: -+ kfree_skb(skb); -+} -+ -+static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -+ struct sta_info *sta, -+ struct ieee80211_fast_tx *fast_tx, -+ struct sk_buff *skb) -+{ -+ u16 ethertype = (skb->data[12] << 8) | skb->data[13]; -+ struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; -+ struct tid_ampdu_tx *tid_tx = NULL; -+ struct sk_buff *next; -+ u8 tid = IEEE80211_NUM_TIDS; -+ -+ /* control port protocol needs a lot of special handling */ -+ if (cpu_to_be16(ethertype) == sdata->control_port_protocol) -+ return false; -+ -+ /* only RFC 1042 SNAP */ -+ if (ethertype < ETH_P_802_3_MIN) -+ return false; -+ -+ /* don't handle TX status request here either */ -+ if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS) -+ return false; -+ -+ if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -+ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); -+ if (tid_tx) { -+ if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) -+ return false; -+ if (tid_tx->timeout) -+ tid_tx->last_tx = jiffies; -+ } -+ } -+ -+ /* after this point (skb is modified) we cannot return false */ -+ skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata)); -+ if (!skb) -+ return true; -+ -+ skb_list_walk_safe(skb, skb, next) { -+ skb_mark_not_on_list(skb); -+ __ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid, tid_tx); -+ } -+ - return true; - } - -@@ -4193,31 +4267,14 @@ void __ieee80211_subif_start_xmit(struct - goto out; - } - -- if (skb_is_gso(skb)) { -- struct sk_buff *segs; -- -- segs = skb_gso_segment(skb, 0); -- if (IS_ERR(segs)) { -- goto out_free; -- } else if (segs) { -- consume_skb(skb); -- skb = segs; -- } -- } else { -- /* we cannot process non-linear frames on this path */ -- if (skb_linearize(skb)) -- goto out_free; -- -- /* the frame could be fragmented, software-encrypted, and other -- * things so we cannot really handle checksum offload with it - -- * fix it up in software before we handle anything else. -- */ -- if (skb->ip_summed == CHECKSUM_PARTIAL) { -- skb_set_transport_header(skb, -- skb_checksum_start_offset(skb)); -- if (skb_checksum_help(skb)) -- goto out_free; -- } -+ /* the frame could be fragmented, software-encrypted, and other -+ * things so we cannot really handle checksum or GSO offload. -+ * fix it up in software before we handle anything else. -+ */ -+ skb = ieee80211_tx_skb_fixup(skb, 0); -+ if (!skb) { -+ len = 0; -+ goto out; - } - - skb_list_walk_safe(skb, skb, next) { -@@ -4435,9 +4492,11 @@ normal: - return NETDEV_TX_OK; - } - --static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata, -- struct sk_buff *skb, struct sta_info *sta, -- bool txpending) -+ -+ -+static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb, struct sta_info *sta, -+ bool txpending) - { - struct ieee80211_local *local = sdata->local; - struct ieee80211_tx_control control = {}; -@@ -4446,14 +4505,6 @@ static bool ieee80211_tx_8023(struct iee - unsigned long flags; - int q = info->hw_queue; - -- if (sta) -- sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift); -- -- ieee80211_tpt_led_trig_tx(local, skb->len); -- -- if (ieee80211_queue_skb(local, sdata, sta, skb)) -- return true; -- - spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - - if (local->queue_stop_reasons[q] || -@@ -4480,6 +4531,26 @@ static bool ieee80211_tx_8023(struct iee - return true; - } - -+static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb, struct sta_info *sta, -+ bool txpending) -+{ -+ struct ieee80211_local *local = sdata->local; -+ struct sk_buff *next; -+ bool ret = true; -+ -+ if (ieee80211_queue_skb(local, sdata, sta, skb)) -+ return true; -+ -+ skb_list_walk_safe(skb, skb, next) { -+ skb_mark_not_on_list(skb); -+ if (!__ieee80211_tx_8023(sdata, skb, sta, txpending)) -+ ret = false; -+ } -+ -+ return ret; -+} -+ - static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, - struct net_device *dev, struct sta_info *sta, - struct ieee80211_key *key, struct sk_buff *skb) -@@ -4487,9 +4558,13 @@ static void ieee80211_8023_xmit(struct i - struct ieee80211_tx_info *info; - struct ieee80211_local *local = sdata->local; - struct tid_ampdu_tx *tid_tx; -+ struct sk_buff *seg, *next; -+ unsigned int skbs = 0, len = 0; -+ u16 queue; - u8 tid; - -- skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb)); -+ queue = ieee80211_select_queue(sdata, sta, skb); -+ skb_set_queue_mapping(skb, queue); - - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) && - test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) -@@ -4499,9 +4574,6 @@ static void ieee80211_8023_xmit(struct i - if (unlikely(!skb)) - return; - -- info = IEEE80211_SKB_CB(skb); -- memset(info, 0, sizeof(*info)); -- - ieee80211_aggr_check(sdata, sta, skb); - - tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -@@ -4515,22 +4587,20 @@ static void ieee80211_8023_xmit(struct i - return; - } - -- info->flags |= IEEE80211_TX_CTL_AMPDU; - if (tid_tx->timeout) - tid_tx->last_tx = jiffies; - } - -- if (unlikely(skb->sk && -- skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) -- info->ack_frame_id = ieee80211_store_ack_skb(local, skb, -- &info->flags, NULL); -+ skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata)); -+ if (!skb) -+ return; - -- info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -+ info = IEEE80211_SKB_CB(skb); -+ memset(info, 0, sizeof(*info)); -+ if (tid_tx) -+ info->flags |= IEEE80211_TX_CTL_AMPDU; - -- dev_sw_netstats_tx_add(dev, 1, skb->len); -- -- sta->deflink.tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; -- sta->deflink.tx_stats.packets[skb_get_queue_mapping(skb)]++; -+ info->hw_queue = sdata->vif.hw_queue[queue]; - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, -@@ -4542,6 +4612,24 @@ static void ieee80211_8023_xmit(struct i - if (key) - info->control.hw_key = &key->conf; - -+ skb_list_walk_safe(skb, seg, next) { -+ skbs++; -+ len += seg->len; -+ if (seg != skb) -+ memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info)); -+ } -+ -+ if (unlikely(skb->sk && -+ skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) -+ info->ack_frame_id = ieee80211_store_ack_skb(local, skb, -+ &info->flags, NULL); -+ -+ dev_sw_netstats_tx_add(dev, skbs, len); -+ sta->deflink.tx_stats.packets[queue] += skbs; -+ sta->deflink.tx_stats.bytes[queue] += len; -+ -+ ieee80211_tpt_led_trig_tx(local, len); -+ - ieee80211_tx_8023(sdata, skb, sta, false); - - return; -@@ -4583,6 +4671,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8 - key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)) - goto skip_offload; - -+ sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift); - ieee80211_8023_xmit(sdata, dev, sta, key, skb); - goto out; - diff --git a/package/kernel/mac80211/patches/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch b/package/kernel/mac80211/patches/subsys/310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch similarity index 94% rename from package/kernel/mac80211/patches/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch rename to package/kernel/mac80211/patches/subsys/310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch index f26477e81..16bcbc2ef 100644 --- a/package/kernel/mac80211/patches/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch +++ b/package/kernel/mac80211/patches/subsys/310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -769,7 +769,8 @@ minstrel_ht_calc_rate_stats(struct minst +@@ -700,7 +700,8 @@ minstrel_ht_calc_rate_stats(struct minst unsigned int cur_prob; if (unlikely(mrs->attempts > 0)) { diff --git a/package/kernel/mac80211/patches/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch b/package/kernel/mac80211/patches/subsys/311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch similarity index 89% rename from package/kernel/mac80211/patches/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch rename to package/kernel/mac80211/patches/subsys/311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch index 9b3cc3a66..a6817bd4a 100644 --- a/package/kernel/mac80211/patches/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch +++ b/package/kernel/mac80211/patches/subsys/311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -580,6 +580,14 @@ minstrel_ht_set_best_prob_rate(struct mi +@@ -511,6 +511,14 @@ minstrel_ht_set_best_prob_rate(struct mi int cur_tp_avg, cur_group, cur_idx; int max_gpr_group, max_gpr_idx; int max_gpr_tp_avg, max_gpr_prob; @@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau cur_group = MI_RATE_GROUP(index); cur_idx = MI_RATE_IDX(index); -@@ -601,11 +609,6 @@ minstrel_ht_set_best_prob_rate(struct mi +@@ -532,11 +540,6 @@ minstrel_ht_set_best_prob_rate(struct mi !minstrel_ht_is_legacy_group(max_tp_group)) return; @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; -@@ -663,40 +666,6 @@ minstrel_ht_assign_best_tp_rates(struct +@@ -594,40 +597,6 @@ minstrel_ht_assign_best_tp_rates(struct } @@ -60,7 +60,7 @@ Signed-off-by: Felix Fietkau - int tmp_max_streams, group, tmp_idx, tmp_prob; - int tmp_tp = 0; - -- if (!mi->sta->deflink.ht_cap.ht_supported) +- if (!mi->sta->ht_cap.ht_supported) - return; - - group = MI_RATE_GROUP(mi->max_tp_rate[0]); @@ -86,7 +86,7 @@ Signed-off-by: Felix Fietkau static u16 __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, enum minstrel_sample_type type) -@@ -1176,8 +1145,6 @@ minstrel_ht_update_stats(struct minstrel +@@ -1107,8 +1076,6 @@ minstrel_ht_update_stats(struct minstrel mi->max_prob_rate = tmp_max_prob_rate; @@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau minstrel_ht_refill_sample_rates(mi); #ifdef CPTCFG_MAC80211_DEBUGFS -@@ -1256,7 +1223,7 @@ minstrel_ht_ri_txstat_valid(struct minst +@@ -1153,7 +1120,7 @@ minstrel_ht_txstat_valid(struct minstrel } static void @@ -104,7 +104,7 @@ Signed-off-by: Felix Fietkau { int group, orig_group; -@@ -1271,11 +1238,7 @@ minstrel_downgrade_rate(struct minstrel_ +@@ -1168,11 +1135,7 @@ minstrel_downgrade_rate(struct minstrel_ minstrel_mcs_groups[orig_group].streams) continue; @@ -117,7 +117,7 @@ Signed-off-by: Felix Fietkau } } -@@ -1286,7 +1249,7 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1183,7 +1146,7 @@ minstrel_ht_tx_status(void *priv, struct struct ieee80211_tx_info *info = st->info; struct minstrel_ht_sta *mi = priv_sta; struct ieee80211_tx_rate *ar = info->status.rates; @@ -126,7 +126,7 @@ Signed-off-by: Felix Fietkau struct minstrel_priv *mp = priv; u32 update_interval = mp->update_interval; bool last, update = false; -@@ -1354,18 +1317,13 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1233,18 +1196,13 @@ minstrel_ht_tx_status(void *priv, struct /* * check for sudden death of spatial multiplexing, * downgrade to a lower number of streams if necessary. diff --git a/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch b/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch new file mode 100644 index 000000000..18b1951f6 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch @@ -0,0 +1,262 @@ +From: Aloka Dixit +Date: Tue, 5 Oct 2021 21:09:36 -0700 +Subject: [PATCH] mac80211: split beacon retrieval functions + +Split __ieee80211_beacon_get() into a separate function for AP mode +ieee80211_beacon_get_ap(). +Also, move the code common to all modes (AP, adhoc and mesh) to +a separate function ieee80211_beacon_get_finish(). + +Signed-off-by: Aloka Dixit +Link: https://lore.kernel.org/r/20211006040938.9531-2-alokad@codeaurora.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4987,6 +4987,115 @@ static int ieee80211_beacon_protect(stru + return 0; + } + ++static void ++ieee80211_beacon_get_finish(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_mutable_offsets *offs, ++ struct beacon_data *beacon, ++ struct sk_buff *skb, ++ struct ieee80211_chanctx_conf *chanctx_conf, ++ u16 csa_off_base) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_tx_info *info; ++ enum nl80211_band band; ++ struct ieee80211_tx_rate_control txrc; ++ ++ /* CSA offsets */ ++ if (offs && beacon) { ++ u16 i; ++ ++ for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { ++ u16 csa_off = beacon->cntdwn_counter_offsets[i]; ++ ++ if (!csa_off) ++ continue; ++ ++ offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; ++ } ++ } ++ ++ band = chanctx_conf->def.chan->band; ++ info = IEEE80211_SKB_CB(skb); ++ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ++ info->flags |= IEEE80211_TX_CTL_NO_ACK; ++ info->band = band; ++ ++ memset(&txrc, 0, sizeof(txrc)); ++ txrc.hw = hw; ++ txrc.sband = local->hw.wiphy->bands[band]; ++ txrc.bss_conf = &sdata->vif.bss_conf; ++ txrc.skb = skb; ++ txrc.reported_rate.idx = -1; ++ if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) ++ txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; ++ else ++ txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; ++ txrc.bss = true; ++ rate_control_get_rate(sdata, NULL, &txrc); ++ ++ info->control.vif = vif; ++ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | ++ IEEE80211_TX_CTL_ASSIGN_SEQ | ++ IEEE80211_TX_CTL_FIRST_FRAGMENT; ++} ++ ++static struct sk_buff * ++ieee80211_beacon_get_ap(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_mutable_offsets *offs, ++ bool is_template, ++ struct beacon_data *beacon, ++ struct ieee80211_chanctx_conf *chanctx_conf) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_if_ap *ap = &sdata->u.ap; ++ struct sk_buff *skb = NULL; ++ u16 csa_off_base = 0; ++ ++ if (beacon->cntdwn_counter_offsets[0]) { ++ if (!is_template) ++ ieee80211_beacon_update_cntdwn(vif); ++ ++ ieee80211_set_beacon_cntdwn(sdata, beacon); ++ } ++ ++ /* headroom, head length, ++ * tail length and maximum TIM length ++ */ ++ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + ++ beacon->tail_len + 256 + ++ local->hw.extra_beacon_tailroom); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, local->tx_headroom); ++ skb_put_data(skb, beacon->head, beacon->head_len); ++ ++ ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template); ++ ++ if (offs) { ++ offs->tim_offset = beacon->head_len; ++ offs->tim_length = skb->len - beacon->head_len; ++ offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; ++ ++ /* for AP the csa offsets are from tail */ ++ csa_off_base = skb->len; ++ } ++ ++ if (beacon->tail) ++ skb_put_data(skb, beacon->tail, beacon->tail_len); ++ ++ if (ieee80211_beacon_protect(skb, local, sdata) < 0) ++ return NULL; ++ ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, ++ csa_off_base); ++ return skb; ++} ++ + static struct sk_buff * + __ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -4996,12 +5105,8 @@ __ieee80211_beacon_get(struct ieee80211_ + struct ieee80211_local *local = hw_to_local(hw); + struct beacon_data *beacon = NULL; + struct sk_buff *skb = NULL; +- struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata = NULL; +- enum nl80211_band band; +- struct ieee80211_tx_rate_control txrc; + struct ieee80211_chanctx_conf *chanctx_conf; +- int csa_off_base = 0; + + rcu_read_lock(); + +@@ -5018,48 +5123,11 @@ __ieee80211_beacon_get(struct ieee80211_ + struct ieee80211_if_ap *ap = &sdata->u.ap; + + beacon = rcu_dereference(ap->beacon); +- if (beacon) { +- if (beacon->cntdwn_counter_offsets[0]) { +- if (!is_template) +- ieee80211_beacon_update_cntdwn(vif); +- +- ieee80211_set_beacon_cntdwn(sdata, beacon); +- } +- +- /* +- * headroom, head length, +- * tail length and maximum TIM length +- */ +- skb = dev_alloc_skb(local->tx_headroom + +- beacon->head_len + +- beacon->tail_len + 256 + +- local->hw.extra_beacon_tailroom); +- if (!skb) +- goto out; +- +- skb_reserve(skb, local->tx_headroom); +- skb_put_data(skb, beacon->head, beacon->head_len); +- +- ieee80211_beacon_add_tim(sdata, &ap->ps, skb, +- is_template); +- +- if (offs) { +- offs->tim_offset = beacon->head_len; +- offs->tim_length = skb->len - beacon->head_len; +- offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; +- +- /* for AP the csa offsets are from tail */ +- csa_off_base = skb->len; +- } +- +- if (beacon->tail) +- skb_put_data(skb, beacon->tail, +- beacon->tail_len); +- +- if (ieee80211_beacon_protect(skb, local, sdata) < 0) +- goto out; +- } else ++ if (!beacon) + goto out; ++ ++ skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, ++ beacon, chanctx_conf); + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + struct ieee80211_hdr *hdr; +@@ -5085,6 +5153,9 @@ __ieee80211_beacon_get(struct ieee80211_ + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_BEACON); ++ ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, ++ chanctx_conf, 0); + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + +@@ -5124,51 +5195,13 @@ __ieee80211_beacon_get(struct ieee80211_ + } + + skb_put_data(skb, beacon->tail, beacon->tail_len); ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, ++ chanctx_conf, 0); + } else { + WARN_ON(1); + goto out; + } + +- /* CSA offsets */ +- if (offs && beacon) { +- int i; +- +- for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { +- u16 csa_off = beacon->cntdwn_counter_offsets[i]; +- +- if (!csa_off) +- continue; +- +- offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; +- } +- } +- +- band = chanctx_conf->def.chan->band; +- +- info = IEEE80211_SKB_CB(skb); +- +- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +- info->flags |= IEEE80211_TX_CTL_NO_ACK; +- info->band = band; +- +- memset(&txrc, 0, sizeof(txrc)); +- txrc.hw = hw; +- txrc.sband = local->hw.wiphy->bands[band]; +- txrc.bss_conf = &sdata->vif.bss_conf; +- txrc.skb = skb; +- txrc.reported_rate.idx = -1; +- if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) +- txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; +- else +- txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; +- txrc.bss = true; +- rate_control_get_rate(sdata, NULL, &txrc); +- +- info->control.vif = vif; +- +- info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | +- IEEE80211_TX_CTL_ASSIGN_SEQ | +- IEEE80211_TX_CTL_FIRST_FRAGMENT; + out: + rcu_read_unlock(); + return skb; diff --git a/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch new file mode 100644 index 000000000..4fc8b592c --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch @@ -0,0 +1,493 @@ +From: John Crispin +Date: Wed, 15 Sep 2021 19:54:34 -0700 +Subject: [PATCH] nl80211: MBSSID and EMA support in AP mode + +Add new attributes to configure support for multiple BSSID +and advanced multi-BSSID advertisements (EMA) in AP mode. + +- NL80211_ATTR_MBSSID_CONFIG used for per interface configuration. +- NL80211_ATTR_MBSSID_ELEMS used to MBSSID elements for beacons. + +Memory for the elements is allocated dynamically. This change frees +the memory in existing functions which call nl80211_parse_beacon(), +a comment is added to indicate the new references to do the same. + +Signed-off-by: John Crispin +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Link: https://lore.kernel.org/r/20210916025437.29138-2-alokad@codeaurora.org +[don't leave ERR_PTR hanging around] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1046,6 +1046,36 @@ struct cfg80211_crypto_settings { + }; + + /** ++ * struct cfg80211_mbssid_config - AP settings for multi bssid ++ * ++ * @tx_wdev: pointer to the transmitted interface in the MBSSID set ++ * @index: index of this AP in the multi bssid group. ++ * @ema: set to true if the beacons should be sent out in EMA mode. ++ */ ++struct cfg80211_mbssid_config { ++ struct wireless_dev *tx_wdev; ++ u8 index; ++ bool ema; ++}; ++ ++/** ++ * struct cfg80211_mbssid_elems - Multiple BSSID elements ++ * ++ * @cnt: Number of elements in array %elems. ++ * ++ * @elem: Array of multiple BSSID element(s) to be added into Beacon frames. ++ * @elem.data: Data for multiple BSSID elements. ++ * @elem.len: Length of data. ++ */ ++struct cfg80211_mbssid_elems { ++ u8 cnt; ++ struct { ++ const u8 *data; ++ size_t len; ++ } elem[]; ++}; ++ ++/** + * struct cfg80211_beacon_data - beacon data + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed +@@ -1063,6 +1093,7 @@ struct cfg80211_crypto_settings { + * @assocresp_ies_len: length of assocresp_ies in octets + * @probe_resp_len: length of probe response template (@probe_resp) + * @probe_resp: probe response template (AP mode only) ++ * @mbssid_ies: multiple BSSID elements + * @ftm_responder: enable FTM responder functionality; -1 for no change + * (which also implies no change in LCI/civic location data) + * @lci: Measurement Report element content, starting with Measurement Token +@@ -1080,6 +1111,7 @@ struct cfg80211_beacon_data { + const u8 *probe_resp; + const u8 *lci; + const u8 *civicloc; ++ struct cfg80211_mbssid_elems *mbssid_ies; + s8 ftm_responder; + + size_t head_len, tail_len; +@@ -1194,6 +1226,7 @@ enum cfg80211_ap_settings_flags { + * @he_oper: HE operation IE (or %NULL if HE isn't enabled) + * @fils_discovery: FILS discovery transmission parameters + * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters ++ * @mbssid_config: AP settings for multiple bssid + */ + struct cfg80211_ap_settings { + struct cfg80211_chan_def chandef; +@@ -1226,6 +1259,7 @@ struct cfg80211_ap_settings { + struct cfg80211_he_bss_color he_bss_color; + struct cfg80211_fils_discovery fils_discovery; + struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; ++ struct cfg80211_mbssid_config mbssid_config; + }; + + /** +@@ -4986,6 +5020,13 @@ struct wiphy_iftype_akm_suites { + * %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes + * @sar_capa: SAR control capabilities + * @rfkill: a pointer to the rfkill structure ++ * ++ * @mbssid_max_interfaces: maximum number of interfaces supported by the driver ++ * in a multiple BSSID set. This field must be set to a non-zero value ++ * by the driver to advertise MBSSID support. ++ * @mbssid_max_ema_profile_periodicity: maximum profile periodicity supported by ++ * the driver. Setting this field to a non-zero value indicates that the ++ * driver supports enhanced multi-BSSID advertisements (EMA AP). + */ + struct wiphy { + struct mutex mtx; +@@ -5133,6 +5174,9 @@ struct wiphy { + + struct rfkill *rfkill; + ++ u8 mbssid_max_interfaces; ++ u8 ema_max_profile_periodicity; ++ + char priv[] __aligned(NETDEV_ALIGN); + }; + +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -337,7 +337,10 @@ + * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from + * userspace to request deletion of a virtual interface, then requires +- * attribute %NL80211_ATTR_IFINDEX. ++ * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are ++ * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, ++ * and if this command is used for the transmitting interface, then all ++ * the non-transmitting interfaces are deleted as well. + * + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. +@@ -2593,6 +2596,18 @@ enum nl80211_commands { + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. + * ++ * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID ++ * advertisements (MBSSID) parameters in AP mode. ++ * Kernel uses this attribute to indicate the driver's support for MBSSID ++ * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. ++ * Userspace should use this attribute to configure per interface MBSSID ++ * parameters. ++ * See &enum nl80211_mbssid_config_attributes for details. ++ * ++ * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. ++ * Mandatory parameter for the transmitting interface to enable MBSSID. ++ * Optional for the non-transmitting interfaces. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3096,6 +3111,9 @@ enum nl80211_attrs { + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + ++ NL80211_ATTR_MBSSID_CONFIG, ++ NL80211_ATTR_MBSSID_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -7349,4 +7367,60 @@ enum nl80211_sar_specs_attrs { + NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, + }; + ++/** ++ * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced ++ * multi-BSSID advertisements (EMA) in AP mode. ++ * Kernel uses some of these attributes to advertise driver's support for ++ * MBSSID and EMA. ++ * Remaining attributes should be used by the userspace to configure the ++ * features. ++ * ++ * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise ++ * the maximum number of MBSSID interfaces supported by the driver. ++ * Driver should indicate MBSSID support by setting ++ * wiphy->mbssid_max_interfaces to a value more than or equal to 2. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel ++ * to advertise the maximum profile periodicity supported by the driver ++ * if EMA is enabled. Driver should indicate EMA support to the userspace ++ * by setting wiphy->mbssid_max_ema_profile_periodicity to ++ * a non-zero value. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of ++ * this BSS (u8) in the multiple BSSID set. ++ * Value must be set to 0 for the transmitting interface and non-zero for ++ * all non-transmitting interfaces. The userspace will be responsible ++ * for using unique indices for the interfaces. ++ * Range: 0 to wiphy->mbssid_max_interfaces-1. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for ++ * a non-transmitted profile which provides the interface index (u32) of ++ * the transmitted profile. The value must match one of the interface ++ * indices advertised by the kernel. Optional if the interface being set up ++ * is the transmitting one, however, if provided then the value must match ++ * the interface index of the same. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. ++ * Setting this flag is permitted only if the driver advertises EMA support ++ * by setting wiphy->mbssid_max_ema_profile_periodicity to non-zero. ++ * ++ * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute ++ */ ++enum nl80211_mbssid_config_attributes { ++ __NL80211_MBSSID_CONFIG_ATTR_INVALID, ++ ++ NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, ++ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, ++ NL80211_MBSSID_CONFIG_ATTR_INDEX, ++ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, ++ NL80211_MBSSID_CONFIG_ATTR_EMA, ++ ++ /* keep last */ ++ __NL80211_MBSSID_CONFIG_ATTR_LAST, ++ NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, ++}; ++ + #endif /* __LINUX_NL80211_H */ +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -442,6 +442,16 @@ sar_policy[NL80211_SAR_ATTR_MAX + 1] = { + [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), + }; + ++static const struct nla_policy ++nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = { ++ [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2), ++ [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] = ++ NLA_POLICY_MIN(NLA_U8, 1), ++ [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 }, ++ [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 }, ++ [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG }, ++}; ++ + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, + [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, +@@ -783,6 +793,9 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, + [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, + [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), ++ [NL80211_ATTR_MBSSID_CONFIG] = ++ NLA_POLICY_NESTED(nl80211_mbssid_config_policy), ++ [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, + }; + + /* policy for the key attributes */ +@@ -2231,6 +2244,35 @@ fail: + return -ENOBUFS; + } + ++static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg) ++{ ++ struct nlattr *config; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return 0; ++ ++ config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); ++ if (!config) ++ return -ENOBUFS; ++ ++ if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, ++ wiphy->mbssid_max_interfaces)) ++ goto fail; ++ ++ if (wiphy->ema_max_profile_periodicity && ++ nla_put_u8(msg, ++ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, ++ wiphy->ema_max_profile_periodicity)) ++ goto fail; ++ ++ nla_nest_end(msg, config); ++ return 0; ++ ++fail: ++ nla_nest_cancel(msg, config); ++ return -ENOBUFS; ++} ++ + struct nl80211_dump_wiphy_state { + s64 filter_wiphy; + long start; +@@ -2816,6 +2858,9 @@ static int nl80211_send_wiphy(struct cfg + if (nl80211_put_sar_specs(rdev, msg)) + goto nla_put_failure; + ++ if (nl80211_put_mbssid_support(&rdev->wiphy, msg)) ++ goto nla_put_failure; ++ + /* done */ + state->split_start = 0; + break; +@@ -5005,6 +5050,96 @@ static int validate_beacon_tx_rate(struc + return 0; + } + ++static int nl80211_parse_mbssid_config(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct nlattr *attrs, ++ struct cfg80211_mbssid_config *config, ++ u8 num_elems) ++{ ++ struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return -EOPNOTSUPP; ++ ++ if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL, ++ NULL) || ++ !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]) ++ return -EINVAL; ++ ++ config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]); ++ if (config->ema) { ++ if (!wiphy->ema_max_profile_periodicity) ++ return -EOPNOTSUPP; ++ ++ if (num_elems > wiphy->ema_max_profile_periodicity) ++ return -EINVAL; ++ } ++ ++ config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]); ++ if (config->index >= wiphy->mbssid_max_interfaces || ++ (!config->index && !num_elems)) ++ return -EINVAL; ++ ++ if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) { ++ u32 tx_ifindex = ++ nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]); ++ ++ if ((!config->index && tx_ifindex != dev->ifindex) || ++ (config->index && tx_ifindex == dev->ifindex)) ++ return -EINVAL; ++ ++ if (tx_ifindex != dev->ifindex) { ++ struct net_device *tx_netdev = ++ dev_get_by_index(wiphy_net(wiphy), tx_ifindex); ++ ++ if (!tx_netdev || !tx_netdev->ieee80211_ptr || ++ tx_netdev->ieee80211_ptr->wiphy != wiphy || ++ tx_netdev->ieee80211_ptr->iftype != ++ NL80211_IFTYPE_AP) { ++ dev_put(tx_netdev); ++ return -EINVAL; ++ } ++ ++ config->tx_wdev = tx_netdev->ieee80211_ptr; ++ } else { ++ config->tx_wdev = dev->ieee80211_ptr; ++ } ++ } else if (!config->index) { ++ config->tx_wdev = dev->ieee80211_ptr; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct cfg80211_mbssid_elems * ++nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) ++{ ++ struct nlattr *nl_elems; ++ struct cfg80211_mbssid_elems *elems; ++ int rem_elems; ++ u8 i = 0, num_elems = 0; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return ERR_PTR(-EINVAL); ++ ++ nla_for_each_nested(nl_elems, attrs, rem_elems) ++ num_elems++; ++ ++ elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL); ++ if (!elems) ++ return ERR_PTR(-ENOMEM); ++ ++ nla_for_each_nested(nl_elems, attrs, rem_elems) { ++ elems->elem[i].data = nla_data(nl_elems); ++ elems->elem[i].len = nla_len(nl_elems); ++ i++; ++ } ++ elems->cnt = num_elems; ++ return elems; ++} ++ + static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, + struct nlattr *attrs[], + struct cfg80211_beacon_data *bcn) +@@ -5085,6 +5220,17 @@ static int nl80211_parse_beacon(struct c + bcn->ftm_responder = -1; + } + ++ if (attrs[NL80211_ATTR_MBSSID_ELEMS]) { ++ struct cfg80211_mbssid_elems *mbssid = ++ nl80211_parse_mbssid_elems(&rdev->wiphy, ++ attrs[NL80211_ATTR_MBSSID_ELEMS]); ++ ++ if (IS_ERR(mbssid)) ++ return PTR_ERR(mbssid); ++ ++ bcn->mbssid_ies = mbssid; ++ } ++ + return 0; + } + +@@ -5541,6 +5687,17 @@ static int nl80211_start_ap(struct sk_bu + goto out; + } + ++ if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) { ++ err = nl80211_parse_mbssid_config(&rdev->wiphy, dev, ++ info->attrs[NL80211_ATTR_MBSSID_CONFIG], ++ ¶ms.mbssid_config, ++ params.beacon.mbssid_ies ? ++ params.beacon.mbssid_ies->cnt : ++ 0); ++ if (err) ++ goto out; ++ } ++ + nl80211_calculate_ap_params(¶ms); + + if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) +@@ -5562,6 +5719,11 @@ static int nl80211_start_ap(struct sk_bu + + out: + kfree(params.acl); ++ kfree(params.beacon.mbssid_ies); ++ if (params.mbssid_config.tx_wdev && ++ params.mbssid_config.tx_wdev->netdev && ++ params.mbssid_config.tx_wdev->netdev != dev) ++ dev_put(params.mbssid_config.tx_wdev->netdev); + + return err; + } +@@ -5586,12 +5748,14 @@ static int nl80211_set_beacon(struct sk_ + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); + if (err) +- return err; ++ goto out; + + wdev_lock(wdev); + err = rdev_change_beacon(rdev, dev, ¶ms); + wdev_unlock(wdev); + ++out: ++ kfree(params.mbssid_ies); + return err; + } + +@@ -9268,12 +9432,14 @@ static int nl80211_channel_switch(struct + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after); + if (err) +- return err; ++ goto free; + + csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs), + GFP_KERNEL); +- if (!csa_attrs) +- return -ENOMEM; ++ if (!csa_attrs) { ++ err = -ENOMEM; ++ goto free; ++ } + + err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX, + info->attrs[NL80211_ATTR_CSA_IES], +@@ -9392,6 +9558,8 @@ skip_beacons: + wdev_unlock(wdev); + + free: ++ kfree(params.beacon_after.mbssid_ies); ++ kfree(params.beacon_csa.mbssid_ies); + kfree(csa_attrs); + return err; + } +@@ -14939,6 +15107,8 @@ static int nl80211_color_change(struct s + wdev_unlock(wdev); + + out: ++ kfree(params.beacon_next.mbssid_ies); ++ kfree(params.beacon_color_change.mbssid_ies); + kfree(tb); + return err; + } diff --git a/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch b/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch new file mode 100644 index 000000000..90c56b4e4 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch @@ -0,0 +1,378 @@ +From: Lorenzo Bianconi +Date: Sat, 23 Oct 2021 11:10:50 +0200 +Subject: [PATCH] cfg80211: implement APIs for dedicated radar detection HW + +If a dedicated (off-channel) radar detection hardware (chain) +is available in the hardware/driver, allow this to be used by +calling the NL80211_CMD_RADAR_DETECT command with a new flag +attribute requesting off-channel radar detection is used. + +Offchannel CAC (channel availability check) avoids the CAC +downtime when switching to a radar channel or when turning on +the AP. + +Drivers advertise support for this using the new feature flag +NL80211_EXT_FEATURE_RADAR_OFFCHAN. + +Tested-by: Evelyn Tsai +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/7468e291ef5d05d692c1738d25b8f778d8ea5c3f.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/1e60e60fef00e14401adae81c3d49f3e5f307537.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/85fa50f57fc3adb2934c8d9ca0be30394de6b7e8.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/4b6c08671ad59aae0ac46fc94c02f31b1610eb72.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/241849ccaf2c228873c6f8495bf87b19159ba458.1634979655.git.lorenzo@kernel.org +[remove offchan_mutex, fix cfg80211_stop_offchan_radar_detection(), + remove gfp_t argument, fix documentation, fix tracing] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -4057,6 +4057,15 @@ struct mgmt_frame_regs { + * @set_sar_specs: Update the SAR (TX power) settings. + * + * @color_change: Initiate a color change. ++ * ++ * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * radar/CAC detection on some hw. This chain can't be used to transmit ++ * or receive frames and it is bounded to a running wdev. ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * switching to a different channel during CAC detection on the selected ++ * radar channel. ++ * The caller is expected to set chandef pointer to NULL in order to ++ * disable offchannel CAC/radar detection. + */ + struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +@@ -4387,6 +4396,8 @@ struct cfg80211_ops { + int (*color_change)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_color_change_settings *params); ++ int (*set_radar_offchan)(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef); + }; + + /* +@@ -7608,6 +7619,20 @@ void cfg80211_cac_event(struct net_devic + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event, gfp_t gfp); + ++/** ++ * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event ++ * @wiphy: the wiphy ++ * @chandef: chandef for the current channel ++ * @event: type of event ++ * ++ * This function is called when a Channel Availability Check (CAC) is finished, ++ * started or aborted by a offchannel dedicated chain. ++ * ++ * Note that this acquires the wiphy lock. ++ */ ++void cfg80211_offchan_cac_event(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event); + + /** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -2608,6 +2608,13 @@ enum nl80211_commands { + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * ++ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for ++ * radar/CAC detection on some hw. This chain can't be used to transmit ++ * or receive frames and it is bounded to a running wdev. ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * switching on a different channel during CAC detection on the selected ++ * radar channel. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3114,6 +3121,8 @@ enum nl80211_attrs { + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + ++ NL80211_ATTR_RADAR_OFFCHAN, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -6013,6 +6022,9 @@ enum nl80211_feature_flags { + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * ++ * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC ++ * detection. ++ * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +@@ -6078,6 +6090,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -543,6 +543,7 @@ use_default_name: + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); ++ INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); + + init_waitqueue_head(&rdev->dev_wait); + +@@ -1205,6 +1206,8 @@ void __cfg80211_leave(struct cfg80211_re + + cfg80211_pmsr_wdev_down(wdev); + ++ cfg80211_stop_offchan_radar_detection(wdev); ++ + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + __cfg80211_leave_ibss(rdev, dev, true); +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -84,6 +84,10 @@ struct cfg80211_registered_device { + + struct delayed_work dfs_update_channels_wk; + ++ struct wireless_dev *offchan_radar_wdev; ++ struct cfg80211_chan_def offchan_radar_chandef; ++ struct delayed_work offchan_cac_work; ++ + /* netlink port which started critical protocol (0 means not started) */ + u32 crit_proto_nlportid; + +@@ -491,6 +495,15 @@ cfg80211_chandef_dfs_cac_time(struct wip + + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + ++int ++cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef); ++ ++void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); ++ ++void cfg80211_offchan_cac_work(struct work_struct *work); ++ + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); + +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -970,3 +970,116 @@ void cfg80211_cac_event(struct net_devic + nl80211_radar_notify(rdev, chandef, event, netdev, gfp); + } + EXPORT_SYMBOL(cfg80211_cac_event); ++ ++void cfg80211_offchan_cac_work(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = to_delayed_work(work); ++ struct cfg80211_registered_device *rdev; ++ ++ rdev = container_of(delayed_work, struct cfg80211_registered_device, ++ offchan_cac_work); ++ cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, ++ NL80211_RADAR_CAC_FINISHED); ++} ++ ++static void ++__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) ++{ ++ struct wiphy *wiphy = &rdev->wiphy; ++ struct net_device *netdev; ++ ++ lockdep_assert_wiphy(&rdev->wiphy); ++ ++ if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) ++ return; ++ ++ switch (event) { ++ case NL80211_RADAR_CAC_FINISHED: ++ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); ++ memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); ++ queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); ++ cfg80211_sched_dfs_chan_update(rdev); ++ wdev = rdev->offchan_radar_wdev; ++ rdev->offchan_radar_wdev = NULL; ++ break; ++ case NL80211_RADAR_CAC_ABORTED: ++ cancel_delayed_work(&rdev->offchan_cac_work); ++ wdev = rdev->offchan_radar_wdev; ++ rdev->offchan_radar_wdev = NULL; ++ break; ++ case NL80211_RADAR_CAC_STARTED: ++ WARN_ON(!wdev); ++ rdev->offchan_radar_wdev = wdev; ++ break; ++ default: ++ return; ++ } ++ ++ netdev = wdev ? wdev->netdev : NULL; ++ nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); ++} ++ ++void cfg80211_offchan_cac_event(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) ++{ ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ ++ wiphy_lock(wiphy); ++ __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); ++ wiphy_unlock(wiphy); ++} ++EXPORT_SYMBOL(cfg80211_offchan_cac_event); ++ ++int ++cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef) ++{ ++ unsigned int cac_time_ms; ++ int err; ++ ++ lockdep_assert_wiphy(&rdev->wiphy); ++ ++ if (!wiphy_ext_feature_isset(&rdev->wiphy, ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN)) ++ return -EOPNOTSUPP; ++ ++ if (rdev->offchan_radar_wdev) ++ return -EBUSY; ++ ++ err = rdev_set_radar_offchan(rdev, chandef); ++ if (err) ++ return err; ++ ++ cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef); ++ if (!cac_time_ms) ++ cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; ++ ++ rdev->offchan_radar_chandef = *chandef; ++ __cfg80211_offchan_cac_event(rdev, wdev, chandef, ++ NL80211_RADAR_CAC_STARTED); ++ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, ++ msecs_to_jiffies(cac_time_ms)); ++ ++ return 0; ++} ++ ++void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) ++{ ++ struct wiphy *wiphy = wdev->wiphy; ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ ++ lockdep_assert_wiphy(wiphy); ++ ++ if (wdev != rdev->offchan_radar_wdev) ++ return; ++ ++ rdev_set_radar_offchan(rdev, NULL); ++ ++ __cfg80211_offchan_cac_event(rdev, NULL, NULL, ++ NL80211_RADAR_CAC_ABORTED); ++} +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -796,6 +796,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_MBSSID_CONFIG] = + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, ++ [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, + }; + + /* policy for the key attributes */ +@@ -9272,12 +9273,6 @@ static int nl80211_start_radar_detection + if (err) + return err; + +- if (netif_carrier_ok(dev)) +- return -EBUSY; +- +- if (wdev->cac_started) +- return -EBUSY; +- + err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); + if (err < 0) + return err; +@@ -9288,6 +9283,16 @@ static int nl80211_start_radar_detection + if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) + return -EINVAL; + ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) ++ return cfg80211_start_offchan_radar_detection(rdev, wdev, ++ &chandef); ++ ++ if (netif_carrier_ok(dev)) ++ return -EBUSY; ++ ++ if (wdev->cac_started) ++ return -EBUSY; ++ + /* CAC start is offloaded to HW and can't be started manually */ + if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) + return -EOPNOTSUPP; +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1381,4 +1381,21 @@ static inline int rdev_color_change(stru + return ret; + } + ++static inline int ++rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct wiphy *wiphy = &rdev->wiphy; ++ int ret; ++ ++ if (!rdev->ops->set_radar_offchan) ++ return -EOPNOTSUPP; ++ ++ trace_rdev_set_radar_offchan(wiphy, chandef); ++ ret = rdev->ops->set_radar_offchan(wiphy, chandef); ++ trace_rdev_return_int(wiphy, ret); ++ ++ return ret; ++} ++ + #endif /* __CFG80211_RDEV_OPS */ +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3643,6 +3643,25 @@ TRACE_EVENT(cfg80211_bss_color_notify, + __entry->color_bitmap) + ); + ++TRACE_EVENT(rdev_set_radar_offchan, ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), ++ ++ TP_ARGS(wiphy, chandef), ++ ++ TP_STRUCT__entry( ++ WIPHY_ENTRY ++ CHAN_DEF_ENTRY ++ ), ++ ++ TP_fast_assign( ++ WIPHY_ASSIGN; ++ CHAN_DEF_ASSIGN(chandef) ++ ), ++ ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ++); ++ + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/315-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch b/package/kernel/mac80211/patches/subsys/315-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch new file mode 100644 index 000000000..b1a1d2c89 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/315-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch @@ -0,0 +1,183 @@ +From: Lorenzo Bianconi +Date: Wed, 27 Oct 2021 11:03:42 +0200 +Subject: [PATCH] cfg80211: move offchan_cac_event to a dedicated work + +In order to make cfg80211_offchan_cac_abort() (renamed from +cfg80211_offchan_cac_event) callable in other contexts and +without so much locking restrictions, make it trigger a new +work instead of operating directly. + +Do some other renames while at it to clarify. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/6145c3d0f30400a568023f67981981d24c7c6133.1635325205.git.lorenzo@kernel.org +[rewrite commit log] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -7620,19 +7620,13 @@ void cfg80211_cac_event(struct net_devic + enum nl80211_radar_event event, gfp_t gfp); + + /** +- * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event ++ * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event + * @wiphy: the wiphy +- * @chandef: chandef for the current channel +- * @event: type of event + * +- * This function is called when a Channel Availability Check (CAC) is finished, +- * started or aborted by a offchannel dedicated chain. +- * +- * Note that this acquires the wiphy lock. ++ * This function is called by the driver when a Channel Availability Check ++ * (CAC) is aborted by a offchannel dedicated chain. + */ +-void cfg80211_offchan_cac_event(struct wiphy *wiphy, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event); ++void cfg80211_offchan_cac_abort(struct wiphy *wiphy); + + /** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -543,7 +543,9 @@ use_default_name: + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); +- INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); ++ INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); ++ INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, ++ cfg80211_offchan_cac_done_wk); + + init_waitqueue_head(&rdev->dev_wait); + +@@ -1053,11 +1055,13 @@ void wiphy_unregister(struct wiphy *wiph + cancel_work_sync(&rdev->conn_work); + flush_work(&rdev->event_work); + cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); ++ cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); + flush_work(&rdev->destroy_work); + flush_work(&rdev->sched_scan_stop_wk); + flush_work(&rdev->propagate_radar_detect_wk); + flush_work(&rdev->propagate_cac_done_wk); + flush_work(&rdev->mgmt_registrations_update_wk); ++ flush_work(&rdev->offchan_cac_abort_wk); + + #ifdef CONFIG_PM + if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -86,7 +86,8 @@ struct cfg80211_registered_device { + + struct wireless_dev *offchan_radar_wdev; + struct cfg80211_chan_def offchan_radar_chandef; +- struct delayed_work offchan_cac_work; ++ struct delayed_work offchan_cac_done_wk; ++ struct work_struct offchan_cac_abort_wk; + + /* netlink port which started critical protocol (0 means not started) */ + u32 crit_proto_nlportid; +@@ -502,7 +503,9 @@ cfg80211_start_offchan_radar_detection(s + + void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); + +-void cfg80211_offchan_cac_work(struct work_struct *work); ++void cfg80211_offchan_cac_done_wk(struct work_struct *work); ++ ++void cfg80211_offchan_cac_abort_wk(struct work_struct *work); + + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -971,17 +971,6 @@ void cfg80211_cac_event(struct net_devic + } + EXPORT_SYMBOL(cfg80211_cac_event); + +-void cfg80211_offchan_cac_work(struct work_struct *work) +-{ +- struct delayed_work *delayed_work = to_delayed_work(work); +- struct cfg80211_registered_device *rdev; +- +- rdev = container_of(delayed_work, struct cfg80211_registered_device, +- offchan_cac_work); +- cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_FINISHED); +-} +- + static void + __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, +@@ -1006,7 +995,7 @@ __cfg80211_offchan_cac_event(struct cfg8 + rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: +- cancel_delayed_work(&rdev->offchan_cac_work); ++ cancel_delayed_work(&rdev->offchan_cac_done_wk); + wdev = rdev->offchan_radar_wdev; + rdev->offchan_radar_wdev = NULL; + break; +@@ -1022,17 +1011,44 @@ __cfg80211_offchan_cac_event(struct cfg8 + nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); + } + +-void cfg80211_offchan_cac_event(struct wiphy *wiphy, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event) ++static void ++cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) ++{ ++ wiphy_lock(&rdev->wiphy); ++ __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); ++ wiphy_unlock(&rdev->wiphy); ++} ++ ++void cfg80211_offchan_cac_done_wk(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = to_delayed_work(work); ++ struct cfg80211_registered_device *rdev; ++ ++ rdev = container_of(delayed_work, struct cfg80211_registered_device, ++ offchan_cac_done_wk); ++ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, ++ NL80211_RADAR_CAC_FINISHED); ++} ++ ++void cfg80211_offchan_cac_abort_wk(struct work_struct *work) ++{ ++ struct cfg80211_registered_device *rdev; ++ ++ rdev = container_of(work, struct cfg80211_registered_device, ++ offchan_cac_abort_wk); ++ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, ++ NL80211_RADAR_CAC_ABORTED); ++} ++ ++void cfg80211_offchan_cac_abort(struct wiphy *wiphy) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + +- wiphy_lock(wiphy); +- __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); +- wiphy_unlock(wiphy); ++ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); + } +-EXPORT_SYMBOL(cfg80211_offchan_cac_event); ++EXPORT_SYMBOL(cfg80211_offchan_cac_abort); + + int + cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, +@@ -1062,7 +1078,7 @@ cfg80211_start_offchan_radar_detection(s + rdev->offchan_radar_chandef = *chandef; + __cfg80211_offchan_cac_event(rdev, wdev, chandef, + NL80211_RADAR_CAC_STARTED); +- queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, ++ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, + msecs_to_jiffies(cac_time_ms)); + + return 0; diff --git a/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch new file mode 100644 index 000000000..362bb885d --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch @@ -0,0 +1,99 @@ +From: Lorenzo Bianconi +Date: Wed, 3 Nov 2021 18:02:35 +0100 +Subject: [PATCH] cfg80211: fix possible NULL pointer dereference in + cfg80211_stop_offchan_radar_detection + +Fix the following NULL pointer dereference in +cfg80211_stop_offchan_radar_detection routine that occurs when hostapd +is stopped during the CAC on offchannel chain: + +Sat Jan 1 0[ 779.567851] ESR = 0x96000005 +0:12:50 2000 dae[ 779.572346] EC = 0x25: DABT (current EL), IL = 32 bits +mon.debug hostap[ 779.578984] SET = 0, FnV = 0 +d: hostapd_inter[ 779.583445] EA = 0, S1PTW = 0 +face_deinit_free[ 779.587936] Data abort info: +: num_bss=1 conf[ 779.592224] ISV = 0, ISS = 0x00000005 +->num_bss=1 +Sat[ 779.597403] CM = 0, WnR = 0 + Jan 1 00:12:50[ 779.601749] user pgtable: 4k pages, 39-bit VAs, pgdp=00000000418b2000 + 2000 daemon.deb[ 779.609601] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 +ug hostapd: host[ 779.619657] Internal error: Oops: 96000005 [#1] SMP +[ 779.770810] CPU: 0 PID: 2202 Comm: hostapd Not tainted 5.10.75 #0 +[ 779.776892] Hardware name: MediaTek MT7622 RFB1 board (DT) +[ 779.782370] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO BTYPE=--) +[ 779.788384] pc : cfg80211_chandef_valid+0x10/0x490 [cfg80211] +[ 779.794128] lr : cfg80211_check_station_change+0x3190/0x3950 [cfg80211] +[ 779.800731] sp : ffffffc01204b7e0 +[ 779.804036] x29: ffffffc01204b7e0 x28: ffffff80039bdc00 +[ 779.809340] x27: 0000000000000000 x26: ffffffc008cb3050 +[ 779.814644] x25: 0000000000000000 x24: 0000000000000002 +[ 779.819948] x23: ffffff8002630000 x22: ffffff8003e748d0 +[ 779.825252] x21: 0000000000000cc0 x20: ffffff8003da4a00 +[ 779.830556] x19: 0000000000000000 x18: ffffff8001bf7ce0 +[ 779.835860] x17: 00000000ffffffff x16: 0000000000000000 +[ 779.841164] x15: 0000000040d59200 x14: 00000000000019c0 +[ 779.846467] x13: 00000000000001c8 x12: 000636b9e9dab1c6 +[ 779.851771] x11: 0000000000000141 x10: 0000000000000820 +[ 779.857076] x9 : 0000000000000000 x8 : ffffff8003d7d038 +[ 779.862380] x7 : 0000000000000000 x6 : ffffff8003d7d038 +[ 779.867683] x5 : 0000000000000e90 x4 : 0000000000000038 +[ 779.872987] x3 : 0000000000000002 x2 : 0000000000000004 +[ 779.878291] x1 : 0000000000000000 x0 : 0000000000000000 +[ 779.883594] Call trace: +[ 779.886039] cfg80211_chandef_valid+0x10/0x490 [cfg80211] +[ 779.891434] cfg80211_check_station_change+0x3190/0x3950 [cfg80211] +[ 779.897697] nl80211_radar_notify+0x138/0x19c [cfg80211] +[ 779.903005] cfg80211_stop_offchan_radar_detection+0x7c/0x8c [cfg80211] +[ 779.909616] __cfg80211_leave+0x2c/0x190 [cfg80211] +[ 779.914490] cfg80211_register_netdevice+0x1c0/0x6d0 [cfg80211] +[ 779.920404] raw_notifier_call_chain+0x50/0x70 +[ 779.924841] call_netdevice_notifiers_info+0x54/0xa0 +[ 779.929796] __dev_close_many+0x40/0x100 +[ 779.933712] __dev_change_flags+0x98/0x190 +[ 779.937800] dev_change_flags+0x20/0x60 +[ 779.941628] devinet_ioctl+0x534/0x6d0 +[ 779.945370] inet_ioctl+0x1bc/0x230 +[ 779.948849] sock_do_ioctl+0x44/0x200 +[ 779.952502] sock_ioctl+0x268/0x4c0 +[ 779.955985] __arm64_sys_ioctl+0xac/0xd0 +[ 779.959900] el0_svc_common.constprop.0+0x60/0x110 +[ 779.964682] do_el0_svc+0x1c/0x24 +[ 779.967990] el0_svc+0x10/0x1c +[ 779.971036] el0_sync_handler+0x9c/0x120 +[ 779.974950] el0_sync+0x148/0x180 +[ 779.978259] Code: a9bc7bfd 910003fd a90153f3 aa0003f3 (f9400000) +[ 779.984344] ---[ end trace 0e67b4f5d6cdeec7 ]--- +[ 779.996400] Kernel panic - not syncing: Oops: Fatal exception +[ 780.002139] SMP: stopping secondary CPUs +[ 780.006057] Kernel Offset: disabled +[ 780.009537] CPU features: 0x0000002,04002004 +[ 780.013796] Memory Limit: none + +Fixes: b8f5facf286b ("cfg80211: implement APIs for dedicated radar detection HW") +Reported-by: Evelyn Tsai +Tested-by: Evelyn Tsai +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/c2e34c065bf8839c5ffa45498ae154021a72a520.1635958796.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -982,6 +982,9 @@ __cfg80211_offchan_cac_event(struct cfg8 + + lockdep_assert_wiphy(&rdev->wiphy); + ++ if (!cfg80211_chandef_valid(chandef)) ++ return; ++ + if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) + return; + +@@ -1096,6 +1099,6 @@ void cfg80211_stop_offchan_radar_detecti + + rdev_set_radar_offchan(rdev, NULL); + +- __cfg80211_offchan_cac_event(rdev, NULL, NULL, ++ __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_ABORTED); + } diff --git a/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch new file mode 100644 index 000000000..df7afefb3 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch @@ -0,0 +1,136 @@ +From: Lorenzo Bianconi +Date: Tue, 16 Nov 2021 12:41:52 +0100 +Subject: [PATCH] cfg80211: schedule offchan_cac_abort_wk in + cfg80211_radar_event + +If necessary schedule offchan_cac_abort_wk work in cfg80211_radar_event +routine adding offchan parameter to cfg80211_radar_event signature. +Rename cfg80211_radar_event in __cfg80211_radar_event and introduce +the two following inline helpers: +- cfg80211_radar_event +- cfg80211_offchan_radar_event +Doing so the drv will not need to run cfg80211_offchan_cac_abort() after +radar detection on the offchannel chain. + +Tested-by: Owen Peng +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/3ff583e021e3343a3ced54a7b09b5e184d1880dc.1637062727.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -7580,15 +7580,33 @@ void cfg80211_cqm_txe_notify(struct net_ + void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); + + /** +- * cfg80211_radar_event - radar detection event ++ * __cfg80211_radar_event - radar detection event + * @wiphy: the wiphy + * @chandef: chandef for the current channel ++ * @offchan: the radar has been detected on the offchannel chain + * @gfp: context flags + * + * This function is called when a radar is detected on the current chanenl. + */ +-void cfg80211_radar_event(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef, gfp_t gfp); ++void __cfg80211_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ bool offchan, gfp_t gfp); ++ ++static inline void ++cfg80211_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp) ++{ ++ __cfg80211_radar_event(wiphy, chandef, false, gfp); ++} ++ ++static inline void ++cfg80211_offchan_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp) ++{ ++ __cfg80211_radar_event(wiphy, chandef, true, gfp); ++} + + /** + * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(s + } + + +-void cfg80211_radar_event(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef, +- gfp_t gfp) ++void __cfg80211_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ bool offchan, gfp_t gfp) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + +- trace_cfg80211_radar_event(wiphy, chandef); ++ trace_cfg80211_radar_event(wiphy, chandef, offchan); + + /* only set the chandef supplied channel to unavailable, in + * case the radar is detected on only one of multiple channels +@@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy * + */ + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); + ++ if (offchan) ++ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); ++ + cfg80211_sched_dfs_chan_update(rdev); + + nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); +@@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy * + memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def)); + queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); + } +-EXPORT_SYMBOL(cfg80211_radar_event); ++EXPORT_SYMBOL(__cfg80211_radar_event); + + void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, +@@ -998,7 +1001,8 @@ __cfg80211_offchan_cac_event(struct cfg8 + rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: +- cancel_delayed_work(&rdev->offchan_cac_done_wk); ++ if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) ++ return; + wdev = rdev->offchan_radar_wdev; + rdev->offchan_radar_wdev = NULL; + break; +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3022,18 +3022,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_n + ); + + TRACE_EVENT(cfg80211_radar_event, +- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), +- TP_ARGS(wiphy, chandef), ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, ++ bool offchan), ++ TP_ARGS(wiphy, chandef, offchan), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_DEF_ENTRY ++ __field(bool, offchan) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_DEF_ASSIGN(chandef); ++ __entry->offchan = offchan; + ), +- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, +- WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d", ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan) + ); + + TRACE_EVENT(cfg80211_cac_event, diff --git a/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch new file mode 100644 index 000000000..567743d84 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch @@ -0,0 +1,220 @@ +From: Lorenzo Bianconi +Date: Tue, 16 Nov 2021 15:03:36 +0100 +Subject: [PATCH] cfg80211: allow continuous radar monitoring on offchannel + chain + +Allow continuous radar detection on the offchannel chain in order +to switch to the monitored channel whenever the underlying driver +reports a radar pattern on the main channel. + +Tested-by: Owen Peng +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/d46217310a49b14ff0e9c002f0a6e0547d70fd2c.1637071350.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -712,6 +712,19 @@ static bool cfg80211_is_wiphy_oper_chan( + return false; + } + ++static bool ++cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, ++ struct ieee80211_channel *channel) ++{ ++ if (!rdev->offchan_radar_wdev) ++ return false; ++ ++ if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) ++ return false; ++ ++ return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); ++} ++ + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan) + { +@@ -728,6 +741,9 @@ bool cfg80211_any_wiphy_oper_chan(struct + + if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan)) + return true; ++ ++ if (cfg80211_offchan_chain_is_active(rdev, chan)) ++ return true; + } + + return false; +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8 + if (!cfg80211_chandef_valid(chandef)) + return; + +- if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) ++ if (!rdev->offchan_radar_wdev) + return; + + switch (event) { +@@ -998,17 +998,13 @@ __cfg80211_offchan_cac_event(struct cfg8 + queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); + cfg80211_sched_dfs_chan_update(rdev); + wdev = rdev->offchan_radar_wdev; +- rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: + if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) + return; + wdev = rdev->offchan_radar_wdev; +- rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_STARTED: +- WARN_ON(!wdev); +- rdev->offchan_radar_wdev = wdev; + break; + default: + return; +@@ -1024,7 +1020,8 @@ cfg80211_offchan_cac_event(struct cfg802 + enum nl80211_radar_event event) + { + wiphy_lock(&rdev->wiphy); +- __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); ++ __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, ++ chandef, event); + wiphy_unlock(&rdev->wiphy); + } + +@@ -1071,7 +1068,13 @@ cfg80211_start_offchan_radar_detection(s + NL80211_EXT_FEATURE_RADAR_OFFCHAN)) + return -EOPNOTSUPP; + +- if (rdev->offchan_radar_wdev) ++ /* Offchannel chain already locked by another wdev */ ++ if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) ++ return -EBUSY; ++ ++ /* CAC already in progress on the offchannel chain */ ++ if (rdev->offchan_radar_wdev == wdev && ++ delayed_work_pending(&rdev->offchan_cac_done_wk)) + return -EBUSY; + + err = rdev_set_radar_offchan(rdev, chandef); +@@ -1083,6 +1086,8 @@ cfg80211_start_offchan_radar_detection(s + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + + rdev->offchan_radar_chandef = *chandef; ++ rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ ++ + __cfg80211_offchan_cac_event(rdev, wdev, chandef, + NL80211_RADAR_CAC_STARTED); + queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, +@@ -1102,6 +1107,7 @@ void cfg80211_stop_offchan_radar_detecti + return; + + rdev_set_radar_offchan(rdev, NULL); ++ rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ + + __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_ABORTED); +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -9263,42 +9263,60 @@ static int nl80211_start_radar_detection + struct cfg80211_chan_def chandef; + enum nl80211_dfs_regions dfs_region; + unsigned int cac_time_ms; +- int err; ++ int err = -EINVAL; ++ ++ flush_delayed_work(&rdev->dfs_update_channels_wk); ++ ++ wiphy_lock(wiphy); + + dfs_region = reg_get_dfs_region(wiphy); + if (dfs_region == NL80211_DFS_UNSET) +- return -EINVAL; ++ goto unlock; + + err = nl80211_parse_chandef(rdev, info, &chandef); + if (err) +- return err; ++ goto unlock; + + err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); + if (err < 0) +- return err; ++ goto unlock; + +- if (err == 0) +- return -EINVAL; ++ if (err == 0) { ++ err = -EINVAL; ++ goto unlock; ++ } + +- if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) +- return -EINVAL; ++ if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) { ++ err = -EINVAL; ++ goto unlock; ++ } + +- if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) +- return cfg80211_start_offchan_radar_detection(rdev, wdev, +- &chandef); ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { ++ err = cfg80211_start_offchan_radar_detection(rdev, wdev, ++ &chandef); ++ goto unlock; ++ } + +- if (netif_carrier_ok(dev)) +- return -EBUSY; ++ if (netif_carrier_ok(dev)) { ++ err = -EBUSY; ++ goto unlock; ++ } + +- if (wdev->cac_started) +- return -EBUSY; ++ if (wdev->cac_started) { ++ err = -EBUSY; ++ goto unlock; ++ } + + /* CAC start is offloaded to HW and can't be started manually */ +- if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) +- return -EOPNOTSUPP; ++ if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) { ++ err = -EOPNOTSUPP; ++ goto unlock; ++ } + +- if (!rdev->ops->start_radar_detection) +- return -EOPNOTSUPP; ++ if (!rdev->ops->start_radar_detection) { ++ err = -EOPNOTSUPP; ++ goto unlock; ++ } + + cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); + if (WARN_ON(!cac_time_ms)) +@@ -9311,6 +9329,9 @@ static int nl80211_start_radar_detection + wdev->cac_start_time = jiffies; + wdev->cac_time_ms = cac_time_ms; + } ++unlock: ++ wiphy_unlock(wiphy); ++ + return err; + } + +@@ -15941,7 +15962,8 @@ static const struct genl_small_ops nl802 + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = nl80211_start_radar_detection, + .flags = GENL_UNS_ADMIN_PERM, +- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP, ++ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | ++ NL80211_FLAG_NO_WIPHY_MTX, + }, + { + .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, diff --git a/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch new file mode 100644 index 000000000..eb80afbcc --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch @@ -0,0 +1,67 @@ +From: Lorenzo Bianconi +Date: Sat, 23 Oct 2021 11:10:51 +0200 +Subject: [PATCH] mac80211: introduce set_radar_offchan callback + +Similar to cfg80211, introduce set_radar_offchan callback in mac80211_ops +in order to configure a dedicated offchannel chain available on some hw +(e.g. mt7915) to perform offchannel CAC detection and avoid tx/rx downtime. + +Tested-by: Evelyn Tsai +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/201110606d4f3a7dfdf31440e351f2e2c375d4f0.1634979655.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3937,6 +3937,14 @@ struct ieee80211_prep_tx_info { + * twt structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. ++ * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * radar/CAC detection on some hw. This chain can't be used to transmit ++ * or receive frames and it is bounded to a running wdev. ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * switching to a different channel during CAC detection on the selected ++ * radar channel. ++ * The caller is expected to set chandef pointer to NULL in order to ++ * disable offchannel CAC/radar detection. + * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to + * resolve a path for hardware flow offloading + */ +@@ -4267,6 +4275,8 @@ struct ieee80211_ops { + struct ieee80211_twt_setup *twt); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); ++ int (*set_radar_offchan)(struct ieee80211_hw *hw, ++ struct cfg80211_chan_def *chandef); + #if LINUX_VERSION_IS_GEQ(5,10,0) + int (*net_fill_forward_path)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4344,6 +4344,18 @@ out: + return err; + } + ++static int ++ieee80211_set_radar_offchan(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct ieee80211_local *local = wiphy_priv(wiphy); ++ ++ if (!local->ops->set_radar_offchan) ++ return -EOPNOTSUPP; ++ ++ return local->ops->set_radar_offchan(&local->hw, chandef); ++} ++ + const struct cfg80211_ops mac80211_config_ops = { + .add_virtual_intf = ieee80211_add_iface, + .del_virtual_intf = ieee80211_del_iface, +@@ -4448,4 +4460,5 @@ const struct cfg80211_ops mac80211_confi + .reset_tid_config = ieee80211_reset_tid_config, + .set_sar_specs = ieee80211_set_sar_specs, + .color_change = ieee80211_color_change, ++ .set_radar_offchan = ieee80211_set_radar_offchan, + }; diff --git a/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch new file mode 100644 index 000000000..c3a4c0db2 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch @@ -0,0 +1,532 @@ +From: Lorenzo Bianconi +Date: Mon, 29 Nov 2021 14:11:24 +0100 +Subject: [PATCH] cfg80211: rename offchannel_chain structs to background_chain + to avoid confusion with ETSI standard + +ETSI standard defines "Offchannel CAC" as: +"Off-Channel CAC is performed by a number of non-continuous checks +spread over a period in time. This period, which is required to +determine the presence of radar signals, is defined as the Off-Channel +CAC Time.. +Minimum Off-Channel CAC Time 6 minutes and Maximum Off-Channel CAC Time +4 hours..". +mac80211 implementation refers to a dedicated hw chain used for continuous +radar monitoring. Rename offchannel_* references to background_* in +order to avoid confusion with ETSI standard. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/4204cc1d648d76b44557981713231e030a3bd991.1638190762.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -4058,14 +4058,14 @@ struct mgmt_frame_regs { + * + * @color_change: Initiate a color change. + * +- * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * @set_radar_background: Configure dedicated offchannel chain available for + * radar/CAC detection on some hw. This chain can't be used to transmit + * or receive frames and it is bounded to a running wdev. +- * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * Background radar/CAC detection allows to avoid the CAC downtime + * switching to a different channel during CAC detection on the selected + * radar channel. + * The caller is expected to set chandef pointer to NULL in order to +- * disable offchannel CAC/radar detection. ++ * disable background CAC/radar detection. + */ + struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +@@ -4396,8 +4396,8 @@ struct cfg80211_ops { + int (*color_change)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_color_change_settings *params); +- int (*set_radar_offchan)(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef); ++ int (*set_radar_background)(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef); + }; + + /* +@@ -7601,9 +7601,9 @@ cfg80211_radar_event(struct wiphy *wiphy + } + + static inline void +-cfg80211_offchan_radar_event(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef, +- gfp_t gfp) ++cfg80211_background_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp) + { + __cfg80211_radar_event(wiphy, chandef, true, gfp); + } +@@ -7638,13 +7638,13 @@ void cfg80211_cac_event(struct net_devic + enum nl80211_radar_event event, gfp_t gfp); + + /** +- * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event ++ * cfg80211_background_cac_abort - Channel Availability Check offchan abort event + * @wiphy: the wiphy + * + * This function is called by the driver when a Channel Availability Check + * (CAC) is aborted by a offchannel dedicated chain. + */ +-void cfg80211_offchan_cac_abort(struct wiphy *wiphy); ++void cfg80211_background_cac_abort(struct wiphy *wiphy); + + /** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3937,14 +3937,14 @@ struct ieee80211_prep_tx_info { + * twt structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. +- * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * @set_radar_background: Configure dedicated offchannel chain available for + * radar/CAC detection on some hw. This chain can't be used to transmit + * or receive frames and it is bounded to a running wdev. +- * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * Background radar/CAC detection allows to avoid the CAC downtime + * switching to a different channel during CAC detection on the selected + * radar channel. + * The caller is expected to set chandef pointer to NULL in order to +- * disable offchannel CAC/radar detection. ++ * disable background CAC/radar detection. + * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to + * resolve a path for hardware flow offloading + */ +@@ -4275,8 +4275,8 @@ struct ieee80211_ops { + struct ieee80211_twt_setup *twt); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); +- int (*set_radar_offchan)(struct ieee80211_hw *hw, +- struct cfg80211_chan_def *chandef); ++ int (*set_radar_background)(struct ieee80211_hw *hw, ++ struct cfg80211_chan_def *chandef); + #if LINUX_VERSION_IS_GEQ(5,10,0) + int (*net_fill_forward_path)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -2608,10 +2608,10 @@ enum nl80211_commands { + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * +- * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for +- * radar/CAC detection on some hw. This chain can't be used to transmit +- * or receive frames and it is bounded to a running wdev. +- * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain ++ * available for radar/CAC detection on some hw. This chain can't be used ++ * to transmit or receive frames and it is bounded to a running wdev. ++ * Background radar/CAC detection allows to avoid the CAC downtime + * switching on a different channel during CAC detection on the selected + * radar channel. + * +@@ -3121,7 +3121,7 @@ enum nl80211_attrs { + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + +- NL80211_ATTR_RADAR_OFFCHAN, ++ NL80211_ATTR_RADAR_BACKGROUND, + + /* add attributes here, update the policy in nl80211.c */ + +@@ -6022,7 +6022,7 @@ enum nl80211_feature_flags { + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * +- * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC ++ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC + * detection. + * + * @NUM_NL80211_EXT_FEATURES: number of extended features. +@@ -6090,7 +6090,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, +- NL80211_EXT_FEATURE_RADAR_OFFCHAN, ++ NL80211_EXT_FEATURE_RADAR_BACKGROUND, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4345,15 +4345,15 @@ out: + } + + static int +-ieee80211_set_radar_offchan(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef) ++ieee80211_set_radar_background(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) + { + struct ieee80211_local *local = wiphy_priv(wiphy); + +- if (!local->ops->set_radar_offchan) ++ if (!local->ops->set_radar_background) + return -EOPNOTSUPP; + +- return local->ops->set_radar_offchan(&local->hw, chandef); ++ return local->ops->set_radar_background(&local->hw, chandef); + } + + const struct cfg80211_ops mac80211_config_ops = { +@@ -4460,5 +4460,5 @@ const struct cfg80211_ops mac80211_confi + .reset_tid_config = ieee80211_reset_tid_config, + .set_sar_specs = ieee80211_set_sar_specs, + .color_change = ieee80211_color_change, +- .set_radar_offchan = ieee80211_set_radar_offchan, ++ .set_radar_background = ieee80211_set_radar_background, + }; +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -716,13 +716,13 @@ static bool + cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, + struct ieee80211_channel *channel) + { +- if (!rdev->offchan_radar_wdev) ++ if (!rdev->background_radar_wdev) + return false; + +- if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) ++ if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) + return false; + +- return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); ++ return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel); + } + + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -543,9 +543,10 @@ use_default_name: + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); +- INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); +- INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, +- cfg80211_offchan_cac_done_wk); ++ INIT_WORK(&rdev->background_cac_abort_wk, ++ cfg80211_background_cac_abort_wk); ++ INIT_DELAYED_WORK(&rdev->background_cac_done_wk, ++ cfg80211_background_cac_done_wk); + + init_waitqueue_head(&rdev->dev_wait); + +@@ -1055,13 +1056,13 @@ void wiphy_unregister(struct wiphy *wiph + cancel_work_sync(&rdev->conn_work); + flush_work(&rdev->event_work); + cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); +- cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); ++ cancel_delayed_work_sync(&rdev->background_cac_done_wk); + flush_work(&rdev->destroy_work); + flush_work(&rdev->sched_scan_stop_wk); + flush_work(&rdev->propagate_radar_detect_wk); + flush_work(&rdev->propagate_cac_done_wk); + flush_work(&rdev->mgmt_registrations_update_wk); +- flush_work(&rdev->offchan_cac_abort_wk); ++ flush_work(&rdev->background_cac_abort_wk); + + #ifdef CONFIG_PM + if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) +@@ -1210,7 +1211,7 @@ void __cfg80211_leave(struct cfg80211_re + + cfg80211_pmsr_wdev_down(wdev); + +- cfg80211_stop_offchan_radar_detection(wdev); ++ cfg80211_stop_background_radar_detection(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -84,10 +84,10 @@ struct cfg80211_registered_device { + + struct delayed_work dfs_update_channels_wk; + +- struct wireless_dev *offchan_radar_wdev; +- struct cfg80211_chan_def offchan_radar_chandef; +- struct delayed_work offchan_cac_done_wk; +- struct work_struct offchan_cac_abort_wk; ++ struct wireless_dev *background_radar_wdev; ++ struct cfg80211_chan_def background_radar_chandef; ++ struct delayed_work background_cac_done_wk; ++ struct work_struct background_cac_abort_wk; + + /* netlink port which started critical protocol (0 means not started) */ + u32 crit_proto_nlportid; +@@ -497,15 +497,15 @@ cfg80211_chandef_dfs_cac_time(struct wip + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + + int +-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, +- struct wireless_dev *wdev, +- struct cfg80211_chan_def *chandef); ++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef); + +-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); ++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev); + +-void cfg80211_offchan_cac_done_wk(struct work_struct *work); ++void cfg80211_background_cac_done_wk(struct work_struct *work); + +-void cfg80211_offchan_cac_abort_wk(struct work_struct *work); ++void cfg80211_background_cac_abort_wk(struct work_struct *work); + + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -920,7 +920,7 @@ void __cfg80211_radar_event(struct wiphy + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); + + if (offchan) +- queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); ++ queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); + + cfg80211_sched_dfs_chan_update(rdev); + +@@ -975,10 +975,10 @@ void cfg80211_cac_event(struct net_devic + EXPORT_SYMBOL(cfg80211_cac_event); + + static void +-__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, +- struct wireless_dev *wdev, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event) ++__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) + { + struct wiphy *wiphy = &rdev->wiphy; + struct net_device *netdev; +@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8 + if (!cfg80211_chandef_valid(chandef)) + return; + +- if (!rdev->offchan_radar_wdev) ++ if (!rdev->background_radar_wdev) + return; + + switch (event) { +@@ -997,12 +997,12 @@ __cfg80211_offchan_cac_event(struct cfg8 + memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); + queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); + cfg80211_sched_dfs_chan_update(rdev); +- wdev = rdev->offchan_radar_wdev; ++ wdev = rdev->background_radar_wdev; + break; + case NL80211_RADAR_CAC_ABORTED: +- if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) ++ if (!cancel_delayed_work(&rdev->background_cac_done_wk)) + return; +- wdev = rdev->offchan_radar_wdev; ++ wdev = rdev->background_radar_wdev; + break; + case NL80211_RADAR_CAC_STARTED: + break; +@@ -1015,49 +1015,49 @@ __cfg80211_offchan_cac_event(struct cfg8 + } + + static void +-cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event) ++cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) + { + wiphy_lock(&rdev->wiphy); +- __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, +- chandef, event); ++ __cfg80211_background_cac_event(rdev, rdev->background_radar_wdev, ++ chandef, event); + wiphy_unlock(&rdev->wiphy); + } + +-void cfg80211_offchan_cac_done_wk(struct work_struct *work) ++void cfg80211_background_cac_done_wk(struct work_struct *work) + { + struct delayed_work *delayed_work = to_delayed_work(work); + struct cfg80211_registered_device *rdev; + + rdev = container_of(delayed_work, struct cfg80211_registered_device, +- offchan_cac_done_wk); +- cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_FINISHED); ++ background_cac_done_wk); ++ cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, ++ NL80211_RADAR_CAC_FINISHED); + } + +-void cfg80211_offchan_cac_abort_wk(struct work_struct *work) ++void cfg80211_background_cac_abort_wk(struct work_struct *work) + { + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, +- offchan_cac_abort_wk); +- cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_ABORTED); ++ background_cac_abort_wk); ++ cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, ++ NL80211_RADAR_CAC_ABORTED); + } + +-void cfg80211_offchan_cac_abort(struct wiphy *wiphy) ++void cfg80211_background_cac_abort(struct wiphy *wiphy) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + +- queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); ++ queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); + } +-EXPORT_SYMBOL(cfg80211_offchan_cac_abort); ++EXPORT_SYMBOL(cfg80211_background_cac_abort); + + int +-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, +- struct wireless_dev *wdev, +- struct cfg80211_chan_def *chandef) ++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef) + { + unsigned int cac_time_ms; + int err; +@@ -1065,19 +1065,19 @@ cfg80211_start_offchan_radar_detection(s + lockdep_assert_wiphy(&rdev->wiphy); + + if (!wiphy_ext_feature_isset(&rdev->wiphy, +- NL80211_EXT_FEATURE_RADAR_OFFCHAN)) ++ NL80211_EXT_FEATURE_RADAR_BACKGROUND)) + return -EOPNOTSUPP; + + /* Offchannel chain already locked by another wdev */ +- if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) ++ if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev) + return -EBUSY; + + /* CAC already in progress on the offchannel chain */ +- if (rdev->offchan_radar_wdev == wdev && +- delayed_work_pending(&rdev->offchan_cac_done_wk)) ++ if (rdev->background_radar_wdev == wdev && ++ delayed_work_pending(&rdev->background_cac_done_wk)) + return -EBUSY; + +- err = rdev_set_radar_offchan(rdev, chandef); ++ err = rdev_set_radar_background(rdev, chandef); + if (err) + return err; + +@@ -1085,30 +1085,31 @@ cfg80211_start_offchan_radar_detection(s + if (!cac_time_ms) + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + +- rdev->offchan_radar_chandef = *chandef; +- rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ ++ rdev->background_radar_chandef = *chandef; ++ rdev->background_radar_wdev = wdev; /* Get offchain ownership */ + +- __cfg80211_offchan_cac_event(rdev, wdev, chandef, +- NL80211_RADAR_CAC_STARTED); +- queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, ++ __cfg80211_background_cac_event(rdev, wdev, chandef, ++ NL80211_RADAR_CAC_STARTED); ++ queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk, + msecs_to_jiffies(cac_time_ms)); + + return 0; + } + +-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) ++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev) + { + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + lockdep_assert_wiphy(wiphy); + +- if (wdev != rdev->offchan_radar_wdev) ++ if (wdev != rdev->background_radar_wdev) + return; + +- rdev_set_radar_offchan(rdev, NULL); +- rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ ++ rdev_set_radar_background(rdev, NULL); ++ rdev->background_radar_wdev = NULL; /* Release offchain ownership */ + +- __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_ABORTED); ++ __cfg80211_background_cac_event(rdev, wdev, ++ &rdev->background_radar_chandef, ++ NL80211_RADAR_CAC_ABORTED); + } +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -796,7 +796,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_MBSSID_CONFIG] = + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, +- [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, ++ [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, + }; + + /* policy for the key attributes */ +@@ -9291,9 +9291,9 @@ static int nl80211_start_radar_detection + goto unlock; + } + +- if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { +- err = cfg80211_start_offchan_radar_detection(rdev, wdev, +- &chandef); ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) { ++ err = cfg80211_start_background_radar_detection(rdev, wdev, ++ &chandef); + goto unlock; + } + +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1382,17 +1382,17 @@ static inline int rdev_color_change(stru + } + + static inline int +-rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, +- struct cfg80211_chan_def *chandef) ++rdev_set_radar_background(struct cfg80211_registered_device *rdev, ++ struct cfg80211_chan_def *chandef) + { + struct wiphy *wiphy = &rdev->wiphy; + int ret; + +- if (!rdev->ops->set_radar_offchan) ++ if (!rdev->ops->set_radar_background) + return -EOPNOTSUPP; + +- trace_rdev_set_radar_offchan(wiphy, chandef); +- ret = rdev->ops->set_radar_offchan(wiphy, chandef); ++ trace_rdev_set_radar_background(wiphy, chandef); ++ ret = rdev->ops->set_radar_background(wiphy, chandef); + trace_rdev_return_int(wiphy, ret); + + return ret; +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3646,7 +3646,7 @@ TRACE_EVENT(cfg80211_bss_color_notify, + __entry->color_bitmap) + ); + +-TRACE_EVENT(rdev_set_radar_offchan, ++TRACE_EVENT(rdev_set_radar_background, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), + + TP_ARGS(wiphy, chandef), diff --git a/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch new file mode 100644 index 000000000..a135e3d1b --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch @@ -0,0 +1,144 @@ +From: John Crispin +Date: Wed, 15 Sep 2021 19:54:35 -0700 +Subject: [PATCH] mac80211: MBSSID support in interface handling + +Configure multiple BSSID and enhanced multi-BSSID advertisement (EMA) +parameters in mac80211 for AP mode. + +For each interface, 'mbssid_tx_vif' points to the transmitting interface of +the MBSSID set. The pointer is set to NULL if MBSSID is disabled. + +Function ieee80211_stop() is modified to always bring down all the +non-transmitting interfaces first and the transmitting interface last. + +Signed-off-by: John Crispin +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Link: https://lore.kernel.org/r/20210916025437.29138-3-alokad@codeaurora.org +[slightly change logic to be more obvious] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1719,6 +1719,7 @@ enum ieee80211_offload_flags { + * write-protected by sdata_lock and local->mtx so holding either is fine + * for read access. + * @color_change_color: the bss color that will be used after the change. ++ * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled. + */ + struct ieee80211_vif { + enum nl80211_iftype type; +@@ -1750,6 +1751,8 @@ struct ieee80211_vif { + bool color_change_active; + u8 color_change_color; + ++ struct ieee80211_vif *mbssid_tx_vif; ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -112,6 +112,36 @@ static int ieee80211_set_mon_options(str + return 0; + } + ++static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata, ++ struct cfg80211_mbssid_config params) ++{ ++ struct ieee80211_sub_if_data *tx_sdata; ++ ++ sdata->vif.mbssid_tx_vif = NULL; ++ sdata->vif.bss_conf.bssid_index = 0; ++ sdata->vif.bss_conf.nontransmitted = false; ++ sdata->vif.bss_conf.ema_ap = false; ++ ++ if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev) ++ return -EINVAL; ++ ++ tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev); ++ if (!tx_sdata) ++ return -EINVAL; ++ ++ if (tx_sdata == sdata) { ++ sdata->vif.mbssid_tx_vif = &sdata->vif; ++ } else { ++ sdata->vif.mbssid_tx_vif = &tx_sdata->vif; ++ sdata->vif.bss_conf.nontransmitted = true; ++ sdata->vif.bss_conf.bssid_index = params.index; ++ } ++ if (params.ema) ++ sdata->vif.bss_conf.ema_ap = true; ++ ++ return 0; ++} ++ + static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, +@@ -1107,6 +1137,14 @@ static int ieee80211_start_ap(struct wip + changed |= BSS_CHANGED_HE_BSS_COLOR; + } + ++ if (sdata->vif.type == NL80211_IFTYPE_AP && ++ params->mbssid_config.tx_wdev) { ++ err = ieee80211_set_ap_mbssid_options(sdata, ++ params->mbssid_config); ++ if (err) ++ return err; ++ } ++ + mutex_lock(&local->mtx); + err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, + IEEE80211_CHANCTX_SHARED); +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -632,17 +632,46 @@ static void ieee80211_do_stop(struct iee + ieee80211_add_virtual_monitor(local); + } + ++static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata; ++ struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif; ++ ++ if (!tx_vif) ++ return; ++ ++ tx_sdata = vif_to_sdata(tx_vif); ++ sdata->vif.mbssid_tx_vif = NULL; ++ ++ list_for_each_entry_safe(non_tx_sdata, tmp_sdata, ++ &tx_sdata->local->interfaces, list) { ++ if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata && ++ non_tx_sdata->vif.mbssid_tx_vif == tx_vif && ++ ieee80211_sdata_running(non_tx_sdata)) { ++ non_tx_sdata->vif.mbssid_tx_vif = NULL; ++ dev_close(non_tx_sdata->wdev.netdev); ++ } ++ } ++ ++ if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) { ++ tx_sdata->vif.mbssid_tx_vif = NULL; ++ dev_close(tx_sdata->wdev.netdev); ++ } ++} ++ + static int ieee80211_stop(struct net_device *dev) + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + +- /* close all dependent VLAN interfaces before locking wiphy */ ++ /* close dependent VLAN and MBSSID interfaces before locking wiphy */ + if (sdata->vif.type == NL80211_IFTYPE_AP) { + struct ieee80211_sub_if_data *vlan, *tmpsdata; + + list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, + u.vlan.list) + dev_close(vlan->dev); ++ ++ ieee80211_stop_mbssid(sdata); + } + + wiphy_lock(sdata->local->hw.wiphy); diff --git a/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch new file mode 100644 index 000000000..fdbcce945 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch @@ -0,0 +1,326 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Feb 2022 12:54:58 +0100 +Subject: [PATCH] mac80211: MBSSID beacon handling in AP mode + +Add new fields in struct beacon_data to store all MBSSID elements. +Generate a beacon template which includes all MBSSID elements. +Move CSA offset to reflect the MBSSID element length. + +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Co-developed-by: John Crispin +Signed-off-by: John Crispin +Signed-off-by: Lorenzo Bianconi +Tested-by: Money Wang +Link: https://lore.kernel.org/r/5322db3c303f431adaf191ab31c45e151dde5465.1645702516.git.lorenzo@kernel.org +[small cleanups] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -4938,12 +4938,14 @@ void ieee80211_report_low_ack(struct iee + * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets + * to countdown counters. This array can contain zero values which + * should be ignored. ++ * @mbssid_off: position of the multiple bssid element + */ + struct ieee80211_mutable_offsets { + u16 tim_offset; + u16 tim_length; + + u16 cntdwn_counter_offs[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; ++ u16 mbssid_off; + }; + + /** +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -989,11 +989,29 @@ static int ieee80211_set_ftm_responder_p + return 0; + } + ++static int ++ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst, ++ struct cfg80211_mbssid_elems *src) ++{ ++ int i, offset = 0; ++ ++ for (i = 0; i < src->cnt; i++) { ++ memcpy(pos + offset, src->elem[i].data, src->elem[i].len); ++ dst->elem[i].len = src->elem[i].len; ++ dst->elem[i].data = pos + offset; ++ offset += dst->elem[i].len; ++ } ++ dst->cnt = src->cnt; ++ ++ return offset; ++} ++ + static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_beacon_data *params, + const struct ieee80211_csa_settings *csa, + const struct ieee80211_color_change_settings *cca) + { ++ struct cfg80211_mbssid_elems *mbssid = NULL; + struct beacon_data *new, *old; + int new_head_len, new_tail_len; + int size, err; +@@ -1021,6 +1039,17 @@ static int ieee80211_assign_beacon(struc + + size = sizeof(*new) + new_head_len + new_tail_len; + ++ /* new or old multiple BSSID elements? */ ++ if (params->mbssid_ies) { ++ mbssid = params->mbssid_ies; ++ size += struct_size(new->mbssid_ies, elem, mbssid->cnt); ++ size += ieee80211_get_mbssid_beacon_len(mbssid); ++ } else if (old && old->mbssid_ies) { ++ mbssid = old->mbssid_ies; ++ size += struct_size(new->mbssid_ies, elem, mbssid->cnt); ++ size += ieee80211_get_mbssid_beacon_len(mbssid); ++ } ++ + new = kzalloc(size, GFP_KERNEL); + if (!new) + return -ENOMEM; +@@ -1029,12 +1058,20 @@ static int ieee80211_assign_beacon(struc + + /* + * pointers go into the block we allocated, +- * memory is | beacon_data | head | tail | ++ * memory is | beacon_data | head | tail | mbssid_ies + */ + new->head = ((u8 *) new) + sizeof(*new); + new->tail = new->head + new_head_len; + new->head_len = new_head_len; + new->tail_len = new_tail_len; ++ /* copy in optional mbssid_ies */ ++ if (mbssid) { ++ u8 *pos = new->tail + new->tail_len; ++ ++ new->mbssid_ies = (void *)pos; ++ pos += struct_size(new->mbssid_ies, elem, mbssid->cnt); ++ ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid); ++ } + + if (csa) { + new->cntdwn_current_counter = csa->count; +@@ -1332,8 +1369,11 @@ static int ieee80211_stop_ap(struct wiph + + mutex_unlock(&local->mtx); + +- kfree(sdata->u.ap.next_beacon); +- sdata->u.ap.next_beacon = NULL; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + /* turn off carrier for this interface and dependent VLANs */ + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) +@@ -3126,12 +3166,24 @@ cfg80211_beacon_dup(struct cfg80211_beac + + len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len + + beacon->proberesp_ies_len + beacon->assocresp_ies_len + +- beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len; ++ beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len + ++ ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); + + new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL); + if (!new_beacon) + return NULL; + ++ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) { ++ new_beacon->mbssid_ies = ++ kzalloc(struct_size(new_beacon->mbssid_ies, ++ elem, beacon->mbssid_ies->cnt), ++ GFP_KERNEL); ++ if (!new_beacon->mbssid_ies) { ++ kfree(new_beacon); ++ return NULL; ++ } ++ } ++ + pos = (u8 *)(new_beacon + 1); + if (beacon->head_len) { + new_beacon->head_len = beacon->head_len; +@@ -3169,6 +3221,10 @@ cfg80211_beacon_dup(struct cfg80211_beac + memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); + pos += beacon->probe_resp_len; + } ++ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) ++ pos += ieee80211_copy_mbssid_beacon(pos, ++ new_beacon->mbssid_ies, ++ beacon->mbssid_ies); + + /* might copy -1, meaning no changes requested */ + new_beacon->ftm_responder = beacon->ftm_responder; +@@ -3206,8 +3262,11 @@ static int ieee80211_set_after_csa_beaco + case NL80211_IFTYPE_AP: + err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, + NULL, NULL); +- kfree(sdata->u.ap.next_beacon); +- sdata->u.ap.next_beacon = NULL; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + if (err < 0) + return err; +@@ -3362,8 +3421,12 @@ static int ieee80211_set_csa_beacon(stru + if ((params->n_counter_offsets_beacon > + IEEE80211_MAX_CNTDWN_COUNTERS_NUM) || + (params->n_counter_offsets_presp > +- IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) ++ IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; + return -EINVAL; ++ } + + csa.counter_offsets_beacon = params->counter_offsets_beacon; + csa.counter_offsets_presp = params->counter_offsets_presp; +@@ -3373,7 +3436,9 @@ static int ieee80211_set_csa_beacon(stru + + err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa, NULL); + if (err < 0) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); + kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; + return err; + } + *changed |= err; +@@ -3463,8 +3528,11 @@ static int ieee80211_set_csa_beacon(stru + static void ieee80211_color_change_abort(struct ieee80211_sub_if_data *sdata) + { + sdata->vif.color_change_active = false; +- kfree(sdata->u.ap.next_beacon); +- sdata->u.ap.next_beacon = NULL; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + cfg80211_color_change_aborted_notify(sdata->dev); + } +@@ -4202,8 +4270,11 @@ ieee80211_set_after_color_change_beacon( + + ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, + NULL, NULL); +- kfree(sdata->u.ap.next_beacon); +- sdata->u.ap.next_beacon = NULL; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + if (ret < 0) + return ret; +@@ -4246,7 +4317,11 @@ ieee80211_set_color_change_beacon(struct + err = ieee80211_assign_beacon(sdata, ¶ms->beacon_color_change, + NULL, &color_change); + if (err < 0) { +- kfree(sdata->u.ap.next_beacon); ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + return err; + } + *changed |= err; +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -261,6 +261,7 @@ struct beacon_data { + struct ieee80211_meshconf_ie *meshconf; + u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; + u8 cntdwn_current_counter; ++ struct cfg80211_mbssid_elems *mbssid_ies; + struct rcu_head rcu_head; + }; + +@@ -1083,6 +1084,20 @@ ieee80211_vif_get_shift(struct ieee80211 + return shift; + } + ++static inline int ++ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems) ++{ ++ int i, len = 0; ++ ++ if (!elems) ++ return 0; ++ ++ for (i = 0; i < elems->cnt; i++) ++ len += elems->elem[i].len; ++ ++ return len; ++} ++ + enum { + IEEE80211_RX_MSG = 1, + IEEE80211_TX_STATUS_MSG = 2, +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -5041,6 +5041,19 @@ ieee80211_beacon_get_finish(struct ieee8 + IEEE80211_TX_CTL_FIRST_FRAGMENT; + } + ++static void ++ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon) ++{ ++ int i; ++ ++ if (!beacon->mbssid_ies) ++ return; ++ ++ for (i = 0; i < beacon->mbssid_ies->cnt; i++) ++ skb_put_data(skb, beacon->mbssid_ies->elem[i].data, ++ beacon->mbssid_ies->elem[i].len); ++} ++ + static struct sk_buff * + ieee80211_beacon_get_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -5054,6 +5067,7 @@ ieee80211_beacon_get_ap(struct ieee80211 + struct ieee80211_if_ap *ap = &sdata->u.ap; + struct sk_buff *skb = NULL; + u16 csa_off_base = 0; ++ int mbssid_len; + + if (beacon->cntdwn_counter_offsets[0]) { + if (!is_template) +@@ -5063,11 +5077,12 @@ ieee80211_beacon_get_ap(struct ieee80211 + } + + /* headroom, head length, +- * tail length and maximum TIM length ++ * tail length, maximum TIM length and multiple BSSID length + */ ++ mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); + skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + + beacon->tail_len + 256 + +- local->hw.extra_beacon_tailroom); ++ local->hw.extra_beacon_tailroom + mbssid_len); + if (!skb) + return NULL; + +@@ -5081,6 +5096,11 @@ ieee80211_beacon_get_ap(struct ieee80211 + offs->tim_length = skb->len - beacon->head_len; + offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; + ++ if (mbssid_len) { ++ ieee80211_beacon_add_mbssid(skb, beacon); ++ offs->mbssid_off = skb->len - mbssid_len; ++ } ++ + /* for AP the csa offsets are from tail */ + csa_off_base = skb->len; + } diff --git a/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch new file mode 100644 index 000000000..38b0de180 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch @@ -0,0 +1,52 @@ +From: John Crispin +Date: Thu, 24 Feb 2022 12:54:59 +0100 +Subject: [PATCH] mac80211: MBSSID channel switch + +Trigger ieee80211_csa_finish() on the non-transmitting interfaces +when channel switch concludes on the transmitting interface. + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Signed-off-by: John Crispin +Link: https://lore.kernel.org/r/6fde4d7f9fa387494f46a7aa4a584478dcda06f1.1645702516.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3247,9 +3247,31 @@ cfg80211_beacon_dup(struct cfg80211_beac + void ieee80211_csa_finish(struct ieee80211_vif *vif) + { + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_local *local = sdata->local; + +- ieee80211_queue_work(&sdata->local->hw, +- &sdata->csa_finalize_work); ++ rcu_read_lock(); ++ ++ if (vif->mbssid_tx_vif == vif) { ++ /* Trigger ieee80211_csa_finish() on the non-transmitting ++ * interfaces when channel switch is received on ++ * transmitting interface ++ */ ++ struct ieee80211_sub_if_data *iter; ++ ++ list_for_each_entry_rcu(iter, &local->interfaces, list) { ++ if (!ieee80211_sdata_running(iter)) ++ continue; ++ ++ if (iter == sdata || iter->vif.mbssid_tx_vif != vif) ++ continue; ++ ++ ieee80211_queue_work(&iter->local->hw, ++ &iter->csa_finalize_work); ++ } ++ } ++ ieee80211_queue_work(&local->hw, &sdata->csa_finalize_work); ++ ++ rcu_read_unlock(); + } + EXPORT_SYMBOL(ieee80211_csa_finish); + diff --git a/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch new file mode 100644 index 000000000..195556860 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch @@ -0,0 +1,25 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Feb 2022 12:55:00 +0100 +Subject: [PATCH] mac80211: update bssid_indicator in + ieee80211_assign_beacon + +Update bssid_indicator in ieee80211_bss_conf according to the +number of bssid in the set. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/f92317e002fca9933f05a445fcefb4f53291d601.1645702516.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1071,6 +1071,9 @@ static int ieee80211_assign_beacon(struc + new->mbssid_ies = (void *)pos; + pos += struct_size(new->mbssid_ies, elem, mbssid->cnt); + ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid); ++ /* update bssid_indicator */ ++ sdata->vif.bss_conf.bssid_indicator = ++ ilog2(__roundup_pow_of_two(mbssid->cnt + 1)); + } + + if (csa) { diff --git a/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch b/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch new file mode 100644 index 000000000..f0150ddef --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch @@ -0,0 +1,38 @@ +From: Felix Fietkau +Date: Sat, 26 Mar 2022 23:58:35 +0100 +Subject: [PATCH] mac80211: do not wake queues on a vif that is being stopped + +When a vif is being removed and sdata->bss is cleared, __ieee80211_wake_txqs +can still be called on it, which crashes as soon as sdata->bss is being +dereferenced. +To fix this properly, check for SDATA_STATE_RUNNING before waking queues, +and take the fq lock when setting it (to ensure that __ieee80211_wake_txqs +observes the change when running on a different CPU + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -377,7 +377,9 @@ static void ieee80211_do_stop(struct iee + bool cancel_scan; + struct cfg80211_nan_func *func; + ++ spin_lock_bh(&local->fq.lock); + clear_bit(SDATA_STATE_RUNNING, &sdata->state); ++ spin_unlock_bh(&local->fq.lock); + + cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; + if (cancel_scan) +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct + local_bh_disable(); + spin_lock(&fq->lock); + ++ if (!test_bit(SDATA_STATE_RUNNING, &sdata->state)) ++ goto out; ++ + if (sdata->vif.type == NL80211_IFTYPE_AP) + ps = &sdata->bss->ps; + diff --git a/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch new file mode 100644 index 000000000..1a66aa8c0 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch @@ -0,0 +1,1249 @@ +From: Felix Fietkau +Date: Sun, 19 Jun 2022 23:13:05 +0200 +Subject: [PATCH] mac80211: switch airtime fairness back to deficit round-robin + scheduling + +This reverts commits 6a789ba679d652587532cec2a0e0274fda172f3b and +2433647bc8d983a543e7d31b41ca2de1c7e2c198. + +The virtual time scheduler code has a number of issues: +- queues slowed down by hardware/firmware powersave handling were not properly + handled. +- on ath10k in push-pull mode, tx queues that the driver tries to pull from + were starved, causing excessive latency +- delay between tx enqueue and reported airtime use were causing excessively + bursty tx behavior + +The bursty behavior may also be present on the round-robin scheduler, but there +it is much easier to fix without introducing additional regressions + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6666,6 +6666,9 @@ static inline void ieee80211_txq_schedul + { + } + ++void __ieee80211_schedule_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq, bool force); ++ + /** + * ieee80211_schedule_txq - schedule a TXQ for transmission + * +@@ -6678,7 +6681,11 @@ static inline void ieee80211_txq_schedul + * The driver may call this function if it has buffered packets for + * this TXQ internally. + */ +-void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); ++static inline void ++ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) ++{ ++ __ieee80211_schedule_txq(hw, txq, true); ++} + + /** + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() +@@ -6690,8 +6697,12 @@ void ieee80211_schedule_txq(struct ieee8 + * The driver may set force=true if it has buffered packets for this TXQ + * internally. + */ +-void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, +- bool force); ++static inline void ++ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, ++ bool force) ++{ ++ __ieee80211_schedule_txq(hw, txq, force); ++} + + /** + * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1554,38 +1554,6 @@ static void sta_apply_mesh_params(struct + #endif + } + +-static void sta_apply_airtime_params(struct ieee80211_local *local, +- struct sta_info *sta, +- struct station_parameters *params) +-{ +- u8 ac; +- +- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- struct airtime_sched_info *air_sched = &local->airtime[ac]; +- struct airtime_info *air_info = &sta->airtime[ac]; +- struct txq_info *txqi; +- u8 tid; +- +- spin_lock_bh(&air_sched->lock); +- for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { +- if (air_info->weight == params->airtime_weight || +- !sta->sta.txq[tid] || +- ac != ieee80211_ac_from_tid(tid)) +- continue; +- +- airtime_weight_set(air_info, params->airtime_weight); +- +- txqi = to_txq_info(sta->sta.txq[tid]); +- if (RB_EMPTY_NODE(&txqi->schedule_order)) +- continue; +- +- ieee80211_update_airtime_weight(local, air_sched, +- 0, true); +- } +- spin_unlock_bh(&air_sched->lock); +- } +-} +- + static int sta_apply_parameters(struct ieee80211_local *local, + struct sta_info *sta, + struct station_parameters *params) +@@ -1773,8 +1741,7 @@ static int sta_apply_parameters(struct i + sta_apply_mesh_params(local, sta, params); + + if (params->airtime_weight) +- sta_apply_airtime_params(local, sta, params); +- ++ sta->airtime_weight = params->airtime_weight; + + /* set the STA state after all sta info from usermode has been set */ + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) || +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct + "VI %u %u\n" + "BE %u %u\n" + "BK %u %u\n", +- local->airtime[IEEE80211_AC_VO].aql_txq_limit_low, +- local->airtime[IEEE80211_AC_VO].aql_txq_limit_high, +- local->airtime[IEEE80211_AC_VI].aql_txq_limit_low, +- local->airtime[IEEE80211_AC_VI].aql_txq_limit_high, +- local->airtime[IEEE80211_AC_BE].aql_txq_limit_low, +- local->airtime[IEEE80211_AC_BE].aql_txq_limit_high, +- local->airtime[IEEE80211_AC_BK].aql_txq_limit_low, +- local->airtime[IEEE80211_AC_BK].aql_txq_limit_high); ++ local->aql_txq_limit_low[IEEE80211_AC_VO], ++ local->aql_txq_limit_high[IEEE80211_AC_VO], ++ local->aql_txq_limit_low[IEEE80211_AC_VI], ++ local->aql_txq_limit_high[IEEE80211_AC_VI], ++ local->aql_txq_limit_low[IEEE80211_AC_BE], ++ local->aql_txq_limit_high[IEEE80211_AC_BE], ++ local->aql_txq_limit_low[IEEE80211_AC_BK], ++ local->aql_txq_limit_high[IEEE80211_AC_BK]); + return simple_read_from_buffer(user_buf, count, ppos, + buf, len); + } +@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struc + if (ac >= IEEE80211_NUM_ACS) + return -EINVAL; + +- q_limit_low_old = local->airtime[ac].aql_txq_limit_low; +- q_limit_high_old = local->airtime[ac].aql_txq_limit_high; ++ q_limit_low_old = local->aql_txq_limit_low[ac]; ++ q_limit_high_old = local->aql_txq_limit_high[ac]; + +- local->airtime[ac].aql_txq_limit_low = q_limit_low; +- local->airtime[ac].aql_txq_limit_high = q_limit_high; ++ local->aql_txq_limit_low[ac] = q_limit_low; ++ local->aql_txq_limit_high[ac] = q_limit_high; + + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { +@@ -382,46 +382,6 @@ static const struct file_operations forc + .llseek = default_llseek, + }; + +-static ssize_t airtime_read(struct file *file, +- char __user *user_buf, +- size_t count, +- loff_t *ppos) +-{ +- struct ieee80211_local *local = file->private_data; +- char buf[200]; +- u64 v_t[IEEE80211_NUM_ACS]; +- u64 wt[IEEE80211_NUM_ACS]; +- int len = 0, ac; +- +- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->airtime[ac].lock); +- v_t[ac] = local->airtime[ac].v_t; +- wt[ac] = local->airtime[ac].weight_sum; +- spin_unlock_bh(&local->airtime[ac].lock); +- } +- len = scnprintf(buf, sizeof(buf), +- "\tVO VI BE BK\n" +- "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n" +- "Weight\t%-10llu %-10llu %-10llu %-10llu\n", +- v_t[0], +- v_t[1], +- v_t[2], +- v_t[3], +- wt[0], +- wt[1], +- wt[2], +- wt[3]); +- +- return simple_read_from_buffer(user_buf, count, ppos, +- buf, len); +-} +- +-static const struct file_operations airtime_ops = { +- .read = airtime_read, +- .open = simple_open, +- .llseek = default_llseek, +-}; +- + #ifdef CONFIG_PM + static ssize_t reset_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +@@ -672,11 +632,7 @@ void debugfs_hw_add(struct ieee80211_loc + if (local->ops->wake_tx_queue) + DEBUGFS_ADD_MODE(aqm, 0600); + +- if (wiphy_ext_feature_isset(local->hw.wiphy, +- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { +- DEBUGFS_ADD_MODE(airtime, 0600); +- DEBUGFS_ADD_MODE(airtime_flags, 0600); +- } ++ DEBUGFS_ADD_MODE(airtime_flags, 0600); + + DEBUGFS_ADD(aql_txq_limit); + debugfs_create_u32("aql_threshold", 0600, +--- a/net/mac80211/debugfs_netdev.c ++++ b/net/mac80211/debugfs_netdev.c +@@ -512,34 +512,6 @@ static ssize_t ieee80211_if_fmt_aqm( + } + IEEE80211_IF_FILE_R(aqm); + +-static ssize_t ieee80211_if_fmt_airtime( +- const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) +-{ +- struct ieee80211_local *local = sdata->local; +- struct ieee80211_txq *txq = sdata->vif.txq; +- struct airtime_info *air_info; +- int len; +- +- if (!txq) +- return 0; +- +- spin_lock_bh(&local->airtime[txq->ac].lock); +- air_info = to_airtime_info(txq); +- len = scnprintf(buf, +- buflen, +- "RX: %llu us\nTX: %llu us\nWeight: %u\n" +- "Virt-T: %lld us\n", +- air_info->rx_airtime, +- air_info->tx_airtime, +- air_info->weight, +- air_info->v_t); +- spin_unlock_bh(&local->airtime[txq->ac].lock); +- +- return len; +-} +- +-IEEE80211_IF_FILE_R(airtime); +- + IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX); + + /* IBSS attributes */ +@@ -685,10 +657,8 @@ static void add_common_files(struct ieee + + if (sdata->local->ops->wake_tx_queue && + sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && +- sdata->vif.type != NL80211_IFTYPE_NAN) { ++ sdata->vif.type != NL80211_IFTYPE_NAN) + DEBUGFS_ADD(aqm); +- DEBUGFS_ADD(airtime); +- } + } + + static void add_sta_files(struct ieee80211_sub_if_data *sdata) +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f + size_t bufsz = 400; + char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; + u64 rx_airtime = 0, tx_airtime = 0; +- u64 v_t[IEEE80211_NUM_ACS]; ++ s64 deficit[IEEE80211_NUM_ACS]; + ssize_t rv; + int ac; + +@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct f + return -ENOMEM; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->airtime[ac].lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + rx_airtime += sta->airtime[ac].rx_airtime; + tx_airtime += sta->airtime[ac].tx_airtime; +- v_t[ac] = sta->airtime[ac].v_t; +- spin_unlock_bh(&local->airtime[ac].lock); ++ deficit[ac] = sta->airtime[ac].deficit; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + + p += scnprintf(p, bufsz + buf - p, + "RX: %llu us\nTX: %llu us\nWeight: %u\n" +- "Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", +- rx_airtime, tx_airtime, sta->airtime[0].weight, +- v_t[0], v_t[1], v_t[2], v_t[3]); ++ "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", ++ rx_airtime, tx_airtime, sta->airtime_weight, ++ deficit[0], deficit[1], deficit[2], deficit[3]); + + rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); + kfree(buf); +@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct + int ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->airtime[ac].lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + sta->airtime[ac].rx_airtime = 0; + sta->airtime[ac].tx_airtime = 0; +- sta->airtime[ac].v_t = 0; +- spin_unlock_bh(&local->airtime[ac].lock); ++ sta->airtime[ac].deficit = sta->airtime_weight; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + + return count; +@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file + return -ENOMEM; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->airtime[ac].lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + q_limit_l[ac] = sta->airtime[ac].aql_limit_low; + q_limit_h[ac] = sta->airtime[ac].aql_limit_high; +- spin_unlock_bh(&local->airtime[ac].lock); ++ spin_unlock_bh(&local->active_txq_lock[ac]); + q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); + } + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -863,16 +863,20 @@ enum txq_info_flags { + * @def_flow: used as a fallback flow when a packet destined to @tin hashes to + * a fq_flow which is already owned by a different tin + * @def_cvars: codel vars for @def_flow +- * @schedule_order: used with ieee80211_local->active_txqs + * @frags: used to keep fragments created after dequeue ++ * @schedule_order: used with ieee80211_local->active_txqs ++ * @schedule_round: counter to prevent infinite loops on TXQ scheduling + */ + struct txq_info { + struct fq_tin tin; + struct codel_vars def_cvars; + struct codel_stats cstats; +- struct rb_node schedule_order; ++ ++ u16 schedule_round; ++ struct list_head schedule_order; + + struct sk_buff_head frags; ++ + unsigned long flags; + + /* keep last! */ +@@ -949,8 +953,6 @@ struct ieee80211_sub_if_data { + struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; + struct mac80211_qos_map __rcu *qos_map; + +- struct airtime_info airtime[IEEE80211_NUM_ACS]; +- + struct work_struct csa_finalize_work; + bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + struct cfg80211_chan_def csa_chandef; +@@ -1180,44 +1182,6 @@ enum mac80211_scan_state { + SCAN_ABORT, + }; + +-/** +- * struct airtime_sched_info - state used for airtime scheduling and AQL +- * +- * @lock: spinlock that protects all the fields in this struct +- * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time +- * @schedule_pos: the current position maintained while a driver walks the tree +- * with ieee80211_next_txq() +- * @active_list: list of struct airtime_info structs that were active within +- * the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute +- * weight_sum +- * @last_weight_update: used for rate limiting walking active_list +- * @last_schedule_time: tracks the last time a transmission was scheduled; used +- * for catching up v_t if no stations are eligible for +- * transmission. +- * @v_t: global virtual time; queues with v_t < this are eligible for +- * transmission +- * @weight_sum: total sum of all active stations used for dividing airtime +- * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast +- * path - see comment above +- * IEEE80211_RECIPROCAL_DIVISOR_64) +- * @aql_txq_limit_low: AQL limit when total outstanding airtime +- * is < IEEE80211_AQL_THRESHOLD +- * @aql_txq_limit_high: AQL limit when total outstanding airtime +- * is > IEEE80211_AQL_THRESHOLD +- */ +-struct airtime_sched_info { +- spinlock_t lock; +- struct rb_root_cached active_txqs; +- struct rb_node *schedule_pos; +- struct list_head active_list; +- u64 last_weight_update; +- u64 last_schedule_activity; +- u64 v_t; +- u64 weight_sum; +- u64 weight_sum_reciprocal; +- u32 aql_txq_limit_low; +- u32 aql_txq_limit_high; +-}; + DECLARE_STATIC_KEY_FALSE(aql_disable); + + struct ieee80211_local { +@@ -1231,8 +1195,13 @@ struct ieee80211_local { + struct codel_params cparams; + + /* protects active_txqs and txqi->schedule_order */ +- struct airtime_sched_info airtime[IEEE80211_NUM_ACS]; ++ spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; ++ struct list_head active_txqs[IEEE80211_NUM_ACS]; ++ u16 schedule_round[IEEE80211_NUM_ACS]; ++ + u16 airtime_flags; ++ u32 aql_txq_limit_low[IEEE80211_NUM_ACS]; ++ u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; + u32 aql_threshold; + atomic_t aql_total_pending_airtime; + +@@ -1649,125 +1618,6 @@ static inline bool txq_has_queue(struct + return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets); + } + +-static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq) +-{ +- struct ieee80211_sub_if_data *sdata; +- struct sta_info *sta; +- +- if (txq->sta) { +- sta = container_of(txq->sta, struct sta_info, sta); +- return &sta->airtime[txq->ac]; +- } +- +- sdata = vif_to_sdata(txq->vif); +- return &sdata->airtime[txq->ac]; +-} +- +-/* To avoid divisions in the fast path, we keep pre-computed reciprocals for +- * airtime weight calculations. There are two different weights to keep track +- * of: The per-station weight and the sum of weights per phy. +- * +- * For the per-station weights (kept in airtime_info below), we use 32-bit +- * reciprocals with a devisor of 2^19. This lets us keep the multiplications and +- * divisions for the station weights as 32-bit operations at the cost of a bit +- * of rounding error for high weights; but the choice of divisor keeps rounding +- * errors <10% for weights <2^15, assuming no more than 8ms of airtime is +- * reported at a time. +- * +- * For the per-phy sum of weights the values can get higher, so we use 64-bit +- * operations for those with a 32-bit divisor, which should avoid any +- * significant rounding errors. +- */ +-#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL +-#define IEEE80211_RECIPROCAL_SHIFT_64 32 +-#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U +-#define IEEE80211_RECIPROCAL_SHIFT_32 19 +- +-static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight) +-{ +- if (air_info->weight == weight) +- return; +- +- air_info->weight = weight; +- if (weight) { +- air_info->weight_reciprocal = +- IEEE80211_RECIPROCAL_DIVISOR_32 / weight; +- } else { +- air_info->weight_reciprocal = 0; +- } +-} +- +-static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched, +- int weight_sum) +-{ +- if (air_sched->weight_sum == weight_sum) +- return; +- +- air_sched->weight_sum = weight_sum; +- if (air_sched->weight_sum) { +- air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64; +- do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum); +- } else { +- air_sched->weight_sum_reciprocal = 0; +- } +-} +- +-/* A problem when trying to enforce airtime fairness is that we want to divide +- * the airtime between the currently *active* stations. However, basing this on +- * the instantaneous queue state of stations doesn't work, as queues tend to +- * oscillate very quickly between empty and occupied, leading to the scheduler +- * thinking only a single station is active when deciding whether to allow +- * transmission (and thus not throttling correctly). +- * +- * To fix this we use a timer-based notion of activity: a station is considered +- * active if it has been scheduled within the last 100 ms; we keep a separate +- * list of all the stations considered active in this manner, and lazily update +- * the total weight of active stations from this list (filtering the stations in +- * the list by their 'last active' time). +- * +- * We add one additional safeguard to guard against stations that manage to get +- * scheduled every 100 ms but don't transmit a lot of data, and thus don't use +- * up any airtime. Such stations would be able to get priority for an extended +- * period of time if they do start transmitting at full capacity again, and so +- * we add an explicit maximum for how far behind a station is allowed to fall in +- * the virtual airtime domain. This limit is set to a relatively high value of +- * 20 ms because the main mechanism for catching up idle stations is the active +- * state as described above; i.e., the hard limit should only be hit in +- * pathological cases. +- */ +-#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC) +-#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */ +- +-static inline bool airtime_is_active(struct airtime_info *air_info, u64 now) +-{ +- return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION; +-} +- +-static inline void airtime_set_active(struct airtime_sched_info *air_sched, +- struct airtime_info *air_info, u64 now) +-{ +- air_info->last_scheduled = now; +- air_sched->last_schedule_activity = now; +- list_move_tail(&air_info->list, &air_sched->active_list); +-} +- +-static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched, +- u64 v_t, u64 now) +-{ +- air_sched->v_t = v_t; +- return true; +-} +- +-static inline void init_airtime_info(struct airtime_info *air_info, +- struct airtime_sched_info *air_sched) +-{ +- atomic_set(&air_info->aql_tx_pending, 0); +- air_info->aql_limit_low = air_sched->aql_txq_limit_low; +- air_info->aql_limit_high = air_sched->aql_txq_limit_high; +- airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT); +- INIT_LIST_HEAD(&air_info->list); +-} +- + static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) + { + return ether_addr_equal(raddr, addr) || +@@ -2013,14 +1863,6 @@ int ieee80211_tx_control_port(struct wip + u64 *cookie); + int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len); +-void ieee80211_resort_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq); +-void ieee80211_unschedule_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq, +- bool purge); +-void ieee80211_update_airtime_weight(struct ieee80211_local *local, +- struct airtime_sched_info *air_sched, +- u64 now, bool force); + + /* HT */ + void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -2192,9 +2192,6 @@ int ieee80211_if_add(struct ieee80211_lo + } + } + +- for (i = 0; i < IEEE80211_NUM_ACS; i++) +- init_airtime_info(&sdata->airtime[i], &local->airtime[i]); +- + ieee80211_set_default_queues(sdata); + + sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -707,13 +707,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + spin_lock_init(&local->queue_stop_reason_lock); + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { +- struct airtime_sched_info *air_sched = &local->airtime[i]; +- +- air_sched->active_txqs = RB_ROOT_CACHED; +- INIT_LIST_HEAD(&air_sched->active_list); +- spin_lock_init(&air_sched->lock); +- air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; +- air_sched->aql_txq_limit_high = ++ INIT_LIST_HEAD(&local->active_txqs[i]); ++ spin_lock_init(&local->active_txq_lock[i]); ++ local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; ++ local->aql_txq_limit_high[i] = + IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; + } + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1584,8 +1584,12 @@ static void sta_ps_start(struct sta_info + + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { + struct ieee80211_txq *txq = sta->sta.txq[tid]; ++ struct txq_info *txqi = to_txq_info(txq); + +- ieee80211_unschedule_txq(&local->hw, txq, false); ++ spin_lock(&local->active_txq_lock[txq->ac]); ++ if (!list_empty(&txqi->schedule_order)) ++ list_del_init(&txqi->schedule_order); ++ spin_unlock(&local->active_txq_lock[txq->ac]); + + if (txq_has_queue(txq)) + set_bit(tid, &sta->txq_buffered_tids); +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -426,11 +426,15 @@ struct sta_info *sta_info_alloc(struct i + if (sta_prepare_rate_control(local, sta, gfp)) + goto free_txq; + ++ sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + skb_queue_head_init(&sta->ps_tx_buf[i]); + skb_queue_head_init(&sta->tx_filtered[i]); +- init_airtime_info(&sta->airtime[i], &local->airtime[i]); ++ sta->airtime[i].deficit = sta->airtime_weight; ++ atomic_set(&sta->airtime[i].aql_tx_pending, 0); ++ sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; ++ sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; + } + + for (i = 0; i < IEEE80211_NUM_TIDS; i++) +@@ -1889,59 +1893,24 @@ void ieee80211_sta_set_buffered(struct i + } + EXPORT_SYMBOL(ieee80211_sta_set_buffered); + +-void ieee80211_register_airtime(struct ieee80211_txq *txq, +- u32 tx_airtime, u32 rx_airtime) ++void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, ++ u32 tx_airtime, u32 rx_airtime) + { +- struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif); +- struct ieee80211_local *local = sdata->local; +- u64 weight_sum, weight_sum_reciprocal; +- struct airtime_sched_info *air_sched; +- struct airtime_info *air_info; ++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta); ++ struct ieee80211_local *local = sta->sdata->local; ++ u8 ac = ieee80211_ac_from_tid(tid); + u32 airtime = 0; + +- air_sched = &local->airtime[txq->ac]; +- air_info = to_airtime_info(txq); +- +- if (local->airtime_flags & AIRTIME_USE_TX) ++ if (sta->local->airtime_flags & AIRTIME_USE_TX) + airtime += tx_airtime; +- if (local->airtime_flags & AIRTIME_USE_RX) ++ if (sta->local->airtime_flags & AIRTIME_USE_RX) + airtime += rx_airtime; + +- /* Weights scale so the unit weight is 256 */ +- airtime <<= 8; +- +- spin_lock_bh(&air_sched->lock); +- +- air_info->tx_airtime += tx_airtime; +- air_info->rx_airtime += rx_airtime; +- +- if (air_sched->weight_sum) { +- weight_sum = air_sched->weight_sum; +- weight_sum_reciprocal = air_sched->weight_sum_reciprocal; +- } else { +- weight_sum = air_info->weight; +- weight_sum_reciprocal = air_info->weight_reciprocal; +- } +- +- /* Round the calculation of global vt */ +- air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) * +- weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64; +- air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) * +- air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32; +- ieee80211_resort_txq(&local->hw, txq); +- +- spin_unlock_bh(&air_sched->lock); +-} +- +-void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, +- u32 tx_airtime, u32 rx_airtime) +-{ +- struct ieee80211_txq *txq = pubsta->txq[tid]; +- +- if (!txq) +- return; +- +- ieee80211_register_airtime(txq, tx_airtime, rx_airtime); ++ spin_lock_bh(&local->active_txq_lock[ac]); ++ sta->airtime[ac].tx_airtime += tx_airtime; ++ sta->airtime[ac].rx_airtime += rx_airtime; ++ sta->airtime[ac].deficit -= airtime; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_sta_register_airtime); + +@@ -2385,7 +2354,7 @@ void sta_set_sinfo(struct sta_info *sta, + } + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { +- sinfo->airtime_weight = sta->airtime[0].weight; ++ sinfo->airtime_weight = sta->airtime_weight; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); + } + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -135,25 +135,18 @@ enum ieee80211_agg_stop_reason { + #define AIRTIME_USE_TX BIT(0) + #define AIRTIME_USE_RX BIT(1) + +- + struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; +- u64 v_t; +- u64 last_scheduled; +- struct list_head list; ++ s64 deficit; + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ + u32 aql_limit_low; + u32 aql_limit_high; +- u32 weight_reciprocal; +- u16 weight; + }; + + void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, + struct sta_info *sta, u8 ac, + u16 tx_airtime, bool tx_completed); +-void ieee80211_register_airtime(struct ieee80211_txq *txq, +- u32 tx_airtime, u32 rx_airtime); + + struct sta_info; + +@@ -523,6 +516,7 @@ struct ieee80211_fragment_cache { + * @tid_seq: per-TID sequence numbers for sending to this STA + * @airtime: per-AC struct airtime_info describing airtime statistics for this + * station ++ * @airtime_weight: station weight for airtime fairness calculation purposes + * @ampdu_mlme: A-MPDU state machine state + * @mesh: mesh STA information + * @debugfs_dir: debug filesystem directory dentry +@@ -653,6 +647,7 @@ struct sta_info { + u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; + + struct airtime_info airtime[IEEE80211_NUM_ACS]; ++ u16 airtime_weight; + + /* + * Aggregation information, locked with lock. +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -983,25 +983,6 @@ static void __ieee80211_tx_status(struct + if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) + ieee80211_frame_acked(sta, skb); + +- } else if (wiphy_ext_feature_isset(local->hw.wiphy, +- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { +- struct ieee80211_sub_if_data *sdata; +- struct ieee80211_txq *txq; +- u32 airtime; +- +- /* Account airtime to multicast queue */ +- sdata = ieee80211_sdata_from_skb(local, skb); +- +- if (sdata && (txq = sdata->vif.txq)) { +- airtime = info->status.tx_time ?: +- ieee80211_calc_expected_tx_airtime(hw, +- &sdata->vif, +- NULL, +- skb->len, +- false); +- +- ieee80211_register_airtime(txq, airtime, 0); +- } + } + + /* SNMP counters +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -1480,7 +1479,7 @@ void ieee80211_txq_init(struct ieee80211 + codel_vars_init(&txqi->def_cvars); + codel_stats_init(&txqi->cstats); + __skb_queue_head_init(&txqi->frags); +- RB_CLEAR_NODE(&txqi->schedule_order); ++ INIT_LIST_HEAD(&txqi->schedule_order); + + txqi->txq.vif = &sdata->vif; + +@@ -1524,7 +1523,9 @@ void ieee80211_txq_purge(struct ieee8021 + ieee80211_purge_tx_queue(&local->hw, &txqi->frags); + spin_unlock_bh(&fq->lock); + +- ieee80211_unschedule_txq(&local->hw, &txqi->txq, true); ++ spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); ++ list_del_init(&txqi->schedule_order); ++ spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); + } + + void ieee80211_txq_set_params(struct ieee80211_local *local) +@@ -3819,259 +3820,102 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue); + struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); +- struct airtime_sched_info *air_sched; +- u64 now = ktime_get_coarse_boottime_ns(); + struct ieee80211_txq *ret = NULL; +- struct airtime_info *air_info; +- struct txq_info *txqi = NULL; +- struct rb_node *node; +- bool first = false; ++ struct txq_info *txqi = NULL, *head = NULL; ++ bool found_eligible_txq = false; + +- air_sched = &local->airtime[ac]; +- spin_lock_bh(&air_sched->lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + +- node = air_sched->schedule_pos; +- +-begin: +- if (!node) { +- node = rb_first_cached(&air_sched->active_txqs); +- first = true; +- } else { +- node = rb_next(node); +- } +- +- if (!node) +- goto out; +- +- txqi = container_of(node, struct txq_info, schedule_order); +- air_info = to_airtime_info(&txqi->txq); +- +- if (air_info->v_t > air_sched->v_t && +- (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now))) ++ begin: ++ txqi = list_first_entry_or_null(&local->active_txqs[ac], ++ struct txq_info, ++ schedule_order); ++ if (!txqi) + goto out; + +- if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) { +- first = false; +- goto begin; +- } +- +- air_sched->schedule_pos = node; +- air_sched->last_schedule_activity = now; +- ret = &txqi->txq; +-out: +- spin_unlock_bh(&air_sched->lock); +- return ret; +-} +-EXPORT_SYMBOL(ieee80211_next_txq); +- +-static void __ieee80211_insert_txq(struct rb_root_cached *root, +- struct txq_info *txqi) +-{ +- struct rb_node **new = &root->rb_root.rb_node; +- struct airtime_info *old_air, *new_air; +- struct rb_node *parent = NULL; +- struct txq_info *__txqi; +- bool leftmost = true; +- +- while (*new) { +- parent = *new; +- __txqi = rb_entry(parent, struct txq_info, schedule_order); +- old_air = to_airtime_info(&__txqi->txq); +- new_air = to_airtime_info(&txqi->txq); +- +- if (new_air->v_t <= old_air->v_t) { +- new = &parent->rb_left; +- } else { +- new = &parent->rb_right; +- leftmost = false; +- } ++ if (txqi == head) { ++ if (!found_eligible_txq) ++ goto out; ++ else ++ found_eligible_txq = false; + } + +- rb_link_node(&txqi->schedule_order, parent, new); +- rb_insert_color_cached(&txqi->schedule_order, root, leftmost); +-} +- +-void ieee80211_resort_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq) +-{ +- struct airtime_info *air_info = to_airtime_info(txq); +- struct ieee80211_local *local = hw_to_local(hw); +- struct txq_info *txqi = to_txq_info(txq); +- struct airtime_sched_info *air_sched; +- +- air_sched = &local->airtime[txq->ac]; ++ if (!head) ++ head = txqi; + +- lockdep_assert_held(&air_sched->lock); +- +- if (!RB_EMPTY_NODE(&txqi->schedule_order)) { +- struct airtime_info *a_prev = NULL, *a_next = NULL; +- struct txq_info *t_prev, *t_next; +- struct rb_node *n_prev, *n_next; ++ if (txqi->txq.sta) { ++ struct sta_info *sta = container_of(txqi->txq.sta, ++ struct sta_info, sta); ++ bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); ++ s64 deficit = sta->airtime[txqi->txq.ac].deficit; + +- /* Erasing a node can cause an expensive rebalancing operation, +- * so we check the previous and next nodes first and only remove +- * and re-insert if the current node is not already in the +- * correct position. +- */ +- if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) { +- t_prev = container_of(n_prev, struct txq_info, +- schedule_order); +- a_prev = to_airtime_info(&t_prev->txq); +- } ++ if (aql_check) ++ found_eligible_txq = true; + +- if ((n_next = rb_next(&txqi->schedule_order)) != NULL) { +- t_next = container_of(n_next, struct txq_info, +- schedule_order); +- a_next = to_airtime_info(&t_next->txq); ++ if (deficit < 0) ++ sta->airtime[txqi->txq.ac].deficit += ++ sta->airtime_weight; ++ ++ if (deficit < 0 || !aql_check) { ++ list_move_tail(&txqi->schedule_order, ++ &local->active_txqs[txqi->txq.ac]); ++ goto begin; + } +- +- if ((!a_prev || a_prev->v_t <= air_info->v_t) && +- (!a_next || a_next->v_t > air_info->v_t)) +- return; +- +- if (air_sched->schedule_pos == &txqi->schedule_order) +- air_sched->schedule_pos = n_prev; +- +- rb_erase_cached(&txqi->schedule_order, +- &air_sched->active_txqs); +- RB_CLEAR_NODE(&txqi->schedule_order); +- __ieee80211_insert_txq(&air_sched->active_txqs, txqi); + } +-} +- +-void ieee80211_update_airtime_weight(struct ieee80211_local *local, +- struct airtime_sched_info *air_sched, +- u64 now, bool force) +-{ +- struct airtime_info *air_info, *tmp; +- u64 weight_sum = 0; +- +- if (unlikely(!now)) +- now = ktime_get_coarse_boottime_ns(); +- +- lockdep_assert_held(&air_sched->lock); +- +- if (!force && (air_sched->last_weight_update < +- now - AIRTIME_ACTIVE_DURATION)) +- return; +- +- list_for_each_entry_safe(air_info, tmp, +- &air_sched->active_list, list) { +- if (airtime_is_active(air_info, now)) +- weight_sum += air_info->weight; +- else +- list_del_init(&air_info->list); +- } +- airtime_weight_sum_set(air_sched, weight_sum); +- air_sched->last_weight_update = now; +-} + +-void ieee80211_schedule_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq) +- __acquires(txq_lock) __releases(txq_lock) +-{ +- struct ieee80211_local *local = hw_to_local(hw); +- struct txq_info *txqi = to_txq_info(txq); +- struct airtime_sched_info *air_sched; +- u64 now = ktime_get_coarse_boottime_ns(); +- struct airtime_info *air_info; +- u8 ac = txq->ac; +- bool was_active; + +- air_sched = &local->airtime[ac]; +- air_info = to_airtime_info(txq); +- +- spin_lock_bh(&air_sched->lock); +- was_active = airtime_is_active(air_info, now); +- airtime_set_active(air_sched, air_info, now); +- +- if (!RB_EMPTY_NODE(&txqi->schedule_order)) ++ if (txqi->schedule_round == local->schedule_round[ac]) + goto out; + +- /* If the station has been inactive for a while, catch up its v_t so it +- * doesn't get indefinite priority; see comment above the definition of +- * AIRTIME_MAX_BEHIND. +- */ +- if ((!was_active && air_info->v_t < air_sched->v_t) || +- air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND) +- air_info->v_t = air_sched->v_t; +- +- ieee80211_update_airtime_weight(local, air_sched, now, !was_active); +- __ieee80211_insert_txq(&air_sched->active_txqs, txqi); ++ list_del_init(&txqi->schedule_order); ++ txqi->schedule_round = local->schedule_round[ac]; ++ ret = &txqi->txq; + + out: +- spin_unlock_bh(&air_sched->lock); +-} +-EXPORT_SYMBOL(ieee80211_schedule_txq); +- +-static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq, +- bool purge) +-{ +- struct ieee80211_local *local = hw_to_local(hw); +- struct txq_info *txqi = to_txq_info(txq); +- struct airtime_sched_info *air_sched; +- struct airtime_info *air_info; +- +- air_sched = &local->airtime[txq->ac]; +- air_info = to_airtime_info(&txqi->txq); +- +- lockdep_assert_held(&air_sched->lock); +- +- if (purge) { +- list_del_init(&air_info->list); +- ieee80211_update_airtime_weight(local, air_sched, 0, true); +- } +- +- if (RB_EMPTY_NODE(&txqi->schedule_order)) +- return; +- +- if (air_sched->schedule_pos == &txqi->schedule_order) +- air_sched->schedule_pos = rb_prev(&txqi->schedule_order); +- +- if (!purge) +- airtime_set_active(air_sched, air_info, +- ktime_get_coarse_boottime_ns()); +- +- rb_erase_cached(&txqi->schedule_order, +- &air_sched->active_txqs); +- RB_CLEAR_NODE(&txqi->schedule_order); ++ spin_unlock_bh(&local->active_txq_lock[ac]); ++ return ret; + } ++EXPORT_SYMBOL(ieee80211_next_txq); + +-void ieee80211_unschedule_txq(struct ieee80211_hw *hw, ++void __ieee80211_schedule_txq(struct ieee80211_hw *hw, + struct ieee80211_txq *txq, +- bool purge) +- __acquires(txq_lock) __releases(txq_lock) +-{ +- struct ieee80211_local *local = hw_to_local(hw); +- +- spin_lock_bh(&local->airtime[txq->ac].lock); +- __ieee80211_unschedule_txq(hw, txq, purge); +- spin_unlock_bh(&local->airtime[txq->ac].lock); +-} +- +-void ieee80211_return_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq, bool force) ++ bool force) + { + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); + +- spin_lock_bh(&local->airtime[txq->ac].lock); ++ spin_lock_bh(&local->active_txq_lock[txq->ac]); + +- if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force && +- !txq_has_queue(txq)) +- __ieee80211_unschedule_txq(hw, txq, false); ++ if (list_empty(&txqi->schedule_order) && ++ (force || !skb_queue_empty(&txqi->frags) || ++ txqi->tin.backlog_packets)) { ++ /* If airtime accounting is active, always enqueue STAs at the ++ * head of the list to ensure that they only get moved to the ++ * back by the airtime DRR scheduler once they have a negative ++ * deficit. A station that already has a negative deficit will ++ * get immediately moved to the back of the list on the next ++ * call to ieee80211_next_txq(). ++ */ ++ if (txqi->txq.sta && local->airtime_flags && ++ wiphy_ext_feature_isset(local->hw.wiphy, ++ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) ++ list_add(&txqi->schedule_order, ++ &local->active_txqs[txq->ac]); ++ else ++ list_add_tail(&txqi->schedule_order, ++ &local->active_txqs[txq->ac]); ++ } + +- spin_unlock_bh(&local->airtime[txq->ac].lock); ++ spin_unlock_bh(&local->active_txq_lock[txq->ac]); + } +-EXPORT_SYMBOL(ieee80211_return_txq); ++EXPORT_SYMBOL(__ieee80211_schedule_txq); + + DEFINE_STATIC_KEY_FALSE(aql_disable); + + bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +- struct airtime_info *air_info = to_airtime_info(txq); ++ struct sta_info *sta; + struct ieee80211_local *local = hw_to_local(hw); + + if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) +@@ -4086,12 +3930,15 @@ bool ieee80211_txq_airtime_check(struct + if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) + return true; + +- if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low) ++ sta = container_of(txq->sta, struct sta_info, sta); ++ if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < ++ sta->airtime[txq->ac].aql_limit_low) + return true; + + if (atomic_read(&local->aql_total_pending_airtime) < + local->aql_threshold && +- atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high) ++ atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < ++ sta->airtime[txq->ac].aql_limit_high) + return true; + + return false; +@@ -4101,59 +3948,60 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec + bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +- struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq); + struct ieee80211_local *local = hw_to_local(hw); +- struct airtime_sched_info *air_sched; +- struct airtime_info *air_info; +- struct rb_node *node = NULL; +- bool ret = false; +- u64 now; +- ++ struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); ++ struct sta_info *sta; ++ u8 ac = txq->ac; + +- if (!ieee80211_txq_airtime_check(hw, txq)) +- return false; ++ spin_lock_bh(&local->active_txq_lock[ac]); + +- air_sched = &local->airtime[txq->ac]; +- spin_lock_bh(&air_sched->lock); ++ if (!txqi->txq.sta) ++ goto out; + +- if (RB_EMPTY_NODE(&txqi->schedule_order)) ++ if (list_empty(&txqi->schedule_order)) + goto out; + +- now = ktime_get_coarse_boottime_ns(); ++ list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], ++ schedule_order) { ++ if (iter == txqi) ++ break; + +- /* Like in ieee80211_next_txq(), make sure the first station in the +- * scheduling order is eligible for transmission to avoid starvation. +- */ +- node = rb_first_cached(&air_sched->active_txqs); +- if (node) { +- first_txqi = container_of(node, struct txq_info, +- schedule_order); +- air_info = to_airtime_info(&first_txqi->txq); +- +- if (air_sched->v_t < air_info->v_t) +- airtime_catchup_v_t(air_sched, air_info->v_t, now); ++ if (!iter->txq.sta) { ++ list_move_tail(&iter->schedule_order, ++ &local->active_txqs[ac]); ++ continue; ++ } ++ sta = container_of(iter->txq.sta, struct sta_info, sta); ++ if (sta->airtime[ac].deficit < 0) ++ sta->airtime[ac].deficit += sta->airtime_weight; ++ list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); + } + +- air_info = to_airtime_info(&txqi->txq); +- if (air_info->v_t <= air_sched->v_t) { +- air_sched->last_schedule_activity = now; +- ret = true; +- } ++ sta = container_of(txqi->txq.sta, struct sta_info, sta); ++ if (sta->airtime[ac].deficit >= 0) ++ goto out; ++ ++ sta->airtime[ac].deficit += sta->airtime_weight; ++ list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); ++ spin_unlock_bh(&local->active_txq_lock[ac]); + ++ return false; + out: +- spin_unlock_bh(&air_sched->lock); +- return ret; ++ if (!list_empty(&txqi->schedule_order)) ++ list_del_init(&txqi->schedule_order); ++ spin_unlock_bh(&local->active_txq_lock[ac]); ++ ++ return true; + } + EXPORT_SYMBOL(ieee80211_txq_may_transmit); + + void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); +- struct airtime_sched_info *air_sched = &local->airtime[ac]; + +- spin_lock_bh(&air_sched->lock); +- air_sched->schedule_pos = NULL; +- spin_unlock_bh(&air_sched->lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); ++ local->schedule_round[ac]++; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_txq_schedule_start); + diff --git a/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch b/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch new file mode 100644 index 000000000..c006d3762 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch @@ -0,0 +1,52 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 14:53:04 +0200 +Subject: [PATCH] mac80211: make sta airtime deficit field s32 instead of + s64 + +32 bit is more than enough range for the airtime deficit + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f + size_t bufsz = 400; + char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; + u64 rx_airtime = 0, tx_airtime = 0; +- s64 deficit[IEEE80211_NUM_ACS]; ++ s32 deficit[IEEE80211_NUM_ACS]; + ssize_t rv; + int ac; + +@@ -219,7 +219,7 @@ static ssize_t sta_airtime_read(struct f + + p += scnprintf(p, bufsz + buf - p, + "RX: %llu us\nTX: %llu us\nWeight: %u\n" +- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", ++ "Deficit: VO: %d us VI: %d us BE: %d us BK: %d us\n", + rx_airtime, tx_airtime, sta->airtime_weight, + deficit[0], deficit[1], deficit[2], deficit[3]); + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -138,7 +138,7 @@ enum ieee80211_agg_stop_reason { + struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; +- s64 deficit; ++ s32 deficit; + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ + u32 aql_limit_low; + u32 aql_limit_high; +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3847,7 +3847,7 @@ struct ieee80211_txq *ieee80211_next_txq + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); + bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); +- s64 deficit = sta->airtime[txqi->txq.ac].deficit; ++ s32 deficit = sta->airtime[txqi->txq.ac].deficit; + + if (aql_check) + found_eligible_txq = true; diff --git a/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch b/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch new file mode 100644 index 000000000..c21429460 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch @@ -0,0 +1,48 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 14:59:09 +0200 +Subject: [PATCH] mac80211: consider aql_tx_pending when checking airtime + deficit + +When queueing packets for a station, deficit only gets added once the packets +have been transmitted, which could be much later. During that time, a lot of +temporary unfairness could happen, which could lead to bursty behavior. +Fix this by subtracting the aql_tx_pending when checking the deficit in tx +scheduling. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3817,6 +3817,13 @@ out: + } + EXPORT_SYMBOL(ieee80211_tx_dequeue); + ++static inline s32 ieee80211_sta_deficit(struct sta_info *sta, u8 ac) ++{ ++ struct airtime_info *air_info = &sta->airtime[ac]; ++ ++ return air_info->deficit - atomic_read(&air_info->aql_tx_pending); ++} ++ + struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); +@@ -3847,7 +3854,7 @@ struct ieee80211_txq *ieee80211_next_txq + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); + bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); +- s32 deficit = sta->airtime[txqi->txq.ac].deficit; ++ s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac); + + if (aql_check) + found_eligible_txq = true; +@@ -3972,7 +3979,7 @@ bool ieee80211_txq_may_transmit(struct i + continue; + } + sta = container_of(iter->txq.sta, struct sta_info, sta); +- if (sta->airtime[ac].deficit < 0) ++ if (ieee80211_sta_deficit(sta, ac) < 0) + sta->airtime[ac].deficit += sta->airtime_weight; + list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); + } diff --git a/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch b/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch new file mode 100644 index 000000000..317e4f065 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch @@ -0,0 +1,118 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 20:52:50 +0200 +Subject: [PATCH] mac80211: keep recently active tx queues in scheduling + list + +This allows proper deficit accounting to ensure that they don't carry their +deficit until the next time they become active + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -83,6 +83,13 @@ extern const u8 ieee80211_ac_to_qos_mask + + #define IEEE80211_MAX_NAN_INSTANCE_ID 255 + ++ ++/* ++ * Keep a station's queues on the active list for deficit accounting purposes ++ * if it was active or queued during the last 100ms ++ */ ++#define AIRTIME_ACTIVE_DURATION (HZ / 10) ++ + struct ieee80211_bss { + u32 device_ts_beacon, device_ts_presp; + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -138,6 +138,7 @@ enum ieee80211_agg_stop_reason { + struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; ++ u32 last_active; + s32 deficit; + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ + u32 aql_limit_low; +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3824,6 +3824,36 @@ static inline s32 ieee80211_sta_deficit( + return air_info->deficit - atomic_read(&air_info->aql_tx_pending); + } + ++static void ++ieee80211_txq_set_active(struct txq_info *txqi) ++{ ++ struct sta_info *sta; ++ ++ if (!txqi->txq.sta) ++ return; ++ ++ sta = container_of(txqi->txq.sta, struct sta_info, sta); ++ sta->airtime[txqi->txq.ac].last_active = (u32)jiffies; ++} ++ ++static bool ++ieee80211_txq_keep_active(struct txq_info *txqi) ++{ ++ struct sta_info *sta; ++ u32 diff; ++ ++ if (!txqi->txq.sta) ++ return false; ++ ++ sta = container_of(txqi->txq.sta, struct sta_info, sta); ++ if (ieee80211_sta_deficit(sta, txqi->txq.ac) >= 0) ++ return false; ++ ++ diff = (u32)jiffies - sta->airtime[txqi->txq.ac].last_active; ++ ++ return diff <= AIRTIME_ACTIVE_DURATION; ++} ++ + struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); +@@ -3870,7 +3900,6 @@ struct ieee80211_txq *ieee80211_next_txq + } + } + +- + if (txqi->schedule_round == local->schedule_round[ac]) + goto out; + +@@ -3890,12 +3919,13 @@ void __ieee80211_schedule_txq(struct iee + { + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); ++ bool has_queue; + + spin_lock_bh(&local->active_txq_lock[txq->ac]); + ++ has_queue = force || txq_has_queue(txq); + if (list_empty(&txqi->schedule_order) && +- (force || !skb_queue_empty(&txqi->frags) || +- txqi->tin.backlog_packets)) { ++ (has_queue || ieee80211_txq_keep_active(txqi))) { + /* If airtime accounting is active, always enqueue STAs at the + * head of the list to ensure that they only get moved to the + * back by the airtime DRR scheduler once they have a negative +@@ -3903,7 +3933,7 @@ void __ieee80211_schedule_txq(struct iee + * get immediately moved to the back of the list on the next + * call to ieee80211_next_txq(). + */ +- if (txqi->txq.sta && local->airtime_flags && ++ if (txqi->txq.sta && local->airtime_flags && has_queue && + wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + list_add(&txqi->schedule_order, +@@ -3911,6 +3941,8 @@ void __ieee80211_schedule_txq(struct iee + else + list_add_tail(&txqi->schedule_order, + &local->active_txqs[txq->ac]); ++ if (has_queue) ++ ieee80211_txq_set_active(txqi); + } + + spin_unlock_bh(&local->active_txq_lock[txq->ac]); diff --git a/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch new file mode 100644 index 000000000..89718a827 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch @@ -0,0 +1,131 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 21:26:34 +0200 +Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness + +In order to maintain fairness, the amount of queueing needs to be limited +beyond the simple per-station AQL budget, otherwise the driver can simply +repeatedly do scheduling rounds until all queues that have not used their +AQL budget become eligble. + +To be conservative, use the high AQL limit for the first txq and add half +of the low AQL for each subsequent queue. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1211,6 +1211,7 @@ struct ieee80211_local { + u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; + u32 aql_threshold; + atomic_t aql_total_pending_airtime; ++ atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS]; + + const struct ieee80211_ops *ops; + +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; + local->aql_txq_limit_high[i] = + IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; ++ atomic_set(&local->aql_ac_pending_airtime[i], 0); + } + + local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX; +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim + &sta->airtime[ac].aql_tx_pending); + + atomic_add(tx_airtime, &local->aql_total_pending_airtime); ++ atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]); + return; + } + +@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim + tx_pending, 0); + } + ++ atomic_sub(tx_airtime, &local->aql_total_pending_airtime); + tx_pending = atomic_sub_return(tx_airtime, +- &local->aql_total_pending_airtime); ++ &local->aql_ac_pending_airtime[ac]); + if (WARN_ONCE(tx_pending < 0, + "Device %s AC %d pending airtime underflow: %u, %u", + wiphy_name(local->hw.wiphy), ac, tx_pending, +- tx_airtime)) +- atomic_cmpxchg(&local->aql_total_pending_airtime, ++ tx_airtime)) { ++ atomic_cmpxchg(&local->aql_ac_pending_airtime[ac], + tx_pending, 0); ++ atomic_sub(tx_pending, &local->aql_total_pending_airtime); ++ } + } + + int sta_info_move_state(struct sta_info *sta, +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq + + spin_lock_bh(&local->active_txq_lock[ac]); + ++ if (!local->schedule_round[ac]) ++ goto out; ++ + begin: + txqi = list_first_entry_or_null(&local->active_txqs[ac], + struct txq_info, +@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct + } + EXPORT_SYMBOL(ieee80211_txq_airtime_check); + ++static bool ++ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac) ++{ ++ unsigned int num_txq = 0; ++ struct txq_info *txq; ++ u32 aql_limit; ++ ++ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) ++ return true; ++ ++ list_for_each_entry(txq, &local->active_txqs[ac], schedule_order) ++ num_txq++; ++ ++ aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 + ++ local->aql_txq_limit_high[ac]; ++ ++ return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit; ++} ++ + bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i + if (list_empty(&txqi->schedule_order)) + goto out; + ++ if (!ieee80211_txq_schedule_airtime_check(local, ac)) ++ goto out; ++ + list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], + schedule_order) { + if (iter == txqi) +@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct + struct ieee80211_local *local = hw_to_local(hw); + + spin_lock_bh(&local->active_txq_lock[ac]); +- local->schedule_round[ac]++; ++ ++ if (ieee80211_txq_schedule_airtime_check(local, ac)) { ++ local->schedule_round[ac]++; ++ if (!local->schedule_round[ac]) ++ local->schedule_round[ac]++; ++ } else { ++ local->schedule_round[ac] = 0; ++ } ++ + spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_txq_schedule_start); diff --git a/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch b/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch new file mode 100644 index 000000000..df45a520f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch @@ -0,0 +1,58 @@ +From: Felix Fietkau +Date: Sat, 25 Jun 2022 21:25:40 +0200 +Subject: [PATCH] mac80211: add debugfs file to display per-phy AQL pending + airtime + +Now that the global pending airtime is more relevant for airtime fairness, +it makes sense to make it accessible via debugfs for debugging + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -201,6 +201,36 @@ static const struct file_operations airt + .llseek = default_llseek, + }; + ++static ssize_t aql_pending_read(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ieee80211_local *local = file->private_data; ++ char buf[400]; ++ int len = 0; ++ ++ len = scnprintf(buf, sizeof(buf), ++ "AC AQL pending\n" ++ "VO %u us\n" ++ "VI %u us\n" ++ "BE %u us\n" ++ "BK %u us\n" ++ "total %u us\n", ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]), ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]), ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]), ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]), ++ atomic_read(&local->aql_total_pending_airtime)); ++ return simple_read_from_buffer(user_buf, count, ppos, ++ buf, len); ++} ++ ++static const struct file_operations aql_pending_ops = { ++ .read = aql_pending_read, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ + static ssize_t aql_txq_limit_read(struct file *file, + char __user *user_buf, + size_t count, +@@ -628,6 +658,7 @@ void debugfs_hw_add(struct ieee80211_loc + DEBUGFS_ADD(hw_conf); + DEBUGFS_ADD_MODE(force_tx_status, 0600); + DEBUGFS_ADD_MODE(aql_enable, 0600); ++ DEBUGFS_ADD(aql_pending); + + if (local->ops->wake_tx_queue) + DEBUGFS_ADD_MODE(aqm, 0600); diff --git a/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch b/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch new file mode 100644 index 000000000..35f07c1a9 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch @@ -0,0 +1,36 @@ +From: Felix Fietkau +Date: Sat, 25 Jun 2022 23:10:19 +0200 +Subject: [PATCH] mac80211: only accumulate airtime deficit for active + clients + +When a client does not generate any local tx activity, accumulating airtime +deficit for the round-robin scheduler can be harmful. If this goes on for too +long, the deficit could grow quite large, which might cause unreasonable +initial latency once the client becomes active + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1900,6 +1900,7 @@ void ieee80211_sta_register_airtime(stru + struct ieee80211_local *local = sta->sdata->local; + u8 ac = ieee80211_ac_from_tid(tid); + u32 airtime = 0; ++ u32 diff; + + if (sta->local->airtime_flags & AIRTIME_USE_TX) + airtime += tx_airtime; +@@ -1909,7 +1910,11 @@ void ieee80211_sta_register_airtime(stru + spin_lock_bh(&local->active_txq_lock[ac]); + sta->airtime[ac].tx_airtime += tx_airtime; + sta->airtime[ac].rx_airtime += rx_airtime; +- sta->airtime[ac].deficit -= airtime; ++ ++ diff = (u32)jiffies - sta->airtime[ac].last_active; ++ if (diff <= AIRTIME_ACTIVE_DURATION) ++ sta->airtime[ac].deficit -= airtime; ++ + spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_sta_register_airtime); diff --git a/package/kernel/mac80211/patches/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch b/package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch similarity index 89% rename from package/kernel/mac80211/patches/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch rename to package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch index d541b621f..74e857679 100644 --- a/package/kernel/mac80211/patches/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch +++ b/package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch @@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c -@@ -3976,7 +3976,7 @@ struct ieee80211_txq *ieee80211_next_txq +@@ -3894,7 +3894,7 @@ struct ieee80211_txq *ieee80211_next_txq if (deficit < 0) sta->airtime[txqi->txq.ac].deficit += @@ -32,7 +32,7 @@ Signed-off-by: Felix Fietkau if (deficit < 0 || !aql_check) { list_move_tail(&txqi->schedule_order, -@@ -4119,7 +4119,8 @@ bool ieee80211_txq_may_transmit(struct i +@@ -4037,7 +4037,8 @@ bool ieee80211_txq_may_transmit(struct i } sta = container_of(iter->txq.sta, struct sta_info, sta); if (ieee80211_sta_deficit(sta, ac) < 0) @@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); } -@@ -4127,7 +4128,7 @@ bool ieee80211_txq_may_transmit(struct i +@@ -4045,7 +4046,7 @@ bool ieee80211_txq_may_transmit(struct i if (sta->airtime[ac].deficit >= 0) goto out; diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch new file mode 100644 index 000000000..3fa70b05f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch @@ -0,0 +1,110 @@ +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:07 +0200 +Subject: [PATCH] mac80211: mesh: clean up rx_bcn_presp API + +commit a5b983c6073140b624f64e79fea6d33c3e4315a0 upstream. + +We currently pass the entire elements to the rx_bcn_presp() +method, but only need mesh_config. Additionally, we use the +length of the elements to calculate back the entire frame's +length, but that's confusing - just pass the length of the +frame instead. + +Link: https://lore.kernel.org/r/20210920154009.a18ed3d2da6c.I1824b773a0fbae4453e1433c184678ca14e8df45@changeid +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -645,10 +645,9 @@ struct ieee80211_if_ocb { + */ + struct ieee802_11_elems; + struct ieee80211_mesh_sync_ops { +- void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, +- u16 stype, +- struct ieee80211_mgmt *mgmt, +- struct ieee802_11_elems *elems, ++ void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, u16 stype, ++ struct ieee80211_mgmt *mgmt, unsigned int len, ++ const struct ieee80211_meshconf_ie *mesh_cfg, + struct ieee80211_rx_status *rx_status); + + /* should be called with beacon_data under RCU read lock */ +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -1354,8 +1354,8 @@ static void ieee80211_mesh_rx_bcn_presp( + } + + if (ifmsh->sync_ops) +- ifmsh->sync_ops->rx_bcn_presp(sdata, +- stype, mgmt, &elems, rx_status); ++ ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len, ++ elems.mesh_config, rx_status); + } + + int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) +--- a/net/mac80211/mesh_sync.c ++++ b/net/mac80211/mesh_sync.c +@@ -3,6 +3,7 @@ + * Copyright 2011-2012, Pavel Zubarev + * Copyright 2011-2012, Marco Porsch + * Copyright 2011-2012, cozybit Inc. ++ * Copyright (C) 2021 Intel Corporation + */ + + #include "ieee80211_i.h" +@@ -35,12 +36,12 @@ struct sync_method { + /** + * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT + * +- * @ie: information elements of a management frame from the mesh peer ++ * @cfg: mesh config element from the mesh peer (or %NULL) + */ +-static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) ++static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg) + { +- return (ie->mesh_config->meshconf_cap & +- IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; ++ return cfg && ++ (cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING); + } + + void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata) +@@ -76,11 +77,11 @@ void mesh_sync_adjust_tsf(struct ieee802 + } + } + +-static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, +- u16 stype, +- struct ieee80211_mgmt *mgmt, +- struct ieee802_11_elems *elems, +- struct ieee80211_rx_status *rx_status) ++static void ++mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype, ++ struct ieee80211_mgmt *mgmt, unsigned int len, ++ const struct ieee80211_meshconf_ie *mesh_cfg, ++ struct ieee80211_rx_status *rx_status) + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; +@@ -101,10 +102,7 @@ static void mesh_sync_offset_rx_bcn_pres + */ + if (ieee80211_have_rx_timestamp(rx_status)) + t_r = ieee80211_calculate_rx_timestamp(local, rx_status, +- 24 + 12 + +- elems->total_len + +- FCS_LEN, +- 24); ++ len + FCS_LEN, 24); + else + t_r = drv_get_tsf(local, sdata); + +@@ -119,7 +117,7 @@ static void mesh_sync_offset_rx_bcn_pres + * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors + */ + +- if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { ++ if (mesh_peer_tbtt_adjusting(mesh_cfg)) { + msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", + sta->sta.addr); + goto no_sync; diff --git a/package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch b/package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch new file mode 100644 index 000000000..0ad100e2e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch @@ -0,0 +1,82 @@ +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:08 +0200 +Subject: [PATCH] mac80211: move CRC into struct ieee802_11_elems + +commit c6e37ed498f958254b5459253199e816b6bfc52f upstream. + +We're currently returning this value, but to prepare for +returning the allocated structure, move it into there. + +Link: https://lore.kernel.org/r/20210920154009.479b8ebf999d.If0d4ba75ee38998dc3eeae25058aa748efcb2fc9@changeid +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1525,6 +1525,7 @@ struct ieee80211_csa_ie { + struct ieee802_11_elems { + const u8 *ie_start; + size_t total_len; ++ u32 crc; + + /* pointers to IEs */ + const struct ieee80211_tdls_lnkie *lnk_id; +@@ -2084,10 +2085,10 @@ static inline void ieee80211_tx_skb(stru + ieee80211_tx_skb_tid(sdata, skb, 7); + } + +-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid); ++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, ++ struct ieee802_11_elems *elems, ++ u64 filter, u32 crc, u8 *transmitter_bssid, ++ u8 *bss_bssid); + static inline void ieee802_11_parse_elems(const u8 *start, size_t len, + bool action, + struct ieee802_11_elems *elems, +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -4096,10 +4096,11 @@ static void ieee80211_rx_mgmt_beacon(str + */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); +- ncrc = ieee802_11_parse_elems_crc(variable, +- len - baselen, false, &elems, +- care_about_ies, ncrc, +- mgmt->bssid, bssid); ++ ieee802_11_parse_elems_crc(variable, ++ len - baselen, false, &elems, ++ care_about_ies, ncrc, ++ mgmt->bssid, bssid); ++ ncrc = elems.crc; + + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && + ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1469,10 +1469,10 @@ static size_t ieee802_11_find_bssid_prof + return found ? profile_len : 0; + } + +-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid) ++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, ++ struct ieee802_11_elems *elems, ++ u64 filter, u32 crc, u8 *transmitter_bssid, ++ u8 *bss_bssid) + { + const struct element *non_inherit = NULL; + u8 *nontransmitted_profile; +@@ -1524,7 +1524,7 @@ u32 ieee802_11_parse_elems_crc(const u8 + + kfree(nontransmitted_profile); + +- return crc; ++ elems->crc = crc; + } + + void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, diff --git a/package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch b/package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch new file mode 100644 index 000000000..19c18ea13 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch @@ -0,0 +1,80 @@ +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:09 +0200 +Subject: [PATCH] mac80211: mlme: find auth challenge directly + +commit 49a765d6785e99157ff5091cc37485732496864e upstream. + +There's no need to parse all elements etc. just to find the +authentication challenge - use cfg80211_find_elem() instead. +This also allows us to remove WLAN_EID_CHALLENGE handling +from the element parsing entirely. + +Link: https://lore.kernel.org/r/20210920154009.45f9b3a15722.Ice3159ffad03a007d6154cbf1fb3a8c48489e86f@changeid +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1535,7 +1535,6 @@ struct ieee802_11_elems { + const u8 *supp_rates; + const u8 *ds_params; + const struct ieee80211_tim_ie *tim; +- const u8 *challenge; + const u8 *rsn; + const u8 *rsnx; + const u8 *erp_info; +@@ -1589,7 +1588,6 @@ struct ieee802_11_elems { + u8 ssid_len; + u8 supp_rates_len; + u8 tim_len; +- u8 challenge_len; + u8 rsn_len; + u8 rsnx_len; + u8 ext_supp_rates_len; +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2889,17 +2889,17 @@ static void ieee80211_auth_challenge(str + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; ++ const struct element *challenge; + u8 *pos; +- struct ieee802_11_elems elems; + u32 tx_flags = 0; + struct ieee80211_prep_tx_info info = { + .subtype = IEEE80211_STYPE_AUTH, + }; + + pos = mgmt->u.auth.variable; +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, +- mgmt->bssid, auth_data->bss->bssid); +- if (!elems.challenge) ++ challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos, ++ len - (pos - (u8 *)mgmt)); ++ if (!challenge) + return; + auth_data->expected_transaction = 4; + drv_mgd_prepare_tx(sdata->local, sdata, &info); +@@ -2907,7 +2907,8 @@ static void ieee80211_auth_challenge(str + tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_INTFL_MLME_CONN_TX; + ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, +- elems.challenge - 2, elems.challenge_len + 2, ++ (void *)challenge, ++ challenge->datalen + sizeof(*challenge), + auth_data->bss->bssid, auth_data->bss->bssid, + auth_data->key, auth_data->key_len, + auth_data->key_idx, tx_flags); +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1120,10 +1120,6 @@ _ieee802_11_parse_elems_crc(const u8 *st + } else + elem_parse_failed = true; + break; +- case WLAN_EID_CHALLENGE: +- elems->challenge = pos; +- elems->challenge_len = elen; +- break; + case WLAN_EID_VENDOR_SPECIFIC: + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && + pos[2] == 0xf2) { diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch new file mode 100644 index 000000000..8af61eea1 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch @@ -0,0 +1,1143 @@ +From: Johannes Berg +Date: Mon, 20 Sep 2021 15:40:10 +0200 +Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems + +As the 802.11 spec evolves, we need to parse more and more +elements. This is causing the struct to grow, and we can no +longer get away with putting it on the stack. + +Change the API to always dynamically allocate and return an +allocated pointer that must be kfree()d later. + +As an alternative, I contemplated a scheme whereby we'd say +in the code which elements we needed, e.g. + + DECLARE_ELEMENT_PARSER(elems, + SUPPORTED_CHANNELS, + CHANNEL_SWITCH, + EXT(KEY_DELIVERY)); + + ieee802_11_parse_elems(..., &elems, ...); + +and while I think this is possible and will save us a lot +since most individual places only care about a small subset +of the elements, it ended up being a bit more work since a +lot of places do the parsing and then pass the struct to +other functions, sometimes with multiple levels. + +Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -478,7 +478,7 @@ void ieee80211_process_addba_request(str + size_t len) + { + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; +- struct ieee802_11_elems elems = { }; ++ struct ieee802_11_elems *elems = NULL; + u8 dialog_token; + int ies_len; + +@@ -496,16 +496,17 @@ void ieee80211_process_addba_request(str + ies_len = len - offsetof(struct ieee80211_mgmt, + u.action.u.addba_req.variable); + if (ies_len) { +- ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); +- if (elems.parse_error) ++ elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, ++ ies_len, true, mgmt->bssid, NULL); ++ if (!elems || elems->parse_error) + return; + } + + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, + start_seq_num, ba_policy, tid, + buf_size, true, false, +- elems.addba_ext_ie); ++ elems ? elems->addba_ext_ie : NULL); ++ kfree(elems); + } + + void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif, +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -9,7 +9,7 @@ + * Copyright 2009, Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH +- * Copyright(c) 2018-2020 Intel Corporation ++ * Copyright(c) 2018-2021 Intel Corporation + */ + + #include +@@ -1589,7 +1589,7 @@ void ieee80211_rx_mgmt_probe_beacon(stru + struct ieee80211_rx_status *rx_status) + { + size_t baselen; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + + BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) != + offsetof(typeof(mgmt->u.beacon), variable)); +@@ -1602,10 +1602,14 @@ void ieee80211_rx_mgmt_probe_beacon(stru + if (baselen > len) + return; + +- ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, +- false, &elems, mgmt->bssid, NULL); +- +- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); ++ elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, ++ len - baselen, false, ++ mgmt->bssid, NULL); ++ ++ if (elems) { ++ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems); ++ kfree(elems); ++ } + } + + void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, +@@ -1614,7 +1618,7 @@ void ieee80211_ibss_rx_queued_mgmt(struc + struct ieee80211_rx_status *rx_status; + struct ieee80211_mgmt *mgmt; + u16 fc; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + int ies_len; + + rx_status = IEEE80211_SKB_RXCB(skb); +@@ -1651,15 +1655,16 @@ void ieee80211_ibss_rx_queued_mgmt(struc + if (ies_len < 0) + break; + +- ieee802_11_parse_elems( ++ elems = ieee802_11_parse_elems( + mgmt->u.action.u.chan_switch.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); ++ ies_len, true, mgmt->bssid, NULL); + +- if (elems.parse_error) ++ if (!elems || elems->parse_error) + break; + + ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, +- rx_status, &elems); ++ rx_status, elems); ++ kfree(elems); + break; + } + } +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2083,18 +2083,18 @@ static inline void ieee80211_tx_skb(stru + ieee80211_tx_skb_tid(sdata, skb, 7); + } + +-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid); +-static inline void ieee802_11_parse_elems(const u8 *start, size_t len, +- bool action, +- struct ieee802_11_elems *elems, +- u8 *transmitter_bssid, +- u8 *bss_bssid) ++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, ++ bool action, ++ u64 filter, u32 crc, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid); ++static inline struct ieee802_11_elems * ++ieee802_11_parse_elems(const u8 *start, size_t len, bool action, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid) + { +- ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0, +- transmitter_bssid, bss_bssid); ++ return ieee802_11_parse_elems_crc(start, len, action, 0, 0, ++ transmitter_bssid, bss_bssid); + } + + +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee8 + struct sk_buff *presp; + struct beacon_data *bcn; + struct ieee80211_mgmt *hdr; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u8 *pos; + +@@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee8 + if (baselen > len) + return; + +- ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid, +- NULL); +- +- if (!elems.mesh_id) ++ elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid, ++ NULL); ++ if (!elems) + return; + ++ if (!elems->mesh_id) ++ goto free; ++ + /* 802.11-2012 10.1.4.3.2 */ + if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && + !is_broadcast_ether_addr(mgmt->da)) || +- elems.ssid_len != 0) +- return; ++ elems->ssid_len != 0) ++ goto free; + +- if (elems.mesh_id_len != 0 && +- (elems.mesh_id_len != ifmsh->mesh_id_len || +- memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) +- return; ++ if (elems->mesh_id_len != 0 && ++ (elems->mesh_id_len != ifmsh->mesh_id_len || ++ memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) ++ goto free; + + rcu_read_lock(); + bcn = rcu_dereference(ifmsh->beacon); +@@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee8 + ieee80211_tx_skb(sdata, presp); + out: + rcu_read_unlock(); ++free: ++ kfree(elems); + } + + static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, +@@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp( + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + struct ieee80211_channel *channel; + size_t baselen; + int freq; +@@ -1320,42 +1324,47 @@ static void ieee80211_mesh_rx_bcn_presp( + if (baselen > len) + return; + +- ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, +- false, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, ++ len - baselen, ++ false, mgmt->bssid, NULL); ++ if (!elems) ++ return; + + /* ignore non-mesh or secure / unsecure mismatch */ +- if ((!elems.mesh_id || !elems.mesh_config) || +- (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || +- (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) +- return; ++ if ((!elems->mesh_id || !elems->mesh_config) || ++ (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || ++ (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) ++ goto free; + +- if (elems.ds_params) +- freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); ++ if (elems->ds_params) ++ freq = ieee80211_channel_to_frequency(elems->ds_params[0], band); + else + freq = rx_status->freq; + + channel = ieee80211_get_channel(local->hw.wiphy, freq); + + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) +- return; ++ goto free; + +- if (mesh_matches_local(sdata, &elems)) { ++ if (mesh_matches_local(sdata, elems)) { + mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n", + sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal); + if (!sdata->u.mesh.user_mpm || + sdata->u.mesh.mshcfg.rssi_threshold == 0 || + sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal) +- mesh_neighbour_update(sdata, mgmt->sa, &elems, ++ mesh_neighbour_update(sdata, mgmt->sa, elems, + rx_status); + + if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && + !sdata->vif.csa_active) +- ieee80211_mesh_process_chnswitch(sdata, &elems, true); ++ ieee80211_mesh_process_chnswitch(sdata, elems, true); + } + + if (ifmsh->sync_ops) + ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len, +- elems.mesh_config, rx_status); ++ elems->mesh_config, rx_status); ++free: ++ kfree(elems); + } + + int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) +@@ -1447,7 +1456,7 @@ static void mesh_rx_csa_frame(struct iee + struct ieee80211_mgmt *mgmt, size_t len) + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + u16 pre_value; + bool fwd_csa = true; + size_t baselen; +@@ -1460,33 +1469,37 @@ static void mesh_rx_csa_frame(struct iee + pos = mgmt->u.action.u.chan_switch.variable; + baselen = offsetof(struct ieee80211_mgmt, + u.action.u.chan_switch.variable); +- ieee802_11_parse_elems(pos, len - baselen, true, &elems, +- mgmt->bssid, NULL); +- +- if (!mesh_matches_local(sdata, &elems)) ++ elems = ieee802_11_parse_elems(pos, len - baselen, true, ++ mgmt->bssid, NULL); ++ if (!elems) + return; + +- ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; ++ if (!mesh_matches_local(sdata, elems)) ++ goto free; ++ ++ ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl; + if (!--ifmsh->chsw_ttl) + fwd_csa = false; + +- pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value); ++ pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value); + if (ifmsh->pre_value >= pre_value) +- return; ++ goto free; + + ifmsh->pre_value = pre_value; + + if (!sdata->vif.csa_active && +- !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { ++ !ieee80211_mesh_process_chnswitch(sdata, elems, false)) { + mcsa_dbg(sdata, "Failed to process CSA action frame"); +- return; ++ goto free; + } + + /* forward or re-broadcast the CSA frame */ + if (fwd_csa) { +- if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) ++ if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0) + mcsa_dbg(sdata, "Failed to forward the CSA frame"); + } ++free: ++ kfree(elems); + } + + static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* + * Copyright (c) 2008, 2009 open80211s Ltd. +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019, 2021 Intel Corporation + * Author: Luis Carlos Cobo + */ + +@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(stru + void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) + { +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u32 path_metric; + struct sta_info *sta; +@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee8 + rcu_read_unlock(); + + baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; +- ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, +- len - baselen, false, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, ++ len - baselen, false, mgmt->bssid, NULL); ++ if (!elems) ++ return; + +- if (elems.preq) { +- if (elems.preq_len != 37) ++ if (elems->preq) { ++ if (elems->preq_len != 37) + /* Right now we support just 1 destination and no AE */ +- return; +- path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, ++ goto free; ++ path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq, + MPATH_PREQ); + if (path_metric) +- hwmp_preq_frame_process(sdata, mgmt, elems.preq, ++ hwmp_preq_frame_process(sdata, mgmt, elems->preq, + path_metric); + } +- if (elems.prep) { +- if (elems.prep_len != 31) ++ if (elems->prep) { ++ if (elems->prep_len != 31) + /* Right now we support no AE */ +- return; +- path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, ++ goto free; ++ path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep, + MPATH_PREP); + if (path_metric) +- hwmp_prep_frame_process(sdata, mgmt, elems.prep, ++ hwmp_prep_frame_process(sdata, mgmt, elems->prep, + path_metric); + } +- if (elems.perr) { +- if (elems.perr_len != 15) ++ if (elems->perr) { ++ if (elems->perr_len != 15) + /* Right now we support only one destination per PERR */ +- return; +- hwmp_perr_frame_process(sdata, mgmt, elems.perr); ++ goto free; ++ hwmp_perr_frame_process(sdata, mgmt, elems->perr); + } +- if (elems.rann) +- hwmp_rann_frame_process(sdata, mgmt, elems.rann); ++ if (elems->rann) ++ hwmp_rann_frame_process(sdata, mgmt, elems->rann); ++free: ++ kfree(elems); + } + + /** +--- a/net/mac80211/mesh_plink.c ++++ b/net/mac80211/mesh_plink.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* + * Copyright (c) 2008, 2009 open80211s Ltd. +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019, 2021 Intel Corporation + * Author: Luis Carlos Cobo + */ + #include +@@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee8021 + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) + { +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u8 *baseaddr; + +@@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee8021 + if (baselen > len) + return; + } +- ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems, +- mgmt->bssid, NULL); +- mesh_process_plink_frame(sdata, mgmt, &elems, rx_status); ++ elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, ++ mgmt->bssid, NULL); ++ mesh_process_plink_frame(sdata, mgmt, elems, rx_status); ++ kfree(elems); + } +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3317,8 +3317,11 @@ static bool ieee80211_assoc_success(stru + aid = 0; /* TODO */ + } + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems, +- mgmt->bssid, assoc_data->bss->bssid); ++ elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, ++ mgmt->bssid, assoc_data->bss->bssid); ++ ++ if (!elems) ++ return false; + + if (elems->aid_resp) + aid = le16_to_cpu(elems->aid_resp->aid); +@@ -3340,7 +3343,8 @@ static bool ieee80211_assoc_success(stru + + if (!is_s1g && !elems->supp_rates) { + sdata_info(sdata, "no SuppRates element in AssocResp\n"); +- return false; ++ ret = false; ++ goto out; + } + + sdata->vif.bss_conf.aid = aid; +@@ -3362,7 +3366,7 @@ static bool ieee80211_assoc_success(stru + (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && + (!elems->vht_cap_elem || !elems->vht_operation)))) { + const struct cfg80211_bss_ies *ies; +- struct ieee802_11_elems bss_elems; ++ struct ieee802_11_elems *bss_elems; + + rcu_read_lock(); + ies = rcu_dereference(cbss->ies); +@@ -3373,13 +3377,17 @@ static bool ieee80211_assoc_success(stru + if (!bss_ies) + return false; + +- ieee802_11_parse_elems(bss_ies->data, bss_ies->len, +- false, &bss_elems, +- mgmt->bssid, +- assoc_data->bss->bssid); ++ bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, ++ false, mgmt->bssid, ++ assoc_data->bss->bssid); ++ if (!bss_elems) { ++ ret = false; ++ goto out; ++ } ++ + if (assoc_data->wmm && +- !elems->wmm_param && bss_elems.wmm_param) { +- elems->wmm_param = bss_elems.wmm_param; ++ !elems->wmm_param && bss_elems->wmm_param) { ++ elems->wmm_param = bss_elems->wmm_param; + sdata_info(sdata, + "AP bug: WMM param missing from AssocResp\n"); + } +@@ -3388,30 +3396,32 @@ static bool ieee80211_assoc_success(stru + * Also check if we requested HT/VHT, otherwise the AP doesn't + * have to include the IEs in the (re)association response. + */ +- if (!elems->ht_cap_elem && bss_elems.ht_cap_elem && ++ if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { +- elems->ht_cap_elem = bss_elems.ht_cap_elem; ++ elems->ht_cap_elem = bss_elems->ht_cap_elem; + sdata_info(sdata, + "AP bug: HT capability missing from AssocResp\n"); + } +- if (!elems->ht_operation && bss_elems.ht_operation && ++ if (!elems->ht_operation && bss_elems->ht_operation && + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { +- elems->ht_operation = bss_elems.ht_operation; ++ elems->ht_operation = bss_elems->ht_operation; + sdata_info(sdata, + "AP bug: HT operation missing from AssocResp\n"); + } +- if (!elems->vht_cap_elem && bss_elems.vht_cap_elem && ++ if (!elems->vht_cap_elem && bss_elems->vht_cap_elem && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { +- elems->vht_cap_elem = bss_elems.vht_cap_elem; ++ elems->vht_cap_elem = bss_elems->vht_cap_elem; + sdata_info(sdata, + "AP bug: VHT capa missing from AssocResp\n"); + } +- if (!elems->vht_operation && bss_elems.vht_operation && ++ if (!elems->vht_operation && bss_elems->vht_operation && + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { +- elems->vht_operation = bss_elems.vht_operation; ++ elems->vht_operation = bss_elems->vht_operation; + sdata_info(sdata, + "AP bug: VHT operation missing from AssocResp\n"); + } ++ ++ kfree(bss_elems); + } + + /* +@@ -3656,6 +3666,7 @@ static bool ieee80211_assoc_success(stru + + ret = true; + out: ++ kfree(elems); + kfree(bss_ies); + return ret; + } +@@ -3667,7 +3678,7 @@ static void ieee80211_rx_mgmt_assoc_resp + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; + u16 capab_info, status_code, aid; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + int ac, uapsd_queues = -1; + u8 *pos; + bool reassoc; +@@ -3724,14 +3735,16 @@ static void ieee80211_rx_mgmt_assoc_resp + fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) + return; + +- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, +- mgmt->bssid, assoc_data->bss->bssid); ++ elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, ++ mgmt->bssid, assoc_data->bss->bssid); ++ if (!elems) ++ goto notify_driver; + + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && +- elems.timeout_int && +- elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { ++ elems->timeout_int && ++ elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; +- tu = le32_to_cpu(elems.timeout_int->value); ++ tu = le32_to_cpu(elems->timeout_int->value); + ms = tu * 1024 / 1000; + sdata_info(sdata, + "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", +@@ -3751,7 +3764,7 @@ static void ieee80211_rx_mgmt_assoc_resp + event.u.mlme.reason = status_code; + drv_event_callback(sdata->local, sdata, &event); + } else { +- if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) { ++ if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) { + /* oops -- internal error -- send timeout for now */ + ieee80211_destroy_assoc_data(sdata, false, false); + cfg80211_assoc_timeout(sdata->dev, cbss); +@@ -3781,6 +3794,7 @@ static void ieee80211_rx_mgmt_assoc_resp + ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len); + notify_driver: + drv_mgd_complete_tx(sdata->local, sdata, &info); ++ kfree(elems); + } + + static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, +@@ -3985,7 +3999,7 @@ static void ieee80211_rx_mgmt_beacon(str + struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_mgmt *mgmt = (void *) hdr; + size_t baselen; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; +@@ -4031,15 +4045,16 @@ static void ieee80211_rx_mgmt_beacon(str + + if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && + ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { +- ieee802_11_parse_elems(variable, +- len - baselen, false, &elems, +- bssid, +- ifmgd->assoc_data->bss->bssid); ++ elems = ieee802_11_parse_elems(variable, len - baselen, false, ++ bssid, ++ ifmgd->assoc_data->bss->bssid); ++ if (!elems) ++ return; + + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); + +- if (elems.dtim_period) +- ifmgd->dtim_period = elems.dtim_period; ++ if (elems->dtim_period) ++ ifmgd->dtim_period = elems->dtim_period; + ifmgd->have_beacon = true; + ifmgd->assoc_data->need_beacon = false; + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { +@@ -4047,17 +4062,17 @@ static void ieee80211_rx_mgmt_beacon(str + le64_to_cpu(mgmt->u.beacon.timestamp); + sdata->vif.bss_conf.sync_device_ts = + rx_status->device_timestamp; +- sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; ++ sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; + } + +- if (elems.mbssid_config_ie) ++ if (elems->mbssid_config_ie) + bss_conf->profile_periodicity = +- elems.mbssid_config_ie->profile_periodicity; ++ elems->mbssid_config_ie->profile_periodicity; + else + bss_conf->profile_periodicity = 0; + +- if (elems.ext_capab_len >= 11 && +- (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) ++ if (elems->ext_capab_len >= 11 && ++ (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) + bss_conf->ema_ap = true; + else + bss_conf->ema_ap = false; +@@ -4066,6 +4081,7 @@ static void ieee80211_rx_mgmt_beacon(str + ifmgd->assoc_data->timeout = jiffies; + ifmgd->assoc_data->timeout_started = true; + run_again(sdata, ifmgd->assoc_data->timeout); ++ kfree(elems); + return; + } + +@@ -4097,14 +4113,15 @@ static void ieee80211_rx_mgmt_beacon(str + */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); +- ieee802_11_parse_elems_crc(variable, +- len - baselen, false, &elems, +- care_about_ies, ncrc, +- mgmt->bssid, bssid); +- ncrc = elems.crc; ++ elems = ieee802_11_parse_elems_crc(variable, len - baselen, ++ false, care_about_ies, ncrc, ++ mgmt->bssid, bssid); ++ if (!elems) ++ return; ++ ncrc = elems->crc; + + if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && +- ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { ++ ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) { + if (local->hw.conf.dynamic_ps_timeout > 0) { + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; +@@ -4174,12 +4191,12 @@ static void ieee80211_rx_mgmt_beacon(str + le64_to_cpu(mgmt->u.beacon.timestamp); + sdata->vif.bss_conf.sync_device_ts = + rx_status->device_timestamp; +- sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; ++ sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; + } + + if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) || + ieee80211_is_s1g_short_beacon(mgmt->frame_control)) +- return; ++ goto free; + ifmgd->beacon_crc = ncrc; + ifmgd->beacon_crc_valid = true; + +@@ -4187,12 +4204,12 @@ static void ieee80211_rx_mgmt_beacon(str + + ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, + rx_status->device_timestamp, +- &elems, true); ++ elems, true); + + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && +- ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, +- elems.wmm_param_len, +- elems.mu_edca_param_set)) ++ ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, ++ elems->wmm_param_len, ++ elems->mu_edca_param_set)) + changed |= BSS_CHANGED_QOS; + + /* +@@ -4201,7 +4218,7 @@ static void ieee80211_rx_mgmt_beacon(str + */ + if (!ifmgd->have_beacon) { + /* a few bogus AP send dtim_period = 0 or no TIM IE */ +- bss_conf->dtim_period = elems.dtim_period ?: 1; ++ bss_conf->dtim_period = elems->dtim_period ?: 1; + + changed |= BSS_CHANGED_BEACON_INFO; + ifmgd->have_beacon = true; +@@ -4213,9 +4230,9 @@ static void ieee80211_rx_mgmt_beacon(str + ieee80211_recalc_ps_vif(sdata); + } + +- if (elems.erp_info) { ++ if (elems->erp_info) { + erp_valid = true; +- erp_value = elems.erp_info[0]; ++ erp_value = elems->erp_info[0]; + } else { + erp_valid = false; + } +@@ -4228,12 +4245,12 @@ static void ieee80211_rx_mgmt_beacon(str + mutex_lock(&local->sta_mtx); + sta = sta_info_get(sdata, bssid); + +- changed |= ieee80211_recalc_twt_req(sdata, sta, &elems); ++ changed |= ieee80211_recalc_twt_req(sdata, sta, elems); + +- if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem, +- elems.vht_cap_elem, elems.ht_operation, +- elems.vht_operation, elems.he_operation, +- elems.s1g_oper, bssid, &changed)) { ++ if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem, ++ elems->vht_cap_elem, elems->ht_operation, ++ elems->vht_operation, elems->he_operation, ++ elems->s1g_oper, bssid, &changed)) { + mutex_unlock(&local->sta_mtx); + sdata_info(sdata, + "failed to follow AP %pM bandwidth change, disconnect\n", +@@ -4245,21 +4262,23 @@ static void ieee80211_rx_mgmt_beacon(str + sizeof(deauth_buf), true, + WLAN_REASON_DEAUTH_LEAVING, + false); +- return; ++ goto free; + } + +- if (sta && elems.opmode_notif) +- ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, ++ if (sta && elems->opmode_notif) ++ ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif, + rx_status->band); + mutex_unlock(&local->sta_mtx); + + changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt, +- elems.country_elem, +- elems.country_elem_len, +- elems.pwr_constr_elem, +- elems.cisco_dtpc_elem); ++ elems->country_elem, ++ elems->country_elem_len, ++ elems->pwr_constr_elem, ++ elems->cisco_dtpc_elem); + + ieee80211_bss_info_change_notify(sdata, changed); ++free: ++ kfree(elems); + } + + void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, +@@ -4288,7 +4307,6 @@ void ieee80211_sta_rx_queued_mgmt(struct + struct ieee80211_rx_status *rx_status; + struct ieee80211_mgmt *mgmt; + u16 fc; +- struct ieee802_11_elems elems; + int ies_len; + + rx_status = (struct ieee80211_rx_status *) skb->cb; +@@ -4320,6 +4338,8 @@ void ieee80211_sta_rx_queued_mgmt(struct + break; + case IEEE80211_STYPE_ACTION: + if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { ++ struct ieee802_11_elems *elems; ++ + ies_len = skb->len - + offsetof(struct ieee80211_mgmt, + u.action.u.chan_switch.variable); +@@ -4328,18 +4348,21 @@ void ieee80211_sta_rx_queued_mgmt(struct + break; + + /* CSA IE cannot be overridden, no need for BSSID */ +- ieee802_11_parse_elems( +- mgmt->u.action.u.chan_switch.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems( ++ mgmt->u.action.u.chan_switch.variable, ++ ies_len, true, mgmt->bssid, NULL); + +- if (elems.parse_error) ++ if (!elems || elems->parse_error) + break; + + ieee80211_sta_process_chanswitch(sdata, + rx_status->mactime, + rx_status->device_timestamp, +- &elems, false); ++ elems, false); ++ kfree(elems); + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { ++ struct ieee802_11_elems *elems; ++ + ies_len = skb->len - + offsetof(struct ieee80211_mgmt, + u.action.u.ext_chan_switch.variable); +@@ -4351,21 +4374,22 @@ void ieee80211_sta_rx_queued_mgmt(struct + * extended CSA IE can't be overridden, no need for + * BSSID + */ +- ieee802_11_parse_elems( +- mgmt->u.action.u.ext_chan_switch.variable, +- ies_len, true, &elems, mgmt->bssid, NULL); ++ elems = ieee802_11_parse_elems( ++ mgmt->u.action.u.ext_chan_switch.variable, ++ ies_len, true, mgmt->bssid, NULL); + +- if (elems.parse_error) ++ if (!elems || elems->parse_error) + break; + + /* for the handling code pretend this was also an IE */ +- elems.ext_chansw_ie = ++ elems->ext_chansw_ie = + &mgmt->u.action.u.ext_chan_switch.data; + + ieee80211_sta_process_chanswitch(sdata, + rx_status->mactime, + rx_status->device_timestamp, +- &elems, false); ++ elems, false); ++ kfree(elems); + } + break; + } +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -9,7 +9,7 @@ + * Copyright 2007, Michael Wu + * Copyright 2013-2015 Intel Mobile Communications GmbH + * Copyright 2016-2017 Intel Deutschland GmbH +- * Copyright (C) 2018-2020 Intel Corporation ++ * Copyright (C) 2018-2021 Intel Corporation + */ + + #include +@@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee802 + }; + bool signal_valid; + struct ieee80211_sub_if_data *scan_sdata; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + size_t baselen; + u8 *elements; + +@@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee802 + if (baselen > len) + return NULL; + +- ieee802_11_parse_elems(elements, len - baselen, false, &elems, +- mgmt->bssid, cbss->bssid); ++ elems = ieee802_11_parse_elems(elements, len - baselen, false, ++ mgmt->bssid, cbss->bssid); ++ if (!elems) ++ return NULL; + + /* In case the signal is invalid update the status */ + signal_valid = channel == cbss->channel; +@@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee802 + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; + + bss = (void *)cbss->priv; +- ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon); ++ ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon); + + list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) { + non_tx_bss = (void *)non_tx_cbss->priv; + +- ieee80211_update_bss_from_elems(local, non_tx_bss, &elems, ++ ieee80211_update_bss_from_elems(local, non_tx_bss, elems, + rx_status, beacon); + } + ++ kfree(elems); ++ + return bss; + } + +--- a/net/mac80211/tdls.c ++++ b/net/mac80211/tdls.c +@@ -6,7 +6,7 @@ + * Copyright 2014, Intel Corporation + * Copyright 2014 Intel Mobile Communications GmbH + * Copyright 2015 - 2016 Intel Deutschland GmbH +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019, 2021 Intel Corporation + */ + + #include +@@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_re + struct sk_buff *skb) + { + struct ieee80211_local *local = sdata->local; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems = NULL; + struct sta_info *sta; + struct ieee80211_tdls_data *tf = (void *)skb->data; + bool local_initiator; +@@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_re + goto call_drv; + } + +- ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, +- skb->len - baselen, false, &elems, +- NULL, NULL); +- if (elems.parse_error) { ++ elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, ++ skb->len - baselen, false, NULL, NULL); ++ if (!elems) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (elems->parse_error) { + tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); + ret = -EINVAL; + goto out; + } + +- if (!elems.ch_sw_timing || !elems.lnk_id) { ++ if (!elems->ch_sw_timing || !elems->lnk_id) { + tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); + ret = -EINVAL; + goto out; +@@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_re + + /* validate the initiator is set correctly */ + local_initiator = +- !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); ++ !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); + if (local_initiator == sta->sta.tdls_initiator) { + tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); + ret = -EINVAL; + goto out; + } + +- params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); +- params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); ++ params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); ++ params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); + + params.tmpl_skb = + ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); +@@ -1763,6 +1767,7 @@ call_drv: + out: + mutex_unlock(&local->sta_mtx); + dev_kfree_skb_any(params.tmpl_skb); ++ kfree(elems); + return ret; + } + +@@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_re + struct sk_buff *skb) + { + struct ieee80211_local *local = sdata->local; +- struct ieee802_11_elems elems; ++ struct ieee802_11_elems *elems; + struct cfg80211_chan_def chandef; + struct ieee80211_channel *chan; + enum nl80211_channel_type chan_type; +@@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_re + return -EINVAL; + } + +- ieee802_11_parse_elems(tf->u.chan_switch_req.variable, +- skb->len - baselen, false, &elems, NULL, NULL); +- if (elems.parse_error) { ++ elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable, ++ skb->len - baselen, false, NULL, NULL); ++ if (!elems) ++ return -ENOMEM; ++ ++ if (elems->parse_error) { + tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + +- if (!elems.ch_sw_timing || !elems.lnk_id) { ++ if (!elems->ch_sw_timing || !elems->lnk_id) { + tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + +- if (!elems.sec_chan_offs) { ++ if (!elems->sec_chan_offs) { + chan_type = NL80211_CHAN_HT20; + } else { +- switch (elems.sec_chan_offs->sec_chan_offs) { ++ switch (elems->sec_chan_offs->sec_chan_offs) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + chan_type = NL80211_CHAN_HT40PLUS; + break; +@@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_re + if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef, + sdata->wdev.iftype)) { + tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + + mutex_lock(&local->sta_mtx); +@@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_re + + /* validate the initiator is set correctly */ + local_initiator = +- !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); ++ !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); + if (local_initiator == sta->sta.tdls_initiator) { + tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); + ret = -EINVAL; +@@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_re + } + + /* peer should have known better */ +- if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs && +- elems.sec_chan_offs->sec_chan_offs) { ++ if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs && ++ elems->sec_chan_offs->sec_chan_offs) { + tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n"); + ret = -ENOTSUPP; + goto out; + } + + params.chandef = &chandef; +- params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); +- params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); ++ params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); ++ params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); + + params.tmpl_skb = + ieee80211_tdls_ch_sw_resp_tmpl_get(sta, +@@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_re + out: + mutex_unlock(&local->sta_mtx); + dev_kfree_skb_any(params.tmpl_skb); ++free: ++ kfree(elems); + return ret; + } + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1399,8 +1399,8 @@ _ieee802_11_parse_elems_crc(const u8 *st + + static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, + struct ieee802_11_elems *elems, +- u8 *transmitter_bssid, +- u8 *bss_bssid, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid, + u8 *nontransmitted_profile) + { + const struct element *elem, *sub; +@@ -1465,16 +1465,20 @@ static size_t ieee802_11_find_bssid_prof + return found ? profile_len : 0; + } + +-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, +- struct ieee802_11_elems *elems, +- u64 filter, u32 crc, u8 *transmitter_bssid, +- u8 *bss_bssid) ++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, ++ bool action, u64 filter, ++ u32 crc, ++ const u8 *transmitter_bssid, ++ const u8 *bss_bssid) + { ++ struct ieee802_11_elems *elems; + const struct element *non_inherit = NULL; + u8 *nontransmitted_profile; + int nontransmitted_profile_len = 0; + +- memset(elems, 0, sizeof(*elems)); ++ elems = kzalloc(sizeof(*elems), GFP_ATOMIC); ++ if (!elems) ++ return NULL; + elems->ie_start = start; + elems->total_len = len; + +@@ -1521,6 +1525,8 @@ void ieee802_11_parse_elems_crc(const u8 + kfree(nontransmitted_profile); + + elems->crc = crc; ++ ++ return elems; + } + + void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, diff --git a/package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch b/package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch new file mode 100644 index 000000000..d2a43304b --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch @@ -0,0 +1,118 @@ +From 6d945a33f2b0aa24fc210dadaa0af3e8218e7002 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 25 Mar 2022 11:42:41 +0100 +Subject: [PATCH] mac80211: introduce BSS color collision detection + +Add ieee80211_rx_check_bss_color_collision routine in order to introduce +BSS color collision detection in mac80211 if it is not supported in HW/FW +(e.g. for mt7915 chipset). +Add IEEE80211_HW_DETECTS_COLOR_COLLISION flag to let the driver notify +BSS color collision detection is supported in HW/FW. Set this for ath11k +which apparently didn't need this code. + +Tested-by: Peter Chiu +Co-developed-by: Ryder Lee +Signed-off-by: Ryder Lee +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/a05eeeb1841a84560dc5aaec77894fcb69a54f27.1648204871.git.lorenzo@kernel.org +[clarify commit message a bit, move flag to mac80211] +Signed-off-by: Johannes Berg +--- + drivers/net/wireless/ath/ath11k/mac.c | 5 ++- + include/net/mac80211.h | 4 +++ + net/mac80211/debugfs.c | 1 + + net/mac80211/rx.c | 46 +++++++++++++++++++++++++++ + 4 files changed, 55 insertions(+), 1 deletion(-) + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -2418,6 +2418,9 @@ struct ieee80211_txq { + * usage and 802.11 frames with %RX_FLAG_ONLY_MONITOR set for monitor to + * the stack. + * ++ * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color ++ * collision detection and doesn't need it in software. ++ * + * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays + */ + enum ieee80211_hw_flags { +@@ -2473,6 +2476,7 @@ enum ieee80211_hw_flags { + IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, + IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, + IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP, ++ IEEE80211_HW_DETECTS_COLOR_COLLISION, + + /* keep last, obviously */ + NUM_IEEE80211_HW_FLAGS +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -494,6 +494,7 @@ static const char *hw_flag_names[] = { + FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), + FLAG(SUPPORTS_RX_DECAP_OFFLOAD), + FLAG(SUPPORTS_CONC_MON_RX_DECAP), ++ FLAG(DETECTS_COLOR_COLLISION), + #undef FLAG + }; + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3181,6 +3181,49 @@ static void ieee80211_process_sa_query_r + ieee80211_tx_skb(sdata, skb); + } + ++static void ++ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; ++ const struct element *ie; ++ size_t baselen; ++ ++ if (!wiphy_ext_feature_isset(rx->local->hw.wiphy, ++ NL80211_EXT_FEATURE_BSS_COLOR)) ++ return; ++ ++ if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) ++ return; ++ ++ if (rx->sdata->vif.csa_active) ++ return; ++ ++ baselen = mgmt->u.beacon.variable - rx->skb->data; ++ if (baselen > rx->skb->len) ++ return; ++ ++ ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ++ mgmt->u.beacon.variable, ++ rx->skb->len - baselen); ++ if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) && ++ ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) { ++ struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf; ++ const struct ieee80211_he_operation *he_oper; ++ u8 color; ++ ++ he_oper = (void *)(ie->data + 1); ++ if (le32_get_bits(he_oper->he_oper_params, ++ IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED)) ++ return; ++ ++ color = le32_get_bits(he_oper->he_oper_params, ++ IEEE80211_HE_OPERATION_BSS_COLOR_MASK); ++ if (color == bss_conf->he_bss_color.color) ++ ieeee80211_obss_color_collision_notify(&rx->sdata->vif, ++ BIT_ULL(color)); ++ } ++} ++ + static ieee80211_rx_result debug_noinline + ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) + { +@@ -3206,6 +3249,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802 + !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { + int sig = 0; + ++ /* sw bss color collision detection */ ++ ieee80211_rx_check_bss_color_collision(rx); ++ + if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && + !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) + sig = status->signal; diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch new file mode 100644 index 000000000..83d820ca2 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch @@ -0,0 +1,115 @@ +From: Johannes Berg +Date: Fri, 1 Oct 2021 21:11:08 +0200 +Subject: [PATCH] mac80211: fix memory leaks with element parsing + +commit 8223ac199a3849257e86ec27865dc63f034b1cf1 upstream. + +My previous commit 5d24828d05f3 ("mac80211: always allocate +struct ieee802_11_elems") had a few bugs and leaked the new +allocated struct in a few error cases, fix that. + +Fixes: 5d24828d05f3 ("mac80211: always allocate struct ieee802_11_elems") +Signed-off-by: Johannes Berg +Link: https://lore.kernel.org/r/20211001211108.9839928e42e0.Ib81ca187d3d3af7ed1bfeac2e00d08a4637c8025@changeid +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -499,13 +499,14 @@ void ieee80211_process_addba_request(str + elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, + ies_len, true, mgmt->bssid, NULL); + if (!elems || elems->parse_error) +- return; ++ goto free; + } + + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, + start_seq_num, ba_policy, tid, + buf_size, true, false, + elems ? elems->addba_ext_ie : NULL); ++free: + kfree(elems); + } + +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -1659,11 +1659,11 @@ void ieee80211_ibss_rx_queued_mgmt(struc + mgmt->u.action.u.chan_switch.variable, + ies_len, true, mgmt->bssid, NULL); + +- if (!elems || elems->parse_error) +- break; +- +- ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, +- rx_status, elems); ++ if (elems && !elems->parse_error) ++ ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, ++ skb->len, ++ rx_status, ++ elems); + kfree(elems); + break; + } +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3374,8 +3374,10 @@ static bool ieee80211_assoc_success(stru + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, + GFP_ATOMIC); + rcu_read_unlock(); +- if (!bss_ies) +- return false; ++ if (!bss_ies) { ++ ret = false; ++ goto out; ++ } + + bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, + false, mgmt->bssid, +@@ -4352,13 +4354,11 @@ void ieee80211_sta_rx_queued_mgmt(struct + mgmt->u.action.u.chan_switch.variable, + ies_len, true, mgmt->bssid, NULL); + +- if (!elems || elems->parse_error) +- break; +- +- ieee80211_sta_process_chanswitch(sdata, +- rx_status->mactime, +- rx_status->device_timestamp, +- elems, false); ++ if (elems && !elems->parse_error) ++ ieee80211_sta_process_chanswitch(sdata, ++ rx_status->mactime, ++ rx_status->device_timestamp, ++ elems, false); + kfree(elems); + } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { + struct ieee802_11_elems *elems; +@@ -4378,17 +4378,17 @@ void ieee80211_sta_rx_queued_mgmt(struct + mgmt->u.action.u.ext_chan_switch.variable, + ies_len, true, mgmt->bssid, NULL); + +- if (!elems || elems->parse_error) +- break; ++ if (elems && !elems->parse_error) { ++ /* for the handling code pretend it was an IE */ ++ elems->ext_chansw_ie = ++ &mgmt->u.action.u.ext_chan_switch.data; ++ ++ ieee80211_sta_process_chanswitch(sdata, ++ rx_status->mactime, ++ rx_status->device_timestamp, ++ elems, false); ++ } + +- /* for the handling code pretend this was also an IE */ +- elems->ext_chansw_ie = +- &mgmt->u.action.u.ext_chan_switch.data; +- +- ieee80211_sta_process_chanswitch(sdata, +- rx_status->mactime, +- rx_status->device_timestamp, +- elems, false); + kfree(elems); + } + break; diff --git a/package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch b/package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch new file mode 100644 index 000000000..c1026b427 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch @@ -0,0 +1,41 @@ +From: Johannes Berg +Date: Wed, 28 Sep 2022 21:56:15 +0200 +Subject: [PATCH] wifi: cfg80211: fix u8 overflow in + cfg80211_update_notlisted_nontrans() + +commit aebe9f4639b13a1f4e9a6b42cdd2e38c617b442d upstream. + +In the copy code of the elements, we do the following calculation +to reach the end of the MBSSID element: + + /* copy the IEs after MBSSID */ + cpy_len = mbssid[1] + 2; + +This looks fine, however, cpy_len is a u8, the same as mbssid[1], +so the addition of two can overflow. In this case the subsequent +memcpy() will overflow the allocated buffer, since it copies 256 +bytes too much due to the way the allocation and memcpy() sizes +are calculated. + +Fix this by using size_t for the cpy_len variable. + +This fixes CVE-2022-41674. + +Reported-by: Soenke Huster +Tested-by: Soenke Huster +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") +Reviewed-by: Kees Cook +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -2229,7 +2229,7 @@ cfg80211_update_notlisted_nontrans(struc + size_t new_ie_len; + struct cfg80211_bss_ies *new_ies; + const struct cfg80211_bss_ies *old; +- u8 cpy_len; ++ size_t cpy_len; + + lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock); + diff --git a/package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch b/package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch new file mode 100644 index 000000000..4f0b8473e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch @@ -0,0 +1,47 @@ +From: Johannes Berg +Date: Wed, 28 Sep 2022 22:01:37 +0200 +Subject: [PATCH] wifi: cfg80211/mac80211: reject bad MBSSID elements + +commit 8f033d2becc24aa6bfd2a5c104407963560caabc upstream + +Per spec, the maximum value for the MaxBSSID ('n') indicator is 8, +and the minimum is 1 since a multiple BSSID set with just one BSSID +doesn't make sense (the # of BSSIDs is limited by 2^n). + +Limit this in the parsing in both cfg80211 and mac80211, rejecting +any elements with an invalid value. + +This fixes potentially bad shifts in the processing of these inside +the cfg80211_gen_new_bssid() function later. + +I found this during the investigation of CVE-2022-41674 fixed by the +previous patch. + +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") +Fixes: 78ac51f81532 ("mac80211: support multi-bssid") +Reviewed-by: Kees Cook +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1413,6 +1413,8 @@ static size_t ieee802_11_find_bssid_prof + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) { + if (elem->datalen < 2) + continue; ++ if (elem->data[0] < 1 || elem->data[0] > 8) ++ continue; + + for_each_element(sub, elem->data + 1, elem->datalen - 1) { + u8 new_bssid[ETH_ALEN]; +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -2094,6 +2094,8 @@ static void cfg80211_parse_mbssid_data(s + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) { + if (elem->datalen < 4) + continue; ++ if (elem->data[0] < 1 || (int)elem->data[0] > 8) ++ continue; + for_each_element(sub, elem->data + 1, elem->datalen - 1) { + u8 profile_len; + diff --git a/package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch b/package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch new file mode 100644 index 000000000..c44b821e9 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch @@ -0,0 +1,94 @@ +From: Johannes Berg +Date: Wed, 28 Sep 2022 22:07:15 +0200 +Subject: [PATCH] wifi: mac80211: fix MBSSID parsing use-after-free + +commit ff05d4b45dd89b922578dac497dcabf57cf771c6 + +When we parse a multi-BSSID element, we might point some +element pointers into the allocated nontransmitted_profile. +However, we free this before returning, causing UAF when the +relevant pointers in the parsed elements are accessed. + +Fix this by not allocating the scratch buffer separately but +as part of the returned structure instead, that way, there +are no lifetime issues with it. + +The scratch buffer introduction as part of the returned data +here is taken from MLO feature work done by Ilan. + +This fixes CVE-2022-42719. + +Fixes: 5023b14cf4df ("mac80211: support profile split between elements") +Co-developed-by: Ilan Peer +Signed-off-by: Ilan Peer +Reviewed-by: Kees Cook +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1606,6 +1606,14 @@ struct ieee802_11_elems { + + /* whether a parse error occurred while retrieving these elements */ + bool parse_error; ++ ++ /* ++ * scratch buffer that can be used for various element parsing related ++ * tasks, e.g., element de-fragmentation etc. ++ */ ++ size_t scratch_len; ++ u8 *scratch_pos; ++ u8 scratch[]; + }; + + static inline struct ieee80211_local *hw_to_local( +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1478,24 +1478,25 @@ struct ieee802_11_elems *ieee802_11_pars + u8 *nontransmitted_profile; + int nontransmitted_profile_len = 0; + +- elems = kzalloc(sizeof(*elems), GFP_ATOMIC); ++ elems = kzalloc(sizeof(*elems) + len, GFP_ATOMIC); + if (!elems) + return NULL; + elems->ie_start = start; + elems->total_len = len; + +- nontransmitted_profile = kmalloc(len, GFP_ATOMIC); +- if (nontransmitted_profile) { +- nontransmitted_profile_len = +- ieee802_11_find_bssid_profile(start, len, elems, +- transmitter_bssid, +- bss_bssid, +- nontransmitted_profile); +- non_inherit = +- cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, +- nontransmitted_profile, +- nontransmitted_profile_len); +- } ++ elems->scratch_len = len; ++ elems->scratch_pos = elems->scratch; ++ ++ nontransmitted_profile = elems->scratch_pos; ++ nontransmitted_profile_len = ++ ieee802_11_find_bssid_profile(start, len, elems, ++ transmitter_bssid, ++ bss_bssid, ++ nontransmitted_profile); ++ non_inherit = ++ cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, ++ nontransmitted_profile, ++ nontransmitted_profile_len); + + crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter, + crc, non_inherit); +@@ -1524,8 +1525,6 @@ struct ieee802_11_elems *ieee802_11_pars + offsetofend(struct ieee80211_bssid_index, dtim_count)) + elems->dtim_count = elems->bssid_index->dtim_count; + +- kfree(nontransmitted_profile); +- + elems->crc = crc; + + return elems; diff --git a/package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch b/package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch new file mode 100644 index 000000000..da94840da --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch @@ -0,0 +1,41 @@ +From: Johannes Berg +Date: Thu, 29 Sep 2022 21:50:44 +0200 +Subject: [PATCH] wifi: cfg80211: ensure length byte is present before + access + +commit 567e14e39e8f8c6997a1378bc3be615afca86063 upstream. + +When iterating the elements here, ensure the length byte is +present before checking it to see if the entire element will +fit into the buffer. + +Longer term, we should rewrite this code using the type-safe +element iteration macros that check all of this. + +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") +Reported-by: Soenke Huster +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -304,7 +304,8 @@ static size_t cfg80211_gen_new_ie(const + tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); + tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie; + +- while (tmp_old + tmp_old[1] + 2 - ie <= ielen) { ++ while (tmp_old + 2 - ie <= ielen && ++ tmp_old + tmp_old[1] + 2 - ie <= ielen) { + if (tmp_old[0] == 0) { + tmp_old++; + continue; +@@ -364,7 +365,8 @@ static size_t cfg80211_gen_new_ie(const + * copied to new ie, skip ssid, capability, bssid-index ie + */ + tmp_new = sub_copy; +- while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { ++ while (tmp_new + 2 - sub_copy <= subie_len && ++ tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { + if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP || + tmp_new[0] == WLAN_EID_SSID)) { + memcpy(pos, tmp_new, tmp_new[1] + 2); diff --git a/package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch b/package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch new file mode 100644 index 000000000..098d3c961 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch @@ -0,0 +1,90 @@ +From: Johannes Berg +Date: Fri, 30 Sep 2022 23:44:23 +0200 +Subject: [PATCH] wifi: cfg80211: fix BSS refcounting bugs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 0b7808818cb9df6680f98996b8e9a439fa7bcc2f upstream. + +There are multiple refcounting bugs related to multi-BSSID: + - In bss_ref_get(), if the BSS has a hidden_beacon_bss, then + the bss pointer is overwritten before checking for the + transmitted BSS, which is clearly wrong. Fix this by using + the bss_from_pub() macro. + + - In cfg80211_bss_update() we copy the transmitted_bss pointer + from tmp into new, but then if we release new, we'll unref + it erroneously. We already set the pointer and ref it, but + need to NULL it since it was copied from the tmp data. + + - In cfg80211_inform_single_bss_data(), if adding to the non- + transmitted list fails, we unlink the BSS and yet still we + return it, but this results in returning an entry without + a reference. We shouldn't return it anyway if it was broken + enough to not get added there. + +This fixes CVE-2022-42720. + +Reported-by: Sönke Huster +Tested-by: Sönke Huster +Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS") +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cf + lockdep_assert_held(&rdev->bss_lock); + + bss->refcount++; +- if (bss->pub.hidden_beacon_bss) { +- bss = container_of(bss->pub.hidden_beacon_bss, +- struct cfg80211_internal_bss, +- pub); +- bss->refcount++; +- } +- if (bss->pub.transmitted_bss) { +- bss = container_of(bss->pub.transmitted_bss, +- struct cfg80211_internal_bss, +- pub); +- bss->refcount++; +- } ++ ++ if (bss->pub.hidden_beacon_bss) ++ bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++; ++ ++ if (bss->pub.transmitted_bss) ++ bss_from_pub(bss->pub.transmitted_bss)->refcount++; + } + + static inline void bss_ref_put(struct cfg80211_registered_device *rdev, +@@ -1736,6 +1730,8 @@ cfg80211_bss_update(struct cfg80211_regi + new->refcount = 1; + INIT_LIST_HEAD(&new->hidden_list); + INIT_LIST_HEAD(&new->pub.nontrans_list); ++ /* we'll set this later if it was non-NULL */ ++ new->pub.transmitted_bss = NULL; + + if (rcu_access_pointer(tmp->pub.proberesp_ies)) { + hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); +@@ -1973,11 +1969,18 @@ cfg80211_inform_single_bss_data(struct w + /* this is a nontransmitting bss, we need to add it to + * transmitting bss' list if it is not there + */ ++ spin_lock_bh(&rdev->bss_lock); + if (cfg80211_add_nontrans_list(non_tx_data->tx_bss, + &res->pub)) { +- if (__cfg80211_unlink_bss(rdev, res)) ++ if (__cfg80211_unlink_bss(rdev, res)) { + rdev->bss_generation++; ++ res = NULL; ++ } + } ++ spin_unlock_bh(&rdev->bss_lock); ++ ++ if (!res) ++ return NULL; + } + + trace_cfg80211_return_bss(&res->pub); diff --git a/package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch b/package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch new file mode 100644 index 000000000..db0e51edc --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch @@ -0,0 +1,48 @@ +From: Johannes Berg +Date: Sat, 1 Oct 2022 00:01:44 +0200 +Subject: [PATCH] wifi: cfg80211: avoid nontransmitted BSS list + corruption +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit bcca852027e5878aec911a347407ecc88d6fff7f upstream. + +If a non-transmitted BSS shares enough information (both +SSID and BSSID!) with another non-transmitted BSS of a +different AP, then we can find and update it, and then +try to add it to the non-transmitted BSS list. We do a +search for it on the transmitted BSS, but if it's not +there (but belongs to another transmitted BSS), the list +gets corrupted. + +Since this is an erroneous situation, simply fail the +list insertion in this case and free the non-transmitted +BSS. + +This fixes CVE-2022-42721. + +Reported-by: Sönke Huster +Tested-by: Sönke Huster +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -425,6 +425,15 @@ cfg80211_add_nontrans_list(struct cfg802 + + rcu_read_unlock(); + ++ /* ++ * This is a bit weird - it's not on the list, but already on another ++ * one! The only way that could happen is if there's some BSSID/SSID ++ * shared by multiple APs in their multi-BSSID profiles, potentially ++ * with hidden SSID mixed in ... ignore it. ++ */ ++ if (!list_empty(&nontrans_bss->nontrans_list)) ++ return -EINVAL; ++ + /* add to the list */ + list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list); + return 0; diff --git a/package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch b/package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch new file mode 100644 index 000000000..053cd4d39 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch @@ -0,0 +1,31 @@ +From: Johannes Berg +Date: Wed, 5 Oct 2022 15:10:09 +0200 +Subject: [PATCH] wifi: mac80211_hwsim: avoid mac80211 warning on bad + rate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 1833b6f46d7e2830251a063935ab464256defe22 upstream. + +If the tool on the other side (e.g. wmediumd) gets confused +about the rate, we hit a warning in mac80211. Silence that +by effectively duplicating the check here and dropping the +frame silently (in mac80211 it's dropped with the warning). + +Reported-by: Sönke Huster +Tested-by: Sönke Huster +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -3757,6 +3757,8 @@ static int hwsim_cloned_frame_received_n + + rx_status.band = channel->band; + rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); ++ if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) ++ goto out; + rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); + + hdr = (void *)skb->data; diff --git a/package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch b/package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch new file mode 100644 index 000000000..8b93da437 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch @@ -0,0 +1,52 @@ +From: Johannes Berg +Date: Wed, 5 Oct 2022 21:24:10 +0200 +Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for + P2P-device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit b2d03cabe2b2e150ff5a381731ea0355459be09f upstream. + +If beacon protection is active but the beacon cannot be +decrypted or is otherwise malformed, we call the cfg80211 +API to report this to userspace, but that uses a netdev +pointer, which isn't present for P2P-Device. Fix this to +call it only conditionally to ensure cfg80211 won't crash +in the case of P2P-Device. + +This fixes CVE-2022-42722. + +Reported-by: Sönke Huster +Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space") +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1987,10 +1987,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_ + + if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS || + mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + +- NUM_DEFAULT_BEACON_KEYS) { +- cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, +- skb->data, +- skb->len); ++ NUM_DEFAULT_BEACON_KEYS) { ++ if (rx->sdata->dev) ++ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, ++ skb->data, ++ skb->len); + return RX_DROP_MONITOR; /* unexpected BIP keyidx */ + } + +@@ -2138,7 +2139,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_ + /* either the frame has been decrypted or will be dropped */ + status->flag |= RX_FLAG_DECRYPTED; + +- if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE)) ++ if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE && ++ rx->sdata->dev)) + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, + skb->data, skb->len); + diff --git a/package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch b/package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch new file mode 100644 index 000000000..303b6e648 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch @@ -0,0 +1,85 @@ +From: Johannes Berg +Date: Wed, 5 Oct 2022 23:11:43 +0200 +Subject: [PATCH] wifi: cfg80211: update hidden BSSes to avoid WARN_ON +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit c90b93b5b782891ebfda49d4e5da36632fefd5d1 upstream. + +When updating beacon elements in a non-transmitted BSS, +also update the hidden sub-entries to the same beacon +elements, so that a future update through other paths +won't trigger a WARN_ON(). + +The warning is triggered because the beacon elements in +the hidden BSSes that are children of the BSS should +always be the same as in the parent. + +Reported-by: Sönke Huster +Tested-by: Sönke Huster +Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -1602,6 +1602,23 @@ struct cfg80211_non_tx_bss { + u8 bssid_index; + }; + ++static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known, ++ const struct cfg80211_bss_ies *new_ies, ++ const struct cfg80211_bss_ies *old_ies) ++{ ++ struct cfg80211_internal_bss *bss; ++ ++ /* Assign beacon IEs to all sub entries */ ++ list_for_each_entry(bss, &known->hidden_list, hidden_list) { ++ const struct cfg80211_bss_ies *ies; ++ ++ ies = rcu_access_pointer(bss->pub.beacon_ies); ++ WARN_ON(ies != old_ies); ++ ++ rcu_assign_pointer(bss->pub.beacon_ies, new_ies); ++ } ++} ++ + static bool + cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *known, +@@ -1625,7 +1642,6 @@ cfg80211_update_known_bss(struct cfg8021 + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); + } else if (rcu_access_pointer(new->pub.beacon_ies)) { + const struct cfg80211_bss_ies *old; +- struct cfg80211_internal_bss *bss; + + if (known->pub.hidden_beacon_bss && + !list_empty(&known->hidden_list)) { +@@ -1653,16 +1669,7 @@ cfg80211_update_known_bss(struct cfg8021 + if (old == rcu_access_pointer(known->pub.ies)) + rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies); + +- /* Assign beacon IEs to all sub entries */ +- list_for_each_entry(bss, &known->hidden_list, hidden_list) { +- const struct cfg80211_bss_ies *ies; +- +- ies = rcu_access_pointer(bss->pub.beacon_ies); +- WARN_ON(ies != old); +- +- rcu_assign_pointer(bss->pub.beacon_ies, +- new->pub.beacon_ies); +- } ++ cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old); + + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); +@@ -2312,6 +2319,8 @@ cfg80211_update_notlisted_nontrans(struc + } else { + old = rcu_access_pointer(nontrans_bss->beacon_ies); + rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies); ++ cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss), ++ new_ies, old); + rcu_assign_pointer(nontrans_bss->ies, new_ies); + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); diff --git a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch index c38fa13f0..f2ed528d2 100644 --- a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch +++ b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch @@ -1,22 +1,11 @@ -From: Hauke Mehrtens -Date: Mon, 24 Feb 2020 00:00:00 +0100 -Subject: [PATCH] mac80211: Allow IBSS mode and different beacon intervals - -ath10k-ct supports the combination to select IBSS (ADHOC) mode and -different beacon intervals together. mac80211 does not like this -combination, but Ben says this is ok, so remove this check. - -ath10k-ct starting with version 5.2 allows the combination of -NL80211_IFTYPE_ADHOC and beacon_int_min_gcd in ath10k_10x_ct_if_comb -which triggers this warning. Ben told me that this is not a big problem +ath10k-ct starting with version 5.2 allows the combination of +NL80211_IFTYPE_ADHOC and beacon_int_min_gcd in ath10k_10x_ct_if_comb +which triggers this warning. Ben told me that this is not a big problem and we should ignore this. ---- - net/wireless/core.c | 15 --------------- - 1 file changed, 15 deletions(-) --- a/net/wireless/core.c +++ b/net/wireless/core.c -@@ -614,21 +614,6 @@ static int wiphy_verify_combinations(str +@@ -625,21 +625,6 @@ static int wiphy_verify_combinations(str c->limits[j].max > 1)) return -EINVAL; diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch index 13b374aae..5c4b01416 100644 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch @@ -1,6 +1,6 @@ --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -4081,6 +4081,7 @@ struct mgmt_frame_regs { +@@ -3869,6 +3869,7 @@ struct mgmt_frame_regs { * (as advertised by the nl80211 feature flag.) * @get_tx_power: store the current TX power into the dbm variable; * return 0 if successful @@ -8,7 +8,7 @@ * * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting * functions to adjust rfkill hw state -@@ -4431,6 +4432,7 @@ struct cfg80211_ops { +@@ -4202,6 +4203,7 @@ struct cfg80211_ops { enum nl80211_tx_power_setting type, int mbm); int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); @@ -18,7 +18,7 @@ --- a/include/net/mac80211.h +++ b/include/net/mac80211.h -@@ -1645,6 +1645,7 @@ enum ieee80211_smps_mode { +@@ -1566,6 +1566,7 @@ enum ieee80211_smps_mode { * * @power_level: requested transmit power (in dBm), backward compatibility * value only that is set to the minimum of all interfaces @@ -26,7 +26,7 @@ * * @chandef: the channel definition to tune to * @radar_enabled: whether radar detection is enabled -@@ -1665,6 +1666,7 @@ enum ieee80211_smps_mode { +@@ -1586,6 +1587,7 @@ enum ieee80211_smps_mode { struct ieee80211_conf { u32 flags; int power_level, dynamic_ps_timeout; @@ -36,19 +36,19 @@ u8 ps_dtim_period; --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h -@@ -2749,6 +2749,9 @@ enum nl80211_commands { - * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the ack RX - * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates - * the incoming frame RX timestamp. +@@ -2615,6 +2615,9 @@ enum nl80211_commands { + * switching on a different channel during CAC detection on the selected + * radar channel. + * + * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce + * transmit power to stay within regulatory limits. u32, dBi. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3277,6 +3280,8 @@ enum nl80211_attrs { - NL80211_ATTR_TX_HW_TIMESTAMP, - NL80211_ATTR_RX_HW_TIMESTAMP, +@@ -3123,6 +3126,8 @@ enum nl80211_attrs { + + NL80211_ATTR_RADAR_BACKGROUND, + NL80211_ATTR_WIPHY_ANTENNA_GAIN, + @@ -57,7 +57,7 @@ __NL80211_ATTR_AFTER_LAST, --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2998,6 +2998,19 @@ static int ieee80211_get_tx_power(struct +@@ -2812,6 +2812,19 @@ static int ieee80211_get_tx_power(struct return 0; } @@ -77,7 +77,7 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) { struct ieee80211_local *local = wiphy_priv(wiphy); -@@ -4881,6 +4894,7 @@ const struct cfg80211_ops mac80211_confi +@@ -4516,6 +4529,7 @@ const struct cfg80211_ops mac80211_confi .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, @@ -87,7 +87,7 @@ CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump) --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -1521,6 +1521,7 @@ struct ieee80211_local { +@@ -1442,6 +1442,7 @@ struct ieee80211_local { int dynamic_ps_forced_timeout; int user_power_level; /* in dBm, for all interfaces */ @@ -119,7 +119,7 @@ if (local->hw.conf.power_level != power) { changed |= IEEE80211_CONF_CHANGE_POWER; local->hw.conf.power_level = power; -@@ -762,6 +768,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ +@@ -679,6 +685,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ IEEE80211_RADIOTAP_MCS_HAVE_BW; local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; @@ -129,15 +129,15 @@ local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -799,6 +799,7 @@ static const struct nla_policy nl80211_p - [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), - [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, - [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, +@@ -797,6 +797,7 @@ static const struct nla_policy nl80211_p + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, + [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, + [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, }; /* policy for the key attributes */ -@@ -3511,6 +3512,22 @@ static int nl80211_set_wiphy(struct sk_b +@@ -3377,6 +3378,22 @@ static int nl80211_set_wiphy(struct sk_b if (result) goto out; } diff --git a/package/kernel/mac80211/patches/subsys/401-mac80211-allow-vht-on-2g.patch b/package/kernel/mac80211/patches/subsys/600-mac80211-allow-vht-on-2g.patch similarity index 89% rename from package/kernel/mac80211/patches/subsys/401-mac80211-allow-vht-on-2g.patch rename to package/kernel/mac80211/patches/subsys/600-mac80211-allow-vht-on-2g.patch index bc929c435..e3b0692af 100644 --- a/package/kernel/mac80211/patches/subsys/401-mac80211-allow-vht-on-2g.patch +++ b/package/kernel/mac80211/patches/subsys/600-mac80211-allow-vht-on-2g.patch @@ -12,7 +12,7 @@ have_80mhz = true; --- a/net/mac80211/util.c +++ b/net/mac80211/util.c -@@ -1981,7 +1981,8 @@ static int ieee80211_build_preq_ies_band +@@ -1925,7 +1925,8 @@ static int ieee80211_build_preq_ies_band /* Check if any channel in this sband supports at least 80 MHz */ for (i = 0; i < sband->n_channels; i++) { if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | @@ -24,7 +24,7 @@ have_80mhz = true; --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c -@@ -4744,7 +4744,8 @@ static int ieee80211_prep_channel(struct +@@ -5116,7 +5116,8 @@ static int ieee80211_prep_channel(struct have_80mhz = false; for (i = 0; i < sband->n_channels; i++) { if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | diff --git a/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch b/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch deleted file mode 100644 index 26af6a2fb..000000000 --- a/package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/backport-include/linux/of_net.h -+++ /dev/null -@@ -1,26 +0,0 @@ --#ifndef _BP_OF_NET_H --#define _BP_OF_NET_H --#include_next --#include --#include -- --/* The behavior of of_get_mac_address() changed in kernel 5.2, it now -- * returns an error code and not NULL in case of an error. -- */ --#if LINUX_VERSION_IS_LESS(5,13,0) --static inline int backport_of_get_mac_address(struct device_node *np, u8 *mac_out) --{ -- const void *mac = of_get_mac_address(np); -- -- if (!mac) -- return -ENODEV; -- if (IS_ERR(mac)) -- return PTR_ERR(mac); -- ether_addr_copy(mac_out, mac); -- -- return 0; --} --#define of_get_mac_address LINUX_BACKPORT(of_get_mac_address) --#endif /* < 5.2 */ -- --#endif /* _BP_OF_NET_H */ diff --git a/package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch b/package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch new file mode 100644 index 000000000..dc2b05b1a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch @@ -0,0 +1,22 @@ +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -6027,6 +6027,11 @@ enum nl80211_feature_flags { + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * ++ * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports ++ * FILS encryption and decryption for (Re)Association Request and Response ++ * frames. Userspace has to share FILS AAD details to the driver by using ++ * @NL80211_CMD_SET_FILS_AAD. ++ * + * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC + * detection. + * +@@ -6095,6 +6100,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, ++ NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD, + NL80211_EXT_FEATURE_RADAR_BACKGROUND, + + /* add new features before the definition below */ diff --git a/package/kernel/mac80211/patches/subsys/784-ethtool_ringparam.patch b/package/kernel/mac80211/patches/subsys/784-ethtool_ringparam.patch new file mode 100644 index 000000000..f2b3050f8 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/784-ethtool_ringparam.patch @@ -0,0 +1,30 @@ +--- a/net/mac80211/ethtool.c ++++ b/net/mac80211/ethtool.c +@@ -14,7 +14,13 @@ + #include "driver-ops.h" + + static int ieee80211_set_ringparam(struct net_device *dev, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + struct ethtool_ringparam *rp) ++#else ++ struct ethtool_ringparam *rp, ++ struct kernel_ethtool_ringparam *kernel_rp, ++ struct netlink_ext_ack *extack) ++#endif + { + struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); + +@@ -25,7 +31,13 @@ static int ieee80211_set_ringparam(struc + } + + static void ieee80211_get_ringparam(struct net_device *dev, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) + struct ethtool_ringparam *rp) ++#else ++ struct ethtool_ringparam *rp, ++ struct kernel_ethtool_ringparam *kernel_rp, ++ struct netlink_ext_ack *extack) ++#endif + { + struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); + diff --git a/package/kernel/mac80211/patches/subsys/785-backport-of_get_mac_address.patch b/package/kernel/mac80211/patches/subsys/785-backport-of_get_mac_address.patch new file mode 100644 index 000000000..efec7556b --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/785-backport-of_get_mac_address.patch @@ -0,0 +1,11 @@ +--- a/backport-include/linux/of_net.h ++++ b/backport-include/linux/of_net.h +@@ -7,7 +7,7 @@ + /* The behavior of of_get_mac_address() changed in kernel 5.2, it now + * returns an error code and not NULL in case of an error. + */ +-#if LINUX_VERSION_IS_LESS(5,13,0) ++#if LINUX_VERSION_IS_LESS(5,2,0) + static inline int backport_of_get_mac_address(struct device_node *np, u8 *mac_out) + { + const void *mac = of_get_mac_address(np); diff --git a/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch b/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch index 56cc52302..a17d6f616 100644 --- a/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch +++ b/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch @@ -18,7 +18,7 @@ Signed-off-by: David Bauer --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c -@@ -254,7 +254,11 @@ static void ieee80211_send_addba_resp(st +@@ -251,7 +251,11 @@ static void ieee80211_send_addba_resp(st mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; mgmt->u.action.u.addba_resp.dialog_token = dialog_token; diff --git a/package/kernel/mac80211/patches/subsys/995-backport-pskb_pull.patch b/package/kernel/mac80211/patches/subsys/995-backport-pskb_pull.patch new file mode 100644 index 000000000..915b54a32 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/995-backport-pskb_pull.patch @@ -0,0 +1,27 @@ +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -49,7 +49,11 @@ + + if (present_fcs_len) + __pskb_trim(skb, skb->len - present_fcs_len); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + __pskb_pull(skb, rtap_space); ++#else ++ pskb_pull(skb, rtap_space); ++#endif + + hdr = (void *)skb->data; + fc = hdr->frame_control; +@@ -74,8 +78,11 @@ + + memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data, + hdrlen - IEEE80211_HT_CTL_LEN); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + __pskb_pull(skb, IEEE80211_HT_CTL_LEN); +- ++#else ++ pskb_pull(skb, IEEE80211_HT_CTL_LEN); ++#endif + return skb; + } + diff --git a/package/kernel/mac80211/patches/subsys/996-use-prandom_u32_max.patch b/package/kernel/mac80211/patches/subsys/996-use-prandom_u32_max.patch new file mode 100644 index 000000000..08d49e57a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/996-use-prandom_u32_max.patch @@ -0,0 +1,14 @@ +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -1867,7 +1867,11 @@ + + memset(sample_table, 0xff, sizeof(sample_table)); + for (col = 0; col < SAMPLE_COLUMNS; col++) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + prandom_bytes(rnd, sizeof(rnd)); ++#else ++ get_random_bytes(rnd, sizeof(rnd)); ++#endif + for (i = 0; i < MCS_GROUP_RATES; i++) { + new_idx = (i + rnd[i]) % MCS_GROUP_RATES; + while (sample_table[col][new_idx] != 0xff) diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile index 709523087..85a47ac63 100644 --- a/package/kernel/mt76/Makefile +++ b/package/kernel/mt76/Makefile @@ -1,16 +1,16 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mt76 -PKG_RELEASE=5 +PKG_RELEASE=6 PKG_LICENSE:=GPLv2 PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2022-12-09 -PKG_SOURCE_VERSION:=7fae1de12ae7832a6095fd2df198f41fabd5223d -PKG_MIRROR_HASH:=c2bf2f23265d5e181c275a62a64f487b190f19b43fc4c584b62b9e6c16e992ef +PKG_SOURCE_DATE:=2022-12-01 +PKG_SOURCE_VERSION:=cdd7229e769b65d12284ea9ebcd1cff01d3bf228 +PKG_MIRROR_HASH:=b509fd2757775bffbc6daf41408d54c6c5aeb557774710712b5288315da94a9e PKG_MAINTAINER:=Felix Fietkau PKG_USE_NINJA:=0 diff --git a/package/kernel/mt76/patches/001-mt76-mt7915-fix-changed-IEEE80211_MAX_AMPDU_BUF-defi.patch b/package/kernel/mt76/patches/001-mt76-mt7915-fix-changed-IEEE80211_MAX_AMPDU_BUF-defi.patch new file mode 100644 index 000000000..1f84c601f --- /dev/null +++ b/package/kernel/mt76/patches/001-mt76-mt7915-fix-changed-IEEE80211_MAX_AMPDU_BUF-defi.patch @@ -0,0 +1,34 @@ +From 2994307fe092a9627e12ad7cd9f32f4d36c201d8 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sun, 25 Sep 2022 15:58:37 +0200 +Subject: [PATCH] mt76: mt7915: fix changed IEEE80211_MAX_AMPDU_BUF define in + new kernel + +New kernel use IEEE80211_MAX_AMPDU_BUF_HE instead of +IEEE80211_MAX_AMPDU_BUF. +This got backported to stable kernel 5.15.61 and cause compilation +error. +Add required ifdef to handle this changed define. + +Signed-off-by: Christian Marangi +--- + mt7915/init.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/mt7915/init.c b/mt7915/init.c +index 489f6e77..1813370a 100644 +--- a/mt7915/init.c ++++ b/mt7915/init.c +@@ -327,8 +327,8 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) + struct mt7915_dev *dev = phy->dev; + + hw->queues = 4; +- hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; +- hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; ++ hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; ++ hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->netdev_features = NETIF_F_RXCSUM; + + hw->radiotap_timestamp.units_pos = +-- +2.37.2 diff --git a/package/kernel/mt76/patches/010-bypass-werror.patch b/package/kernel/mt76/patches/010-bypass-werror.patch new file mode 100644 index 000000000..536dff9e3 --- /dev/null +++ b/package/kernel/mt76/patches/010-bypass-werror.patch @@ -0,0 +1,9 @@ +--- a/Makefile ++++ b/Makefile +@@ -1,5 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0-only +-EXTRA_CFLAGS += -Werror -DCONFIG_MT76_LEDS ++EXTRA_CFLAGS += -DCONFIG_MT76_LEDS + obj-m := mt76.o + obj-$(CONFIG_MT76_USB) += mt76-usb.o + obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o diff --git a/package/kernel/mt76/patches/020-fix-crash-in-chip-reset-fail.patch b/package/kernel/mt76/patches/020-fix-crash-in-chip-reset-fail.patch new file mode 100644 index 000000000..2777d142e --- /dev/null +++ b/package/kernel/mt76/patches/020-fix-crash-in-chip-reset-fail.patch @@ -0,0 +1,11 @@ +--- a/mt7921/pci_mac.c ++++ b/mt7921/pci_mac.c +@@ -261,7 +261,7 @@ int mt7921e_mac_reset(struct mt7921_dev *dev) + + err = mt7921e_driver_own(dev); + if (err) +- return err; ++ goto out; + + err = mt7921_run_firmware(dev); + if (err) diff --git a/package/kernel/mt76/patches/090-backport-to-linux-5.19.patch b/package/kernel/mt76/patches/090-backport-to-linux-5.19.patch new file mode 100644 index 000000000..44a14950a --- /dev/null +++ b/package/kernel/mt76/patches/090-backport-to-linux-5.19.patch @@ -0,0 +1,14 @@ +--- a/usb.c ++++ b/usb.c +@@ -1068,7 +1068,11 @@ + + INIT_WORK(&usb->stat_work, mt76u_tx_status_data); + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5,19,0) + usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1); ++#else ++ usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0)); ++#endif + if (usb->data_len < 32) + usb->data_len = 32; + diff --git a/package/kernel/mt76/patches/091-fix-linux-6.1-build.patch b/package/kernel/mt76/patches/091-fix-linux-6.1-build.patch new file mode 100644 index 000000000..0b7ee7b3e --- /dev/null +++ b/package/kernel/mt76/patches/091-fix-linux-6.1-build.patch @@ -0,0 +1,33 @@ +--- a/mt7921/dma.c +--- b/mt7921/dma.c +@@ -283,10 +283,15 @@ + if (ret < 0) + return ret; + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) + netif_tx_napi_add(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + mt7921_poll_tx, NAPI_POLL_WEIGHT); + napi_enable(&dev->mt76.tx_napi); +- ++#else ++ netif_napi_add_tx_weight(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, ++ mt7921_poll_tx, NAPI_POLL_WEIGHT); ++ napi_enable(&dev->mt76.tx_napi); ++#endif + return mt7921_dma_enable(dev); + } + +--- a/dma.c +--- b/dma.c +@@ -895,7 +895,11 @@ + dev->napi_dev.threaded = 1; + + mt76_for_each_q_rx(dev, i) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(6,1,0) + netif_napi_add(&dev->napi_dev, &dev->napi[i], poll, 64); ++#else ++ netif_napi_add_weight(&dev->napi_dev, &dev->napi[i], poll, 64); ++#endif + mt76_dma_rx_fill(dev, &dev->q_rx[i]); + napi_enable(&dev->napi[i]); + }