diff --git a/feeds/wifi-ax/mac80211/patches/pending/230-get_txpower.patch b/feeds/wifi-ax/mac80211/patches/pending/230-get_txpower.patch index 7c925c7b..5a3917f5 100644 --- a/feeds/wifi-ax/mac80211/patches/pending/230-get_txpower.patch +++ b/feeds/wifi-ax/mac80211/patches/pending/230-get_txpower.patch @@ -21,10 +21,8 @@ Signed-off-by: Aditya Kumar Singh drivers/net/wireless/ath/ath11k/wmi.c | 49 ++++++++++++- 6 files changed, 229 insertions(+), 95 deletions(-) -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/core.c -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/core.c -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/core.c +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c @@ -425,6 +425,55 @@ static const struct ath11k_num_vdevs_pee }, }; @@ -81,10 +79,8 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/c int ath11k_core_suspend(struct ath11k_base *ab) { int ret; -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/core.h -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/core.h -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/core.h +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h @@ -527,8 +527,6 @@ struct ath11k_debug { struct ath11k_dbg_htt_stats htt_stats; u32 extd_tx_stats; @@ -94,10 +90,10 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/c u32 extd_rx_stats; u32 pktlog_filter; u32 pktlog_mode; -@@ -759,6 +757,11 @@ struct ath11k { - u8 cfr_enabled; - bool ani_enabled; - enum wmi_phy_mode cfr_phymode; +@@ -764,6 +762,11 @@ struct ath11k { + struct cfg80211_chan_def awgn_chandef; + u32 chan_bw_interference_bitmap; + bool awgn_intf_handling_in_prog; + + /* fw pdev_stats can be requested by get_txpower mac ops too */ + struct list_head fw_stats_pdevs; @@ -106,7 +102,7 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/c }; struct ath11k_band_cap { -@@ -1188,6 +1191,12 @@ enum ath11k_fw_recovery_option { +@@ -1193,6 +1196,12 @@ enum ath11k_fw_recovery_option { ATH11K_FW_RECOVERY_ENABLE_SSR_ONLY, }; @@ -119,10 +115,8 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/c 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[]; -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs.c -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/debugfs.c -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs.c +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -650,86 +650,29 @@ void ath11k_debug_aggr_size_config_init( &fops_amsdu_aggr_size); } @@ -313,10 +307,8 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/d } static ssize_t ath11k_write_pktlog_filter(struct file *file, -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs.h -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/debugfs.h -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs.h +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h @@ -231,7 +231,7 @@ int ath11k_debugfs_pdev_create(struct at void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab); int ath11k_debugfs_register(struct ath11k *ar); @@ -337,11 +329,9 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/d { } -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/mac.c -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c -@@ -8850,6 +8850,96 @@ out: +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -8969,6 +8969,96 @@ out: return ret; } @@ -438,7 +428,7 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/m static const struct ieee80211_ops ath11k_ops = { .tx = ath11k_mac_op_tx, .start = ath11k_mac_op_start, -@@ -8892,6 +8982,7 @@ static const struct ieee80211_ops ath11k +@@ -9011,6 +9101,7 @@ static const struct ieee80211_ops ath11k #ifdef CPTCFG_MAC80211_MESH .config_mesh_offload_path = ath11k_mac_op_config_mesh_offload_path, #endif @@ -446,7 +436,7 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/m }; static void ath11k_mac_update_ch_list(struct ath11k *ar, -@@ -9562,6 +9653,8 @@ int ath11k_mac_allocate(struct ath11k_ba +@@ -9681,6 +9772,8 @@ int ath11k_mac_allocate(struct ath11k_ba ar->monitor_vdev_id = -1; ar->monitor_vdev_created = false; ar->monitor_started = false; @@ -455,10 +445,8 @@ Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/m } return 0; -Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/wmi.c -=================================================================== ---- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/wmi.c -+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/wmi.c +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -7063,7 +7063,7 @@ void ath11k_wmi_fw_stats_fill(struct ath spin_lock_bh(&ar->data_lock); diff --git a/feeds/wifi-ax/mac80211/patches/qca/305-002-ath11k-Add-support-to-handle-AWGN-interference-for-6G.patch b/feeds/wifi-ax/mac80211/patches/qca/305-002-ath11k-Add-support-to-handle-AWGN-interference-for-6G.patch index aae59156..e55be161 100644 --- a/feeds/wifi-ax/mac80211/patches/qca/305-002-ath11k-Add-support-to-handle-AWGN-interference-for-6G.patch +++ b/feeds/wifi-ax/mac80211/patches/qca/305-002-ath11k-Add-support-to-handle-AWGN-interference-for-6G.patch @@ -5,7 +5,8 @@ Subject: [PATCH] ath11k: Add support to handle AWGN interference for 6G When AWGN interference is detected in any 6G channel, FW indicates it to host using WMI_DCS_INTERFERENCE_EVENT. Added support to parse new wmi -event to get AWGN interference info and indicate to mac80211. +event to get AWGN interference info, validate the AWGN detected channel +and interference bitmap and indicate to mac80211. AWGN interference detection support in FW will be advertised in wmi service ready event, based on which host can decide to handle and process interference @@ -26,7 +27,7 @@ Signed-off-by: Lavanya Suresh --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c -@@ -2161,6 +2161,35 @@ static const struct file_operations fops +@@ -2165,6 +2165,35 @@ static const struct file_operations fops .open = simple_open }; @@ -62,7 +63,7 @@ Signed-off-by: Lavanya Suresh static ssize_t ath11k_write_btcoex(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -@@ -3765,6 +3794,12 @@ int ath11k_debugfs_register(struct ath11 +@@ -4136,6 +4165,12 @@ int ath11k_debugfs_register(struct ath11 &ar->dfs_block_radar_events); } @@ -77,7 +78,7 @@ Signed-off-by: Lavanya Suresh &fops_enable_m3_dump); --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c -@@ -8419,6 +8419,143 @@ exit: +@@ -8531,6 +8531,209 @@ exit: kfree(tb); } @@ -96,6 +97,7 @@ Signed-off-by: Lavanya Suresh + "AWGN Info: channel width: %d, chan freq: %d, center_freq0: %d, center_freq1: %d, bw_intf_bitmap: %d\n", + awgn_info->channel_width, awgn_info->chan_freq, awgn_info->center_freq0, awgn_info->center_freq1, + awgn_info->chan_bw_interference_bitmap); ++ memcpy(data, awgn_info, sizeof(*awgn_info)); + break; + default: + ath11k_warn(ab, @@ -139,12 +141,72 @@ Signed-off-by: Lavanya Suresh + return ret; +} + ++bool ath11k_wmi_validate_dcs_awgn_info(struct ath11k *ar, struct wmi_dcs_awgn_info *awgn_info) ++{ ++ spin_lock_bh(&ar->data_lock); ++ ++ if (!ar->rx_channel) { ++ spin_unlock_bh(&ar->data_lock); ++ return false; ++ } ++ ++ if (awgn_info->chan_freq != ar->rx_channel->center_freq) { ++ spin_unlock_bh(&ar->data_lock); ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "dcs interference event received with wrong channel %d",awgn_info->chan_freq); ++ return false; ++ } ++ spin_unlock_bh(&ar->data_lock); ++ ++ switch (awgn_info->channel_width) { ++ case WMI_HOST_CHAN_WIDTH_20: ++ if (awgn_info->chan_bw_interference_bitmap > WMI_DCS_SEG_PRI20) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "dcs interference event received with wrong chan width bmap %d for 20MHz", ++ awgn_info->chan_bw_interference_bitmap); ++ return false; ++ } ++ break; ++ case WMI_HOST_CHAN_WIDTH_40: ++ if (awgn_info->chan_bw_interference_bitmap > WMI_DCS_SEG_SEC20) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "dcs interference event received with wrong chan width bmap %d for 40MHz", ++ awgn_info->chan_bw_interference_bitmap); ++ return false; ++ } ++ break; ++ case WMI_HOST_CHAN_WIDTH_80: ++ if (awgn_info->chan_bw_interference_bitmap > WMI_DCS_SEG_SEC40) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "dcs interference event received with wrong chan width bmap %d for 80MHz", ++ awgn_info->chan_bw_interference_bitmap); ++ return false; ++ } ++ break; ++ case WMI_HOST_CHAN_WIDTH_160: ++ case WMI_HOST_CHAN_WIDTH_80P80: ++ if (awgn_info->chan_bw_interference_bitmap > WMI_DCS_SEG_SEC80) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "dcs interference event received with wrong chan width bmap %d for 80P80/160MHz", ++ awgn_info->chan_bw_interference_bitmap); ++ return false; ++ } ++ break; ++ default: ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "dcs interference event received with unknown channel width %d", ++ awgn_info->channel_width); ++ return false; ++ } ++ return true; ++} ++ +static void +ath11k_wmi_dcs_awgn_interference_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const struct wmi_dcs_interference_ev *dcs_intf_ev; -+ struct wmi_dcs_awgn_info *awgn_info; ++ struct wmi_dcs_awgn_info awgn_info = {}; + struct ath11k *ar; + struct ath11k_vif *arvif; + const struct wmi_tlv *tlv; @@ -186,7 +248,7 @@ Signed-off-by: Lavanya Suresh + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_dcs_awgn_event_parser, -+ awgn_info); ++ &awgn_info); + if (ret) { + ath11k_warn(ab, "failed to parse awgn tlv %d\n", ret); + return; @@ -205,6 +267,11 @@ Signed-off-by: Lavanya Suresh + goto exit; + } + ++ if (!ath11k_wmi_validate_dcs_awgn_info(ar, &awgn_info)) { ++ ath11k_warn(ab, "Invalid DCS AWGN TLV - Skipping event"); ++ goto exit; ++ } ++ + ath11k_info(ab, "Interface(pdev %d) will be disabled because of AWGN interference\n", + dcs_intf_ev->pdev_id); + @@ -221,7 +288,7 @@ Signed-off-by: Lavanya Suresh static void ath11k_wmi_tm_event_segmented(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb) { -@@ -9566,6 +9703,9 @@ static void ath11k_wmi_tlv_op_rx(struct +@@ -9678,6 +9881,9 @@ static void ath11k_wmi_tlv_op_rx(struct case WMI_WOW_WAKEUP_HOST_EVENTID: ath11k_wmi_event_wow_wakeup_host(ab, skb); break; @@ -231,7 +298,7 @@ Signed-off-by: Lavanya Suresh case WMI_PDEV_GET_TPC_STATS_EVENTID: ath11k_process_tpc_stats(ab, skb); break; -@@ -9728,6 +9868,42 @@ int ath11k_wmi_simulate_radar(struct ath +@@ -9846,6 +10052,42 @@ int ath11k_wmi_simulate_radar(struct ath return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args); } @@ -276,7 +343,7 @@ Signed-off-by: Lavanya Suresh u32 m3_args[WMI_M3_MAX_TEST_ARGS]; --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h -@@ -1903,6 +1903,7 @@ enum wmi_tlv_tag { +@@ -1909,6 +1909,7 @@ enum wmi_tlv_tag { WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, WMI_CTRL_PATH_CAL_STATS = 0x3BC, @@ -284,7 +351,7 @@ Signed-off-by: Lavanya Suresh WMI_TAG_MAX }; -@@ -2175,6 +2176,7 @@ enum wmi_tlv_service { +@@ -2181,6 +2182,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263, WMI_TLV_SERVICE_QOS_NULL_FRAME_TX_OVER_WMI = 264, WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, @@ -292,7 +359,7 @@ Signed-off-by: Lavanya Suresh WMI_MAX_EXT2_SERVICE }; -@@ -4216,6 +4218,17 @@ struct wmi_dfs_unit_test_arg { +@@ -4264,6 +4266,17 @@ struct wmi_dfs_unit_test_arg { u32 radar_param; }; @@ -310,7 +377,7 @@ Signed-off-by: Lavanya Suresh #define WMI_M3_UNIT_TEST_MODULE 0x22 #define WMI_M3_UNIT_TEST_TOKEN 0 -@@ -4843,6 +4856,21 @@ struct wmi_pdev_radar_ev { +@@ -4891,6 +4904,42 @@ struct wmi_pdev_radar_ev { s32 sidx; } __packed; @@ -328,11 +395,32 @@ Signed-off-by: Lavanya Suresh + u32 interference_type; + u32 pdev_id; +} __packed; ++ ++enum wmi_host_channel_width { ++ WMI_HOST_CHAN_WIDTH_20 = 0, ++ WMI_HOST_CHAN_WIDTH_40 = 1, ++ WMI_HOST_CHAN_WIDTH_80 = 2, ++ WMI_HOST_CHAN_WIDTH_160 = 3, ++ WMI_HOST_CHAN_WIDTH_80P80 = 4, ++}; ++ ++enum wmi_dcs_interference_chan_segment { ++ WMI_DCS_SEG_PRI20 = 0x1, ++ WMI_DCS_SEG_SEC20 = 0x2, ++ WMI_DCS_SEG_SEC40_LOWER = 0x4, ++ WMI_DCS_SEG_SEC40_UPPER = 0x8, ++ WMI_DCS_SEG_SEC40 = 0xC, ++ WMI_DCS_SEG_SEC80_LOWER = 0x10, ++ WMI_DCS_SEG_SEC80_LOWER_UPPER = 0x20, ++ WMI_DCS_SEG_SEC80_UPPER_LOWER = 0x40, ++ WMI_DCS_SEG_SEC80_UPPER = 0x80, ++ WMI_DCS_SEG_SEC80 = 0xF0, ++}; + struct wmi_pdev_temperature_event { /* temperature value in Celcius degree */ s32 temp; -@@ -6636,6 +6664,7 @@ void ath11k_wmi_fw_stats_fill(struct ath +@@ -6686,6 +6735,7 @@ void ath11k_wmi_fw_stats_fill(struct ath struct ath11k_fw_stats *fw_stats, u32 stats_id, char *buf); int ath11k_wmi_simulate_radar(struct ath11k *ar); diff --git a/feeds/wifi-ax/mac80211/patches/qca/333-001-ath11k-Add-support-for-awgn-mitigation-in-6Ghz.patch b/feeds/wifi-ax/mac80211/patches/qca/333-001-ath11k-Add-support-for-awgn-mitigation-in-6Ghz.patch new file mode 100644 index 00000000..8908867d --- /dev/null +++ b/feeds/wifi-ax/mac80211/patches/qca/333-001-ath11k-Add-support-for-awgn-mitigation-in-6Ghz.patch @@ -0,0 +1,388 @@ +From 53f2c10cf048d3420bff7db90cb3bafaf6f7ac57 Mon Sep 17 00:00:00 2001 +From: Hari Chandrakanthan +Date: Wed, 1 Dec 2021 12:19:02 +0530 +Subject: [PATCH] ath11k : Add support for awgn mitigation in 6Ghz + +AWGN - Additive white Gaussian Noise + +support to simulate awgn event with channel bw +interference bitmap is added. + +channel bw interference bitmap holds the interference information +on primary and secondary channels. + +Eg: For 80Mhz operating bandwidth, the chan bw interference +bitmap can be as follows. + +segment chan_bw_interference_bitmap +0 0x01 +1 0x02 +2 0x04 +3 0x08 + +segment 0 - primary 20Mhz +segment 1 - secondary 20Mhz +segment 2 - secondary 40Mhz lower +segment 3 - secondary 40Mhz upper + +support to update rx_channel is added + +Signed-off-by: Hari Chandrakanthan +--- + drivers/net/wireless/ath/ath11k/core.h | 4 ++ + drivers/net/wireless/ath/ath11k/debugfs.c | 6 +- + drivers/net/wireless/ath/ath11k/mac.c | 116 +++++++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/mac.h | 3 + + drivers/net/wireless/ath/ath11k/wmi.c | 33 ++++++--- + drivers/net/wireless/ath/ath11k/wmi.h | 2 +- + 6 files changed, 151 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -689,6 +689,7 @@ struct ath11k { + int max_num_peers; + u32 num_started_vdevs; + u32 num_created_vdevs; ++ u32 num_mesh_vdevs; + unsigned long long allocated_vdev_map; + + struct idr txmgmt_idr; +@@ -759,6 +760,10 @@ struct ath11k { + u8 cfr_enabled; + bool ani_enabled; + enum wmi_phy_mode cfr_phymode; ++ ++ struct cfg80211_chan_def awgn_chandef; ++ u32 chan_bw_interference_bitmap; ++ bool awgn_intf_handling_in_prog; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -2273,6 +2273,7 @@ static ssize_t ath11k_write_simulate_awg + { + struct ath11k *ar = file->private_data; + int ret; ++ u32 chan_bw_interference_bitmap; + + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { +@@ -2280,7 +2281,10 @@ static ssize_t ath11k_write_simulate_awg + goto exit; + } + +- ret = ath11k_wmi_simulate_awgn(ar); ++ if (kstrtou32_from_user(user_buf, count, 0, &chan_bw_interference_bitmap)) ++ return -EINVAL; ++ ++ ret = ath11k_wmi_simulate_awgn(ar, chan_bw_interference_bitmap); + if (ret) + goto exit; + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -886,7 +886,7 @@ void ath11k_mac_peer_cleanup_all(struct + ar->num_stations = 0; + } + +-static void ++void + ath11k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + void *data) +@@ -6453,6 +6453,11 @@ static int ath11k_mac_op_start(struct ie + ar->num_peers = 0; + ar->allocated_vdev_map = 0; + ++ spin_lock_bh(&ar->data_lock); ++ ar->awgn_intf_handling_in_prog = false; ++ ar->num_mesh_vdevs = 0; ++ spin_unlock_bh(&ar->data_lock); ++ + /* Configure monitor status ring with default rx_filter to get rx status + * such as rssi, rx_duration. + */ +@@ -6529,6 +6534,10 @@ static void ath11k_mac_op_stop(struct ie + synchronize_rcu(); + + atomic_set(&ar->num_pending_mgmt_tx, 0); ++ ++ spin_lock_bh(&ar->data_lock); ++ ar->awgn_intf_handling_in_prog = false; ++ spin_unlock_bh(&ar->data_lock); + } + + static int +@@ -6662,6 +6671,10 @@ static int ath11k_mac_vdev_delete(struct + ar->ab->free_vdev_map |= 1LL << (arvif->vdev_id); + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); + ar->num_created_vdevs--; ++ spin_lock_bh(&ar->data_lock); ++ if (vif->type == NL80211_IFTYPE_MESH_POINT) ++ ar->num_mesh_vdevs--; ++ spin_unlock_bh(&ar->data_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", + vif->addr, arvif->vdev_id); +@@ -6813,6 +6826,8 @@ static int ath11k_mac_op_add_interface(s + ab->free_vdev_map &= ~(1LL << arvif->vdev_id); + + spin_lock_bh(&ar->data_lock); ++ if (vif->type == NL80211_IFTYPE_MESH_POINT) ++ ar->num_mesh_vdevs++; + list_add(&arvif->list, &ar->arvifs); + spin_unlock_bh(&ar->data_lock); + +@@ -7475,6 +7490,75 @@ ath11k_mac_change_chanctx_fill_iter(void + arg->next_vif++; + } + ++static void ath11k_mac_num_chanctxs_iter(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *conf, ++ void *data) ++{ ++ int *num = data; ++ ++ (*num)++; ++} ++ ++static int ath11k_mac_num_chanctxs(struct ath11k *ar) ++{ ++ int num = 0; ++ ++ ieee80211_iter_chan_contexts_atomic(ar->hw, ++ ath11k_mac_num_chanctxs_iter, ++ &num); ++ ++ return num; ++} ++ ++static void ath11k_mac_update_rx_channel(struct ath11k *ar, ++ struct ieee80211_chanctx_conf *ctx, ++ struct ieee80211_vif_chanctx_switch *vifs, ++ int n_vifs) ++{ ++ struct cfg80211_chan_def *def = NULL; ++ ++ /* Both locks are required because ar->rx_channel is modified. This ++ * allows readers to hold either lock. ++ */ ++ lockdep_assert_held(&ar->conf_mutex); ++ lockdep_assert_held(&ar->data_lock); ++ ++ WARN_ON(ctx && vifs); ++ WARN_ON(vifs && !n_vifs); ++ ++ /* FIXME: Sort of an optimization and a workaround. Peers and vifs are ++ * on a linked list now. Doing a lookup peer -> vif -> chanctx for each ++ * ppdu on Rx may reduce performance on low-end systems. It should be ++ * possible to make tables/hashmaps to speed the lookup up (be vary of ++ * cpu data cache lines though regarding sizes) but to keep the initial ++ * implementation simple and less intrusive fallback to the slow lookup ++ * only for multi-channel cases. Single-channel cases will remain to ++ * use the old channel derival and thus performance should not be ++ * affected much. ++ */ ++ rcu_read_lock(); ++ if (!ctx && ath11k_mac_num_chanctxs(ar) == 1) { ++ ieee80211_iter_chan_contexts_atomic(ar->hw, ++ ath11k_mac_get_any_chandef_iter, ++ &def); ++ if (vifs) ++ def = &vifs[0].new_ctx->def; ++ ++ ar->rx_channel = def->chan; ++ } else if ((ctx && ath11k_mac_num_chanctxs(ar) == 0) || ++ (ctx && (ar->state == ATH11K_STATE_RESTARTED))) { ++ /* During driver restart due to firmware assert, since mac80211 ++ * already has valid channel context for given radio, channel ++ * context iteration return num_chanctx > 0. So fix rx_channel ++ * when restart is in progress. ++ */ ++ ar->rx_channel = ctx->def.chan; ++ } else { ++ ar->rx_channel = NULL; ++ } ++ rcu_read_unlock(); ++} ++ + static void + ath11k_mac_update_vif_chan(struct ath11k *ar, + struct ieee80211_vif_chanctx_switch *vifs, +@@ -7482,6 +7566,7 @@ ath11k_mac_update_vif_chan(struct ath11k + { + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif; ++ struct cfg80211_chan_def *chandef = NULL; + int ret; + int i; + bool monitor_vif = false; +@@ -7520,11 +7605,13 @@ ath11k_mac_update_vif_chan(struct ath11k + } + } + ++ chandef = &vifs[0].new_ctx->def; ++ + /* All relevant vdevs are downed and associated channel resources + * should be available for the channel switch now. + */ + +- /* TODO: Update ar->rx_channel */ ++ ath11k_mac_update_rx_channel(ar, NULL, vifs, n_vifs); + + for (i = 0; i < n_vifs; i++) { + struct vdev_up_params params = {0}; +@@ -7572,6 +7659,38 @@ ath11k_mac_update_vif_chan(struct ath11k + if (!ath11k_mac_monitor_stop(ar)) + ath11k_mac_monitor_start(ar); + } ++ ++ spin_lock_bh(&ar->data_lock); ++ if (ar->awgn_intf_handling_in_prog && chandef) { ++ if (!ar->chan_bw_interference_bitmap || ++ (ar->chan_bw_interference_bitmap & WMI_DCS_SEG_PRI20)) { ++ if (ar->awgn_chandef.chan->center_freq != ++ chandef->chan->center_freq) { ++ ar->awgn_intf_handling_in_prog = false; ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "AWGN : channel switch completed\n"); ++ } else { ++ ath11k_warn(ab, "AWGN : channel switch is not done, freq : %d\n", ++ ar->awgn_chandef.chan->center_freq); ++ } ++ } else { ++ if ((ar->awgn_chandef.chan->center_freq == ++ chandef->chan->center_freq) && ++ (ar->awgn_chandef.width != chandef->width)) { ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "AWGN : BW reduction is complete\n"); ++ ar->awgn_intf_handling_in_prog = false; ++ } else { ++ ath11k_warn(ab, "AWGN : awgn_freq : %d chan_freq %d" ++ " awgn_width %d chan_width %d\n", ++ ar->awgn_chandef.chan->center_freq, ++ chandef->chan->center_freq, ++ ar->awgn_chandef.width, ++ chandef->width); ++ } ++ } ++ } ++ spin_unlock_bh(&ar->data_lock); + } + + static void +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -167,4 +167,7 @@ void ath11k_mac_bcn_tx_event(struct ath1 + void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); + void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id); + bool ath11k_mac_sta_level_info(struct ath11k_vif *arvif, struct ieee80211_sta *sta); ++void ath11k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *conf, ++ void *data); + #endif +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -8685,8 +8685,8 @@ ath11k_wmi_dcs_awgn_interference_event(s + { + const struct wmi_dcs_interference_ev *dcs_intf_ev; + struct wmi_dcs_awgn_info awgn_info = {}; ++ struct cfg80211_chan_def *chandef = NULL; + struct ath11k *ar; +- struct ath11k_vif *arvif; + const struct wmi_tlv *tlv; + u16 tlv_tag; + u8 *ptr; +@@ -8745,20 +8745,35 @@ ath11k_wmi_dcs_awgn_interference_event(s + goto exit; + } + ++ if (ar->awgn_intf_handling_in_prog) ++ goto exit; ++ + if (!ath11k_wmi_validate_dcs_awgn_info(ar, &awgn_info)) { + ath11k_warn(ab, "Invalid DCS AWGN TLV - Skipping event"); + goto exit; + } + +- ath11k_info(ab, "Interface(pdev %d) will be disabled because of AWGN interference\n", ++ ath11k_info(ab, "Interface(pdev %d) : AWGN interference detected\n", + dcs_intf_ev->pdev_id); + +- list_for_each_entry(arvif, &ar->arvifs, list) { +- if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) { +- ieee80211_awgn_detected(arvif->vif); +- } ++ ieee80211_iter_chan_contexts_atomic(ar->hw, ath11k_mac_get_any_chandef_iter, ++ &chandef); ++ if (!chandef) { ++ ath11k_warn(ab, "chandef is not available\n"); ++ goto exit; + } ++ ar->awgn_chandef = *chandef; ++ ++ ieee80211_awgn_detected(ar->hw, awgn_info.chan_bw_interference_bitmap); ++ ++ spin_lock_bh(&ar->data_lock); ++ /* Incase of mesh intf presence, dont set in prog as there will be no ++ Channel/BW change happening. */ ++ ar->awgn_intf_handling_in_prog = (ar->num_mesh_vdevs ? false : true); ++ ar->chan_bw_interference_bitmap = awgn_info.chan_bw_interference_bitmap; ++ spin_unlock_bh(&ar->data_lock); + ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "AWGN : Interference handling started\n"); + exit: + rcu_read_unlock(); + } +@@ -10080,7 +10095,7 @@ int ath11k_wmi_simulate_radar(struct ath + } + + +-int ath11k_wmi_simulate_awgn(struct ath11k *ar) ++int ath11k_wmi_simulate_awgn(struct ath11k *ar, u32 chan_bw_interference_bitmap) + { + struct ath11k_vif *arvif; + u32 awgn_args[WMI_AWGN_MAX_TEST_ARGS]; +@@ -10103,14 +10118,16 @@ int ath11k_wmi_simulate_awgn(struct ath1 + return -EINVAL; + + awgn_args[WMI_AWGN_TEST_AWGN_INT] = WMI_UNIT_TEST_AWGN_INTF_TYPE; +- awgn_args[WMI_AWGN_TEST_BITMAP] = WMI_UNIT_TEST_AWGN_PRIMARY_20; ++ awgn_args[WMI_AWGN_TEST_BITMAP] = chan_bw_interference_bitmap; + + wmi_ut.vdev_id = arvif->vdev_id; + wmi_ut.module_id = WMI_AWGN_UNIT_TEST_MODULE; + wmi_ut.num_args = WMI_AWGN_MAX_TEST_ARGS; + wmi_ut.diag_token = WMI_AWGN_UNIT_TEST_TOKEN; + +- ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "Triggering AWGN Simulation\n"); ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "Triggering AWGN Simulation, interference bitmap : 0x%x\n", ++ chan_bw_interference_bitmap); + + return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, awgn_args); + } +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -6744,7 +6744,7 @@ void ath11k_wmi_fw_stats_fill(struct ath + struct ath11k_fw_stats *fw_stats, u32 stats_id, + char *buf); + int ath11k_wmi_simulate_radar(struct ath11k *ar); +-int ath11k_wmi_simulate_awgn(struct ath11k *ar); ++int ath11k_wmi_simulate_awgn(struct ath11k *ar, u32 chan_bw_interference_bitmap); + 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, +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1264,6 +1264,9 @@ void ath11k_core_halt(struct ath11k *ar) + + ar->num_created_vdevs = 0; + ar->allocated_vdev_map = 0; ++ spin_lock_bh(&ar->data_lock); ++ ar->num_mesh_vdevs = 0; ++ spin_unlock_bh(&ar->data_lock); + + ath11k_mac_scan_finish(ar); + ath11k_mac_peer_cleanup_all(ar); diff --git a/feeds/wifi-ax/mac80211/patches/qca/333-002-mac80211-add-support-to-awgn-detection-and-mitigatio.patch b/feeds/wifi-ax/mac80211/patches/qca/333-002-mac80211-add-support-to-awgn-detection-and-mitigatio.patch new file mode 100644 index 00000000..3b4e6f0a --- /dev/null +++ b/feeds/wifi-ax/mac80211/patches/qca/333-002-mac80211-add-support-to-awgn-detection-and-mitigatio.patch @@ -0,0 +1,356 @@ +From 1634cf729a978d025cfe726ef0d1796af6cdea36 Mon Sep 17 00:00:00 2001 +From: Hari Chandrakanthan +Date: Wed, 1 Dec 2021 12:21:06 +0530 +Subject: [PATCH] mac80211 : add support to awgn detection and mitigation in + 6Ghz + +when awgn interference is detected on operating channel, +AP is supposed to stop transmitting in that channel. +AP can reduce it's operating bandwidth or +completely move to another channel based on the +interference segment. + +support to send nl event upon detecting awgn in 6Ghz is added + +When awgn wmi event is detected by the driver, driver notifies mac80211 +with the channel interference bitmap and mac80211 sends the operating +channel info and the channel interference bitmap to userspace through +NL80211_CMD_AWGN_DETECT cmd and NL80211_ATTR_AWGN_INTERFERENCE_BITMAP +attribute. If the interference is on the primary channel, the userspace +tool completely switches to a new channel or it reduces bandwidth on the +same operating channel. + +Signed-off-by: Hari Chandrakanthan +--- + include/net/cfg80211.h | 13 ++++++++++ + include/net/mac80211.h | 5 ++-- + include/uapi/linux/nl80211.h | 10 ++++++++ + net/mac80211/ieee80211_i.h | 5 ++-- + net/mac80211/iface.c | 3 --- + net/mac80211/main.c | 4 +++ + net/mac80211/util.c | 61 +++++++++++++++++++++++++------------------- + net/wireless/mlme.c | 9 +++++++ + net/wireless/nl80211.c | 37 +++++++++++++++++++++++++++ + net/wireless/nl80211.h | 5 ++++ + 10 files changed, 119 insertions(+), 33 deletions(-) + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -7576,6 +7576,19 @@ void cfg80211_radar_event(struct wiphy * + struct cfg80211_chan_def *chandef, gfp_t gfp); + + /** ++ * cfg80211_awgn_event - awgn detection event ++ * @wiphy: the wiphy ++ * @chandef: chandef for the current channel ++ * @gfp: context flags ++ * @chan_bw_interference_bitmap: channel bandwidth interference bitmap ++ * ++ * This function is called when Additive white Gaussian noise (AWGN) ++ * is detected on the current channel. ++ */ ++void cfg80211_awgn_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, ++ gfp_t gfp, u32 chan_bw_interference_bitmap); ++ ++/** + * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event + * @dev: network device + * @mac: MAC address of a station which opmode got modified +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6256,9 +6256,10 @@ void ieee80211_chswitch_done(struct ieee + /** + * ieee80211_awgn_detected - inform that awgn interference is detected + * +- * @vif: &struct ieee80211_vif pointer from the add_interface callback. ++ * @hw: pointer as obtained from ieee80211_alloc_hw() ++ * @chan_bw_interference_bitmap : awgn interference bitmap + */ +-void ieee80211_awgn_detected(struct ieee80211_vif *vif); ++void ieee80211_awgn_detected(struct ieee80211_hw *hw, u32 chan_bw_interference_bitmap); + + /** + * ieee80211_request_smps - request SM PS transition +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -1209,6 +1209,11 @@ + * @NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_COMPLETED: Notify userland that the color change + * has completed + * ++ * ++ * @NL80211_CMD_AWGN_DETECT: Once AWGN interference is detected on the operating ++ * channel, userspace is notified with the interference bitmap using ++ * %NL80211_ATTR_AWGN_INTERFERENCE_BITMAP ++ + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -1453,6 +1458,7 @@ enum nl80211_commands { + NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_ABORTED, + NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_COMPLETED, + ++ NL80211_CMD_AWGN_DETECT, + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -2639,6 +2645,8 @@ enum nl80211_commands { + * @NL80211_ATTR_BEACON_TX_MODE: used to configure the beacon tx mode as + * staggered mode = 1 or burst mode = 2 in %NL80211_CMD_START_AP or + * %NL80211_CMD_JOIN_MESH from user-space. ++ * @NL80211_ATTR_AWGN_INTERFERENCE_BITMAP: u32 attribute specifying the ++ * interference bitmap of operating bandwidth for %NL80211_CMD_AWGN_DETECT + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3154,6 +3162,8 @@ enum nl80211_attrs { + + NL80211_ATTR_BEACON_TX_MODE, + ++ NL80211_ATTR_AWGN_INTERFERENCE_BITMAP, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -952,8 +952,6 @@ struct ieee80211_sub_if_data { + bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + struct cfg80211_chan_def csa_chandef; + +- struct work_struct awgn_detected_work; +- + struct work_struct color_change_finalize_work; + + struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ +@@ -1461,6 +1459,8 @@ struct ieee80211_local { + struct sk_buff_head skb_queue_tdls_chsw; + + struct mac80211_memory_stats memory_stats; ++ struct work_struct awgn_detected_work; ++ u32 chan_bw_interference_bitmap; + }; + + static inline struct ieee80211_sub_if_data * +@@ -2298,6 +2298,7 @@ void ieee80211_dfs_cac_timer(unsigned lo + void ieee80211_dfs_cac_timer_work(struct work_struct *work); + void ieee80211_dfs_cac_cancel(struct ieee80211_local *local); + void ieee80211_dfs_radar_detected_work(struct work_struct *work); ++void ieee80211_awgn_detected_work(struct work_struct *work); + int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, + struct cfg80211_csa_settings *csa_settings); + +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -474,8 +474,6 @@ static void ieee80211_do_stop(struct iee + sdata_unlock(sdata); + + cancel_work_sync(&sdata->csa_finalize_work); +- cancel_work_sync(&sdata->awgn_detected_work); +- + cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); + + if (sdata->wdev.cac_started) { +@@ -1672,7 +1670,6 @@ static void ieee80211_setup_sdata(struct + INIT_WORK(&sdata->work, ieee80211_iface_work); + INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); + INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); +- INIT_WORK(&sdata->awgn_detected_work, ieee80211_awgn_interference_detected_work); + INIT_WORK(&sdata->color_change_finalize_work, ieee80211_color_change_finalize_work); + INIT_LIST_HEAD(&sdata->assigned_chanctx_list); + INIT_LIST_HEAD(&sdata->reserved_chanctx_list); +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -272,6 +272,7 @@ static void ieee80211_restart_work(struc + "%s called with hardware scan in progress\n", __func__); + + flush_work(&local->radar_detected_work); ++ flush_work(&local->awgn_detected_work); + /* we might do interface manipulations, so need both */ + rtnl_lock(); + wiphy_lock(local->hw.wiphy); +@@ -721,6 +722,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + + INIT_WORK(&local->radar_detected_work, + ieee80211_dfs_radar_detected_work); ++ INIT_WORK(&local->awgn_detected_work, ++ ieee80211_awgn_detected_work); + + INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); + local->smps_mode = IEEE80211_SMPS_OFF; +@@ -1388,6 +1391,7 @@ void ieee80211_unregister_hw(struct ieee + cancel_work_sync(&local->tdls_chsw_work); + flush_work(&local->sched_scan_stopped_work); + flush_work(&local->radar_detected_work); ++ flush_work(&local->awgn_detected_work); + + ieee80211_clear_tx_pending(local); + rate_control_deinitialize(local); +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -3833,6 +3833,32 @@ void ieee80211_dfs_cac_cancel(struct iee + mutex_unlock(&local->mtx); + } + ++void ieee80211_awgn_detected_work(struct work_struct *work) ++{ ++ struct ieee80211_local *local = ++ container_of(work, struct ieee80211_local, awgn_detected_work); ++ struct cfg80211_chan_def chandef = local->hw.conf.chandef; ++ struct ieee80211_chanctx *ctx; ++ int num_chanctx = 0; ++ ++ mutex_lock(&local->chanctx_mtx); ++ list_for_each_entry(ctx, &local->chanctx_list, list) { ++ if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) ++ continue; ++ ++ num_chanctx++; ++ chandef = ctx->conf.def; ++ } ++ mutex_unlock(&local->chanctx_mtx); ++ ++ if (num_chanctx > 1) ++ /* XXX: multi-channel is not supported yet */ ++ WARN_ON_ONCE(1); ++ else ++ cfg80211_awgn_event(local->hw.wiphy, &chandef, GFP_KERNEL, ++ local->chan_bw_interference_bitmap); ++} ++ + void ieee80211_dfs_radar_detected_work(struct work_struct *work) + { + struct ieee80211_local *local = +@@ -3872,6 +3898,15 @@ void ieee80211_radar_detected(struct iee + } + EXPORT_SYMBOL(ieee80211_radar_detected); + ++void ieee80211_awgn_detected(struct ieee80211_hw *hw, u32 chan_bw_interference_bitmap) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ ++ local->chan_bw_interference_bitmap = chan_bw_interference_bitmap; ++ schedule_work(&local->awgn_detected_work); ++} ++EXPORT_SYMBOL(ieee80211_awgn_detected); ++ + u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c) + { + u32 ret; +@@ -3937,32 +3972,6 @@ u32 ieee80211_chandef_downgrade(struct c + return ret; + } + +-void ieee80211_awgn_interference_detected_work(struct work_struct *work) +-{ +- struct ieee80211_sub_if_data *sdata = +- container_of(work, struct ieee80211_sub_if_data, awgn_detected_work); +- +- sdata_lock(sdata); +- +- if (!ieee80211_sdata_running(sdata)) +- goto unlock; +- +- cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev, +- GFP_KERNEL); +- +-unlock: +- sdata_unlock(sdata); +-} +- +-void ieee80211_awgn_detected(struct ieee80211_vif *vif) +-{ +- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); +- +- ieee80211_queue_work(&sdata->local->hw, +- &sdata->awgn_detected_work); +-} +-EXPORT_SYMBOL(ieee80211_awgn_detected); +- + /* + * Returns true if smps_mode_new is strictly more restrictive than + * smps_mode_old. +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -926,6 +926,15 @@ void cfg80211_radar_event(struct wiphy * + } + EXPORT_SYMBOL(cfg80211_radar_event); + ++void cfg80211_awgn_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, ++ gfp_t gfp, u32 chan_bw_interference_bitmap) ++{ ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ ++ nl80211_awgn_notify(rdev, chandef, NULL, gfp, chan_bw_interference_bitmap); ++} ++EXPORT_SYMBOL(cfg80211_awgn_event); ++ + void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event, gfp_t gfp) +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -798,6 +798,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_COLOR_CHANGE_ANNOUNCEMENT_IES] = NLA_POLICY_NESTED(nl80211_policy), + [NL80211_ATTR_RNR_OFFSETS] = NLA_POLICY_NESTED(nl80211_rnr_ies_policy), + [NL80211_ATTR_BEACON_TX_MODE] = NLA_POLICY_RANGE(NLA_U32, 1, 2), ++ [NL80211_ATTR_AWGN_INTERFERENCE_BITMAP] = { .type = NLA_U32 }, + + }; + +@@ -17683,6 +17684,42 @@ void cfg80211_ch_switch_notify(struct ne + } + EXPORT_SYMBOL(cfg80211_ch_switch_notify); + ++void nl80211_awgn_notify(struct cfg80211_registered_device *rdev, ++ struct cfg80211_chan_def *chandef, ++ struct net_device *netdev, ++ gfp_t gfp, u32 chan_bw_interference_bitmap) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ int ret; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ if (!msg) ++ return; ++ ++ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_AWGN_DETECT); ++ if (!hdr) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ if (nl80211_send_chandef(msg, chandef)) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_AWGN_INTERFERENCE_BITMAP, ++ chan_bw_interference_bitmap)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ ++ ret = genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, ++ NL80211_MCGRP_MLME, gfp); ++ return; ++ ++nla_put_failure: ++ nlmsg_free(msg); ++} ++ + void cfg80211_ch_switch_started_notify(struct net_device *dev, + struct cfg80211_chan_def *chandef, + u8 count, bool quiet) +--- a/net/wireless/nl80211.h ++++ b/net/wireless/nl80211.h +@@ -120,6 +120,11 @@ nl80211_radar_notify(struct cfg80211_reg + enum nl80211_radar_event event, + struct net_device *netdev, gfp_t gfp); + ++void nl80211_awgn_notify(struct cfg80211_registered_device *rdev, ++ struct cfg80211_chan_def *chandef, ++ struct net_device *netdev, ++ gfp_t gfp, u32 chan_bw_interference_bitmap); ++ + void nl80211_send_ap_stopped(struct wireless_dev *wdev); + + void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);