* [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery
@ 2024-10-17 3:09 Kang Yang
2024-10-17 3:09 ` [PATCH v6 1/4] wifi: ath12k: add configure country code for WCN7850 Kang Yang
` (5 more replies)
0 siblings, 6 replies; 19+ messages in thread
From: Kang Yang @ 2024-10-17 3:09 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, quic_kangyang
This patch-set mainly does four things:
1. Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware.
2. Implement 11d scan offload, and report country code to firmware by
WMI command WMI_SET_CURRENT_COUNTRY_CMDID.
3. Use WMI_SET_CURRENT_COUNTRY_CMDID to set country code for WCN7850.
4. Store country code, and update it to firmware after device recovery.
With this patch-set, WCN7850 can do 11d offload scan and update country
code to firmware successfully.
Note: This patch-set is an old patch-set in public review written by
Wen Gong. Just resend it for him.
Link: https://patchwork.kernel.org/project/linux-wireless/cover/20230914090746.23560-1-quic_wgong@quicinc.com/
v6: rebase on tag: ath/main(ath-202410161539).
v5: rebase on tag: ath/main(ath-202410111606).
v4: rebase on tag: ath-202410072115.
v3:
1. use wiphy::mtx lock instead of adding a new lock(patch#2).
2. rename struct according to wmi naming convention(patch#1, #2).
3. update copyright in reg.h
4. modifiy patch#3, #4 due to struct name change.
v2: change per Jeff.
1. change alpha2 length from 3 to 2.
2. change wmi_11d_new_cc_ev to wmi_11d_new_cc_event.
Wen Gong (4):
wifi: ath12k: add configure country code for WCN7850
wifi: ath12k: add 11d scan offload support
wifi: ath12k: use correct WMI command to set country code for WCN7850
wifi: ath12k: store and send country code to firmware after recovery
drivers/net/wireless/ath/ath12k/core.c | 34 ++++-
drivers/net/wireless/ath/ath12k/core.h | 17 +++
drivers/net/wireless/ath/ath12k/hw.c | 6 +
drivers/net/wireless/ath/ath12k/hw.h | 1 +
drivers/net/wireless/ath/ath12k/mac.c | 168 ++++++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/mac.h | 7 ++
drivers/net/wireless/ath/ath12k/reg.c | 70 ++++++++---
drivers/net/wireless/ath/ath12k/reg.h | 4 +-
drivers/net/wireless/ath/ath12k/wmi.c | 158 ++++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/wmi.h | 38 ++++++
10 files changed, 481 insertions(+), 22 deletions(-)
base-commit: fa934bf3e0a825ee09f035c6580af513187d59a2
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH v6 1/4] wifi: ath12k: add configure country code for WCN7850 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang @ 2024-10-17 3:09 ` Kang Yang 2024-10-17 3:09 ` [PATCH v6 2/4] wifi: ath12k: add 11d scan offload support Kang Yang ` (4 subsequent siblings) 5 siblings, 0 replies; 19+ messages in thread From: Kang Yang @ 2024-10-17 3:09 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, quic_kangyang From: Wen Gong <quic_wgong@quicinc.com> Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware, which is used for WCN7850 to update country code. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> Signed-off-by: Kang Yang <quic_kangyang@quicinc.com> --- drivers/net/wireless/ath/ath12k/wmi.c | 36 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/wmi.h | 13 ++++++++++ 2 files changed, 49 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index dced2aa9ba1a..28f0428fb172 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3084,6 +3084,42 @@ int ath12k_wmi_send_init_country_cmd(struct ath12k *ar, return ret; } +int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar, + struct wmi_set_current_country_arg *arg) +{ + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_set_current_country_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_current_country_cmd *)skb->data; + cmd->tlv_header = + ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_CURRENT_COUNTRY_CMD, + sizeof(*cmd)); + + cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id); + memcpy(&cmd->new_alpha2, &arg->alpha2, sizeof(arg->alpha2)); + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "set current country pdev id %d alpha2 %c%c\n", + ar->pdev->pdev_id, + arg->alpha2[0], + arg->alpha2[1]); + + if (ret) { + ath12k_warn(ar->ab, + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 6f55dbdf629d..220f530da569 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3945,6 +3945,16 @@ struct ath12k_wmi_eht_rate_set_params { #define MAX_6G_REG_RULES 5 #define REG_US_5G_NUM_REG_RULES 4 +struct wmi_set_current_country_arg { + u8 alpha2[REG_ALPHA2_LEN]; +}; + +struct wmi_set_current_country_cmd { + __le32 tlv_header; + __le32 pdev_id; + __le32 new_alpha2; +} __packed; + enum wmi_start_event_param { WMI_VDEV_START_RESP_EVENT = 0, WMI_VDEV_RESTART_RESP_EVENT, @@ -5547,6 +5557,9 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar, u32 vdev_id, u32 bcn_ctrl_op); int ath12k_wmi_send_init_country_cmd(struct ath12k *ar, struct ath12k_wmi_init_country_arg *arg); +int +ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar, + struct wmi_set_current_country_arg *arg); int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar, int vdev_id, const u8 *addr, dma_addr_t paddr, u8 tid, -- 2.34.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v6 2/4] wifi: ath12k: add 11d scan offload support 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 2024-10-17 3:09 ` [PATCH v6 1/4] wifi: ath12k: add configure country code for WCN7850 Kang Yang @ 2024-10-17 3:09 ` Kang Yang 2024-10-17 3:09 ` [PATCH v6 3/4] wifi: ath12k: use correct WMI command to set country code for WCN7850 Kang Yang ` (3 subsequent siblings) 5 siblings, 0 replies; 19+ messages in thread From: Kang Yang @ 2024-10-17 3:09 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, quic_kangyang From: Wen Gong <quic_wgong@quicinc.com> Add process of event WMI_11D_NEW_COUNTRY_EVENTID. Add handler for WMI_11D_SCAN_START_CMDID, WMI_11D_SCAN_STOP_CMDID. Use WMI_11D_SCAN_START_CMDID to trigger 11d scan then firmware will report 11d scan result by WMI_11D_NEW_COUNTRY_EVENTID. Host will update the new country code back to firmware. The priority of 11d scan is WMI_SCAN_PRIORITY_MEDIUM in firmware, the priority of hw scan is WMI_SCAN_PRIORITY_LOW. Then hw scan will be canceled when 11d scan is running. To avoid this, need to change the priority of first hw scan to WMI_SCAN_PRIORITY_MEDIUM. Add wait_for_completion_timeout() for scan.complete in ath12k_reg_update_chan_list(). Plus another existing wait in ath12k_scan_stop(), there are two places to wait the scan.complete. They run in different threads so it is possible that both of the enter into wait status. Therefore use complete_all() instead of complete() for scan.complete. complete_all() can work well when it is only one thread wait for scan.complete. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> Signed-off-by: Kang Yang <quic_kangyang@quicinc.com> --- drivers/net/wireless/ath/ath12k/core.c | 33 ++++- drivers/net/wireless/ath/ath12k/core.h | 16 +++ drivers/net/wireless/ath/ath12k/mac.c | 160 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/mac.h | 7 ++ drivers/net/wireless/ath/ath12k/reg.c | 40 ++++++- drivers/net/wireless/ath/ath12k/reg.h | 4 +- drivers/net/wireless/ath/ath12k/wmi.c | 122 ++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.h | 25 ++++ 8 files changed, 397 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index c57322221e1d..0a6b089ae050 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1014,6 +1014,7 @@ void ath12k_core_halt(struct ath12k *ar) cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); cancel_work_sync(&ab->rfkill_work); + cancel_work_sync(&ab->update_11d_work); rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); synchronize_rcu(); @@ -1021,6 +1022,33 @@ void ath12k_core_halt(struct ath12k *ar) idr_init(&ar->txmgmt_idr); } +static void ath12k_update_11d(struct work_struct *work) +{ + struct ath12k_base *ab = container_of(work, struct ath12k_base, update_11d_work); + struct ath12k *ar; + struct ath12k_pdev *pdev; + struct wmi_set_current_country_arg arg = {}; + int ret, i; + + spin_lock_bh(&ab->base_lock); + memcpy(&arg.alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath12k_dbg(ab, ATH12K_DBG_WMI, "update 11d new cc %c%c\n", + arg.alpha2[0], arg.alpha2[1]); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ret = ath12k_wmi_send_set_current_country_cmd(ar, &arg); + if (ret) + ath12k_warn(ar->ab, + "pdev id %d failed set current country code: %d\n", + i, ret); + } +} + static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) { struct ath12k *ar; @@ -1045,8 +1073,10 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ar = &ah->radio[j]; ath12k_mac_drain_tx(ar); + ar->state_11d = ATH12K_11D_IDLE; + complete(&ar->completed_11d_scan); complete(&ar->scan.started); - complete(&ar->scan.completed); + complete_all(&ar->scan.completed); complete(&ar->scan.on_channel); complete(&ar->peer_assoc_done); complete(&ar->peer_delete_done); @@ -1313,6 +1343,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, INIT_WORK(&ab->reset_work, ath12k_core_reset); INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work); INIT_WORK(&ab->dump_work, ath12k_coredump_upload); + INIT_WORK(&ab->update_11d_work, ath12k_update_11d); timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 06b637ba8b8f..3d4ab34d50b3 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -200,6 +200,12 @@ enum ath12k_scan_state { ATH12K_SCAN_ABORTING, }; +enum ath12k_11d_state { + ATH12K_11D_IDLE, + ATH12K_11D_PREPARING, + ATH12K_11D_RUNNING, +}; + enum ath12k_dev_flags { ATH12K_CAC_RUNNING, ATH12K_FLAG_CRASH_FLUSH, @@ -335,6 +341,8 @@ struct ath12k_vif_iter { #define ATH12K_RX_RATE_TABLE_11AX_NUM 576 #define ATH12K_RX_RATE_TABLE_NUM 320 +#define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ) + struct ath12k_rx_peer_rate_stats { u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1]; u64 vht_mcs_count[HAL_RX_MAX_MCS_VHT + 1]; @@ -676,6 +684,12 @@ struct ath12k { u32 freq_low; u32 freq_high; + /* Protected by wiphy::mtx lock. */ + u32 vdev_id_11d_scan; + struct completion completed_11d_scan; + enum ath12k_11d_state state_11d; + bool regdom_set_by_user; + bool nlo_enabled; }; @@ -913,6 +927,8 @@ struct ath12k_base { /* continuous recovery fail count */ atomic_t fail_cont_count; unsigned long reset_fail_timeout; + struct work_struct update_11d_work; + u8 new_alpha2[2]; struct { /* protected by data_lock */ u32 fw_crash_counter; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f5f96a8b1d61..0a71867d2540 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3016,6 +3016,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, if (ret) ath12k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", arvif->vdev_id, ret); + + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map) && + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) + ath12k_mac_11d_scan_stop_all(ar->ab); } static void ath12k_bss_disassoc(struct ath12k *ar, @@ -3684,6 +3689,11 @@ static void ath12k_mac_remove_link_interface(struct ieee80211_hw *hw, ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac remove link interface (vdev %d link id %d)", arvif->vdev_id, arvif->link_id); + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map) && + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) + ath12k_mac_11d_scan_stop(ar); + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath12k_peer_delete(ar, arvif->vdev_id, arvif->bssid); if (ret) @@ -3759,7 +3769,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar) ar->scan_channel = NULL; ar->scan.roc_freq = 0; cancel_delayed_work(&ar->scan.timeout); - complete(&ar->scan.completed); + complete_all(&ar->scan.completed); break; } } @@ -4051,7 +4061,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, ret = ath12k_start_scan(ar, arg); if (ret) { - ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret); + if (ret == -EBUSY) + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "scan engine is busy 11d state %d\n", ar->state_11d); + else + ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret); + spin_lock_bh(&ar->data_lock); ar->scan.state = ATH12K_SCAN_IDLE; spin_unlock_bh(&ar->data_lock); @@ -4069,6 +4084,11 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, kfree(arg); } + if (ar->state_11d == ATH12K_11D_PREPARING && + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) + ath12k_mac_11d_scan_start(ar, arvif->vdev_id); + return ret; } @@ -6394,7 +6414,7 @@ static int ath12k_mac_start(struct ath12k *ar) /* TODO: Do we need to enable ANI? */ - ath12k_reg_update_chan_list(ar); + ath12k_reg_update_chan_list(ar, false); ar->num_started_vdevs = 0; ar->num_created_vdevs = 0; @@ -6572,6 +6592,9 @@ static void ath12k_mac_stop(struct ath12k *ar) cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); cancel_work_sync(&ar->ab->rfkill_work); + cancel_work_sync(&ar->ab->update_11d_work); + ar->state_11d = ATH12K_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) { @@ -6844,6 +6867,118 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, ath12k_mac_update_vif_offload(&ahvif->deflink); } +static bool ath12k_mac_vif_ap_active_any(struct ath12k_base *ab) +{ + struct ath12k *ar; + struct ath12k_pdev *pdev; + struct ath12k_link_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->ahvif->vdev_type == WMI_VDEV_TYPE_AP) + return true; + } + } + return false; +} + +void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id) +{ + struct wmi_11d_scan_start_arg arg; + int ret; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (ar->regdom_set_by_user) + goto fin; + + if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID) + goto fin; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + goto fin; + + if (ath12k_mac_vif_ap_active_any(ar->ab)) + goto fin; + + arg.vdev_id = vdev_id; + arg.start_interval_msec = 0; + arg.scan_period_msec = ATH12K_SCAN_11D_INTERVAL; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac start 11d scan for vdev %d\n", vdev_id); + + ret = ath12k_wmi_send_11d_scan_start_cmd(ar, &arg); + if (ret) { + ath12k_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 (ar->state_11d == ATH12K_11D_PREPARING) + ar->state_11d = ATH12K_11D_RUNNING; + } + +fin: + if (ar->state_11d == ATH12K_11D_PREPARING) { + ar->state_11d = ATH12K_11D_IDLE; + complete(&ar->completed_11d_scan); + } +} + +void ath12k_mac_11d_scan_stop(struct ath12k *ar) +{ + int ret; + u32 vdev_id; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + return; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac stop 11d for vdev %d\n", + ar->vdev_id_11d_scan); + + if (ar->state_11d == ATH12K_11D_PREPARING) { + ar->state_11d = ATH12K_11D_IDLE; + complete(&ar->completed_11d_scan); + } + + if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID) { + vdev_id = ar->vdev_id_11d_scan; + + ret = ath12k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); + if (ret) { + ath12k_warn(ar->ab, + "failed to stopt 11d scan vdev %d ret: %d\n", + vdev_id, ret); + } else { + ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID; + ar->state_11d = ATH12K_11D_IDLE; + complete(&ar->completed_11d_scan); + } + } +} + +void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab) +{ + struct ath12k *ar; + struct ath12k_pdev *pdev; + int i; + + ath12k_dbg(ab, ATH12K_DBG_MAC, "mac stop soc 11d scan\n"); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ath12k_mac_11d_scan_stop(ar); + } +} + int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) { struct ath12k_hw *ah = ar->ah; @@ -6969,6 +7104,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) arvif->vdev_id, ret); goto err_peer_del; } + ath12k_mac_11d_scan_stop_all(ar->ab); break; case WMI_VDEV_TYPE_STA: param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; @@ -7007,6 +7143,13 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) arvif->vdev_id, ret); goto err_peer_del; } + + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) && + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { + reinit_completion(&ar->completed_11d_scan); + ar->state_11d = ATH12K_11D_PREPARING; + } break; default: break; @@ -8231,6 +8374,14 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, ar->num_started_vdevs == 1 && ar->monitor_vdev_created) ath12k_mac_monitor_stop(ar); + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) && + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE && + ar->state_11d != ATH12K_11D_PREPARING) { + reinit_completion(&ar->completed_11d_scan); + ar->state_11d = ATH12K_11D_PREPARING; + } + ath12k_mac_remove_link_interface(hw, arvif); ath12k_mac_unassign_link_vif(arvif); } @@ -9827,6 +9978,9 @@ static void ath12k_mac_setup(struct ath12k *ar) INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + + ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID; + init_completion(&ar->completed_11d_scan); } int ath12k_mac_register(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index d382337ba649..1505627a415a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -54,6 +54,13 @@ enum ath12k_supported_bw { extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default; +#define ATH12K_SCAN_11D_INTERVAL 600000 +#define ATH12K_11D_INVALID_VDEV_ID 0xFFFF + +void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id); +void ath12k_mac_11d_scan_stop(struct ath12k *ar); +void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab); + void ath12k_mac_destroy(struct ath12k_base *ab); void ath12k_mac_unregister(struct ath12k_base *ab); int ath12k_mac_register(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 439d61f284d8..aecfd55aef59 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -94,10 +94,16 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) if (ret) ath12k_warn(ar->ab, "INIT Country code set to fw failed : %d\n", ret); + + wiphy_lock(wiphy); + ath12k_mac_11d_scan_stop(ar); + wiphy_unlock(wiphy); + + ar->regdom_set_by_user = true; } } -int ath12k_reg_update_chan_list(struct ath12k *ar) +int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) { struct ieee80211_supported_band **bands; struct ath12k_wmi_scan_chan_list_arg *arg; @@ -106,7 +112,35 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) struct ath12k_wmi_channel_arg *ch; enum nl80211_band band; int num_channels = 0; - int i, ret; + int i, ret, left; + + if (wait && ar->state_11d != ATH12K_11D_IDLE) { + left = wait_for_completion_timeout(&ar->completed_11d_scan, + ATH12K_SCAN_TIMEOUT_HZ); + if (!left) { + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "failed to receive 11d scan complete: timed out\n"); + ar->state_11d = ATH12K_11D_IDLE; + } + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "reg 11d scan wait left time %d\n", left); + } + + if (wait && + (ar->scan.state == ATH12K_SCAN_STARTING || + ar->scan.state == ATH12K_SCAN_RUNNING)) { + left = wait_for_completion_timeout(&ar->scan.completed, + ATH12K_SCAN_TIMEOUT_HZ); + if (!left) + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "failed to receive hw scan complete: timed out\n"); + + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "reg hw scan wait left time %d\n", left); + } + + if (ar->ah->state == ATH12K_HW_STATE_RESTARTING) + return 0; bands = hw->wiphy->bands; for (band = 0; band < NUM_NL80211_BANDS; band++) { @@ -295,7 +329,7 @@ int ath12k_regd_update(struct ath12k *ar, bool init) */ for_each_ar(ah, ar, i) { ab = ar->ab; - ret = ath12k_reg_update_chan_list(ar); + ret = ath12k_reg_update_chan_list(ar, true); if (ret) goto err; } diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h index 29c7ec3260da..e4ceae46e556 100644 --- a/drivers/net/wireless/ath/ath12k/reg.h +++ b/drivers/net/wireless/ath/ath12k/reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_REG_H @@ -96,6 +96,6 @@ struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab, struct ath12k_reg_info *reg_info, bool intersect); int ath12k_regd_update(struct ath12k *ar, bool init); -int ath12k_reg_update_chan_list(struct ath12k *ar); +int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait); #endif diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 28f0428fb172..6937a3ce7f15 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -171,6 +171,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct ath12k_wmi_p2p_noa_info) }, [WMI_TAG_P2P_NOA_EVENT] = { .min_len = sizeof(struct wmi_p2p_noa_event) }, + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { + .min_len = sizeof(struct wmi_11d_new_cc_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -2364,7 +2366,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar, cmd->scan_id = cpu_to_le32(arg->scan_id); cmd->scan_req_id = cpu_to_le32(arg->scan_req_id); cmd->vdev_id = cpu_to_le32(arg->vdev_id); - cmd->scan_priority = cpu_to_le32(arg->scan_priority); + if (ar->state_11d == ATH12K_11D_PREPARING) + arg->scan_priority = WMI_SCAN_PRIORITY_MEDIUM; + else + arg->scan_priority = WMI_SCAN_PRIORITY_LOW; cmd->notify_scan_events = cpu_to_le32(arg->notify_scan_events); ath12k_wmi_copy_scan_event_cntrl_flags(cmd, arg); @@ -3120,6 +3125,74 @@ int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar, return ret; } +int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar, + struct wmi_11d_scan_start_arg *arg) +{ + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_11d_scan_start_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_start_cmd *)skb->data; + cmd->tlv_header = + ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_START_CMD, + sizeof(*cmd)); + + cmd->vdev_id = cpu_to_le32(arg->vdev_id); + cmd->scan_period_msec = cpu_to_le32(arg->scan_period_msec); + cmd->start_interval_msec = cpu_to_le32(arg->start_interval_msec); + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "send 11d scan start vdev id %d period %d ms internal %d ms\n", + arg->vdev_id, arg->scan_period_msec, + arg->start_interval_msec); + + if (ret) { + ath12k_warn(ar->ab, + "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + +int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id) +{ + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_11d_scan_stop_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_stop_cmd *)skb->data; + cmd->tlv_header = + ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_STOP_CMD, + sizeof(*cmd)); + + cmd->vdev_id = cpu_to_le32(vdev_id); + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); + + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, + "send 11d scan stop vdev id %d\n", + cmd->vdev_id); + + if (ret) { + ath12k_warn(ar->ab, + "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id) { @@ -5705,6 +5778,50 @@ static void ath12k_wmi_op_ep_tx_credits(struct ath12k_base *ab) wake_up(&ab->wmi_ab.tx_credits_wq); } +static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *skb) +{ + const struct wmi_11d_new_cc_event *ev; + struct ath12k *ar; + struct ath12k_pdev *pdev; + const void **tb; + int ret, i; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; + if (!ev) { + kfree(tb); + ath12k_warn(ab, "failed to fetch 11d new cc ev"); + return -EPROTO; + } + + spin_lock_bh(&ab->base_lock); + memcpy(&ab->new_alpha2, &ev->new_alpha2, REG_ALPHA2_LEN); + spin_unlock_bh(&ab->base_lock); + + ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi 11d new cc %c%c\n", + ab->new_alpha2[0], + ab->new_alpha2[1]); + + kfree(tb); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + ar->state_11d = ATH12K_11D_IDLE; + complete(&ar->completed_11d_scan); + } + + queue_work(ab->workqueue, &ab->update_11d_work); + + return 0; +} + static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab, struct sk_buff *skb) { @@ -7308,6 +7425,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_GTK_OFFLOAD_STATUS_EVENTID: ath12k_wmi_gtk_offload_status_event(ab, skb); break; + case WMI_11D_NEW_COUNTRY_EVENTID: + ath12k_reg_11d_new_cc_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 220f530da569..c4e785a31e04 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3860,6 +3860,28 @@ struct wmi_init_country_cmd { } cc_info; } __packed; +struct wmi_11d_scan_start_arg { + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +}; + +struct wmi_11d_scan_start_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 scan_period_msec; + __le32 start_interval_msec; +} __packed; + +struct wmi_11d_scan_stop_cmd { + __le32 tlv_header; + __le32 vdev_id; +} __packed; + +struct wmi_11d_new_cc_event { + __le32 new_alpha2; +} __packed; + struct wmi_delba_send_cmd { __le32 tlv_header; __le32 vdev_id; @@ -5565,6 +5587,9 @@ int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar, dma_addr_t paddr, u8 tid, u8 ba_window_size_valid, u32 ba_window_size); +int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar, + struct wmi_11d_scan_start_arg *arg); +int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id); int ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar, struct ath12k_wmi_rx_reorder_queue_remove_arg *arg); -- 2.34.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v6 3/4] wifi: ath12k: use correct WMI command to set country code for WCN7850 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 2024-10-17 3:09 ` [PATCH v6 1/4] wifi: ath12k: add configure country code for WCN7850 Kang Yang 2024-10-17 3:09 ` [PATCH v6 2/4] wifi: ath12k: add 11d scan offload support Kang Yang @ 2024-10-17 3:09 ` Kang Yang 2024-10-17 3:09 ` [PATCH v6 4/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang ` (2 subsequent siblings) 5 siblings, 0 replies; 19+ messages in thread From: Kang Yang @ 2024-10-17 3:09 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, quic_kangyang From: Wen Gong <quic_wgong@quicinc.com> When userspace try to set country code by NL80211_REGDOM_SET_BY_USER hint(like iw reg set XX), it will pass new country code to ath12k. Then ath12k will set this new country code to firmware by WMI_SET_INIT_COUNTRY_CMDID. But for WCN7850, this WMI command won't take effect. For AP based chips(QCN92xx), WMI_SET_INIT_COUNTRY_CMDID is the correct command. However, for STATION based chips(WCN7850), it need to use 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 WCN7850. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> Signed-off-by: Kang Yang <quic_kangyang@quicinc.com> --- drivers/net/wireless/ath/ath12k/hw.c | 6 ++++++ drivers/net/wireless/ath/ath12k/hw.h | 1 + drivers/net/wireless/ath/ath12k/reg.c | 29 ++++++++++++++++----------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index b7b583fadb5a..65c52e3217c5 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -928,6 +928,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .iova_mask = 0, .supports_aspm = false, + + .current_cc_support = false, }, { .name = "wcn7850 hw2.0", @@ -1008,6 +1010,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .iova_mask = ATH12K_PCIE_MAX_PAYLOAD_SIZE - 1, .supports_aspm = true, + + .current_cc_support = true, }, { .name = "qcn9274 hw2.0", @@ -1084,6 +1088,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .iova_mask = 0, .supports_aspm = false, + + .current_cc_support = false, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 8d52182e28ae..8067b103e266 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -190,6 +190,7 @@ struct ath12k_hw_params { bool reoq_lut_support:1; bool supports_shadow_regs:1; bool supports_aspm:1; + bool current_cc_support:1; u32 num_tcl_banks; u32 max_tx_ring; diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index aecfd55aef59..c7b0d66f4874 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -48,6 +48,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath12k_wmi_init_country_arg arg; + struct wmi_set_current_country_arg current_arg = {}; struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret, i; @@ -77,23 +78,27 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) return; } - /* Set the country code to the firmware and wait for - * the WMI_REG_CHAN_LIST_CC EVENT for updating the - * reg info - */ - arg.flags = ALPHA_IS_SET; - memcpy(&arg.cc_info.alpha2, request->alpha2, 2); - arg.cc_info.alpha2[2] = 0; - /* Allow fresh updates to wiphy regd */ ah->regd_updated = false; /* Send the reg change request to all the radios */ for_each_ar(ah, ar, i) { - ret = ath12k_wmi_send_init_country_cmd(ar, &arg); - if (ret) - ath12k_warn(ar->ab, - "INIT Country code set to fw failed : %d\n", ret); + if (ar->ab->hw_params->current_cc_support) { + memcpy(¤t_arg.alpha2, request->alpha2, 2); + ret = ath12k_wmi_send_set_current_country_cmd(ar, ¤t_arg); + if (ret) + ath12k_warn(ar->ab, + "failed set current country code: %d\n", ret); + } else { + arg.flags = ALPHA_IS_SET; + memcpy(&arg.cc_info.alpha2, request->alpha2, 2); + arg.cc_info.alpha2[2] = 0; + + ret = ath12k_wmi_send_init_country_cmd(ar, &arg); + if (ret) + ath12k_warn(ar->ab, + "failed set INIT Country code: %d\n", ret); + } wiphy_lock(wiphy); ath12k_mac_11d_scan_stop(ar); -- 2.34.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v6 4/4] wifi: ath12k: store and send country code to firmware after recovery 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang ` (2 preceding siblings ...) 2024-10-17 3:09 ` [PATCH v6 3/4] wifi: ath12k: use correct WMI command to set country code for WCN7850 Kang Yang @ 2024-10-17 3:09 ` Kang Yang 2024-10-17 18:55 ` [PATCH v6 0/4] " Jeff Johnson 2024-11-29 12:18 ` Mihai Moldovan 5 siblings, 0 replies; 19+ messages in thread From: Kang Yang @ 2024-10-17 3:09 UTC (permalink / raw) To: ath12k; +Cc: linux-wireless, quic_kangyang From: Wen Gong <quic_wgong@quicinc.com> Currently ath12k does not send the country code to firmware after device recovery. As a result the country code will be the default one which is reported from firmware. Country code is important, so ath12k also need to restore it to the value which was used before recovery. This is only needed for platforms which support the current_cc_support hardware parameter. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> Signed-off-by: Kang Yang <quic_kangyang@quicinc.com> --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 8 ++++++++ drivers/net/wireless/ath/ath12k/reg.c | 1 + 4 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 0a6b089ae050..47c1ab2f683e 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1041,6 +1041,7 @@ static void ath12k_update_11d(struct work_struct *work) pdev = &ab->pdevs[i]; ar = pdev->ar; + memcpy(&ar->alpha2, &arg.alpha2, 2); ret = ath12k_wmi_send_set_current_country_cmd(ar, &arg); if (ret) ath12k_warn(ar->ab, diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3d4ab34d50b3..d24fbf84e3ee 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -688,6 +688,7 @@ struct ath12k { u32 vdev_id_11d_scan; struct completion completed_11d_scan; enum ath12k_11d_state state_11d; + u8 alpha2[REG_ALPHA2_LEN]; bool regdom_set_by_user; bool nlo_enabled; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 0a71867d2540..f59a30f4c573 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8927,6 +8927,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ath12k_warn(ar->ab, "pdev %d successfully recovered\n", ar->pdev->pdev_id); + if (ar->ab->hw_params->current_cc_support && + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { + struct wmi_set_current_country_arg arg = {}; + + memcpy(&arg.alpha2, ar->alpha2, 2); + ath12k_wmi_send_set_current_country_cmd(ar, &arg); + } + if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index c7b0d66f4874..c3ebb0247e6f 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -85,6 +85,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) for_each_ar(ah, ar, i) { if (ar->ab->hw_params->current_cc_support) { memcpy(¤t_arg.alpha2, request->alpha2, 2); + memcpy(&ar->alpha2, ¤t_arg.alpha2, 2); ret = ath12k_wmi_send_set_current_country_cmd(ar, ¤t_arg); if (ret) ath12k_warn(ar->ab, -- 2.34.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang ` (3 preceding siblings ...) 2024-10-17 3:09 ` [PATCH v6 4/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang @ 2024-10-17 18:55 ` Jeff Johnson 2024-11-20 16:50 ` Mihai Moldovan 2024-11-29 12:18 ` Mihai Moldovan 5 siblings, 1 reply; 19+ messages in thread From: Jeff Johnson @ 2024-10-17 18:55 UTC (permalink / raw) To: Kang Yang, ath12k; +Cc: linux-wireless On 10/16/2024 8:09 PM, Kang Yang wrote: > This patch-set mainly does four things: > 1. Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware. > 2. Implement 11d scan offload, and report country code to firmware by > WMI command WMI_SET_CURRENT_COUNTRY_CMDID. > 3. Use WMI_SET_CURRENT_COUNTRY_CMDID to set country code for WCN7850. > 4. Store country code, and update it to firmware after device recovery. > > With this patch-set, WCN7850 can do 11d offload scan and update country > code to firmware successfully. > > Note: This patch-set is an old patch-set in public review written by > Wen Gong. Just resend it for him. > Link: https://patchwork.kernel.org/project/linux-wireless/cover/20230914090746.23560-1-quic_wgong@quicinc.com/ > > v6: rebase on tag: ath/main(ath-202410161539). > v5: rebase on tag: ath/main(ath-202410111606). > v4: rebase on tag: ath-202410072115. > v3: > 1. use wiphy::mtx lock instead of adding a new lock(patch#2). > 2. rename struct according to wmi naming convention(patch#1, #2). > 3. update copyright in reg.h > 4. modifiy patch#3, #4 due to struct name change. > v2: change per Jeff. > 1. change alpha2 length from 3 to 2. > 2. change wmi_11d_new_cc_ev to wmi_11d_new_cc_event. > > Wen Gong (4): > wifi: ath12k: add configure country code for WCN7850 > wifi: ath12k: add 11d scan offload support > wifi: ath12k: use correct WMI command to set country code for WCN7850 > wifi: ath12k: store and send country code to firmware after recovery > > drivers/net/wireless/ath/ath12k/core.c | 34 ++++- > drivers/net/wireless/ath/ath12k/core.h | 17 +++ > drivers/net/wireless/ath/ath12k/hw.c | 6 + > drivers/net/wireless/ath/ath12k/hw.h | 1 + > drivers/net/wireless/ath/ath12k/mac.c | 168 ++++++++++++++++++++++++- > drivers/net/wireless/ath/ath12k/mac.h | 7 ++ > drivers/net/wireless/ath/ath12k/reg.c | 70 ++++++++--- > drivers/net/wireless/ath/ath12k/reg.h | 4 +- > drivers/net/wireless/ath/ath12k/wmi.c | 158 ++++++++++++++++++++++- > drivers/net/wireless/ath/ath12k/wmi.h | 38 ++++++ > 10 files changed, 481 insertions(+), 22 deletions(-) > > > base-commit: fa934bf3e0a825ee09f035c6580af513187d59a2 This series looks ok to me, but it conflicts with the MLO branch so I'll defer this until the MLO branch is merged. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-10-17 18:55 ` [PATCH v6 0/4] " Jeff Johnson @ 2024-11-20 16:50 ` Mihai Moldovan 2024-11-21 11:03 ` Kalle Valo 0 siblings, 1 reply; 19+ messages in thread From: Mihai Moldovan @ 2024-11-20 16:50 UTC (permalink / raw) To: ath12k [-- Attachment #1.1: Type: text/plain, Size: 539 bytes --] * On 10/17/24 20:55, Jeff Johnson wrote: > This series looks ok to me, but it conflicts with the MLO branch so I'll defer > this until the MLO branch is merged. I can understand prioritizing MLO, but would like to point out that without these changes, AP mode is essentially broken/disabled hard on non-2.4 GHz bands (and even the 2.4 GHz band is restricted to channels 1 to 11). If you want to: Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-by: Mihai Moldovan <ionic@ionic.de> [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 840 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-11-20 16:50 ` Mihai Moldovan @ 2024-11-21 11:03 ` Kalle Valo 2024-11-22 20:17 ` Mihai Moldovan 0 siblings, 1 reply; 19+ messages in thread From: Kalle Valo @ 2024-11-21 11:03 UTC (permalink / raw) To: Mihai Moldovan; +Cc: ath12k Mihai Moldovan <ionic@ionic.de> writes: > * On 10/17/24 20:55, Jeff Johnson wrote: >> This series looks ok to me, but it conflicts with the MLO branch so I'll defer >> this until the MLO branch is merged. > > I can understand prioritizing MLO, but would like to point out that > without these changes, AP mode is essentially broken/disabled hard on > non-2.4 GHz bands (and even the 2.4 GHz band is restricted to channels > 1 to 11). But this is not a regression, right? I mean, has it been always broken? It is very unfortunate MLO is currently taking too much of our time but we should get that done soon, I hope. But all help (review, testing etc) is very much appreciated. -- https://patchwork.kernel.org/project/linux-wireless/list/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-11-21 11:03 ` Kalle Valo @ 2024-11-22 20:17 ` Mihai Moldovan 0 siblings, 0 replies; 19+ messages in thread From: Mihai Moldovan @ 2024-11-22 20:17 UTC (permalink / raw) To: Kalle Valo; +Cc: ath12k [-- Attachment #1.1: Type: text/plain, Size: 407 bytes --] * On 11/21/24 12:03, Kalle Valo wrote: > But this is not a regression, right? I mean, has it been always broken? Yeah, true, to the best of my knowledge, running an AP never worked on a non-2.4 GHz band with ath12k since its inception, so it's not a regression. Just wanted to point that out and offer my testing input that it works with this patch set for the hardware I tested. Mihai [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 840 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang ` (4 preceding siblings ...) 2024-10-17 18:55 ` [PATCH v6 0/4] " Jeff Johnson @ 2024-11-29 12:18 ` Mihai Moldovan 2024-12-02 1:53 ` Kang Yang 5 siblings, 1 reply; 19+ messages in thread From: Mihai Moldovan @ 2024-11-29 12:18 UTC (permalink / raw) To: Kang Yang, ath12k [-- Attachment #1.1: Type: text/plain, Size: 3469 bytes --] * On 10/17/24 05:09, Kang Yang wrote: > This patch-set mainly does four things: > 1. Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware. > 2. Implement 11d scan offload, and report country code to firmware by > WMI command WMI_SET_CURRENT_COUNTRY_CMDID. > 3. Use WMI_SET_CURRENT_COUNTRY_CMDID to set country code for WCN7850. > 4. Store country code, and update it to firmware after device recovery. > > With this patch-set, WCN7850 can do 11d offload scan and update country > code to firmware successfully. > > Note: This patch-set is an old patch-set in public review written by > Wen Gong. Just resend it for him. > Link: https://patchwork.kernel.org/project/linux-wireless/cover/20230914090746.23560-1-quic_wgong@quicinc.com/ Have you tested this in AP mode or was testing limited to STA mode? Even with this patch set, hostapd fails to start on a channel that is disabled in the default regdomain, even if 11d is enabled and a CC specified, even after a CC update is requested and CHANEL_LIST_UPDATE is being received. --- 1732881245.637059: wifibe: interface state UNINITIALIZED->COUNTRY_UPDATE 1732881245.637268: Previous country code na, new country code DEI 1732881245.637283: Continue interface setup after channel list update 1732881245.637291: ctrl_iface not configured! 1732881245.637318: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=0 linkmode=0 ifi_family=0 ifi_flags=0x1043 ([UP][RUNNING]) 1732881245.637371: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=2 linkmode=0 ifi_family=0 ifi_flags=0x1003 ([UP]) 1732881245.637404: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=2 linkmode=0 master=5 ifi_family=0 ifi_flags=0x1003 ([UP]) 1732881245.637434: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=2 linkmode=0 master=5 ifi_family=0 ifi_flags=0x1003 ([UP]) 1732881245.637464: RTM_NEWLINK: ifi_index=6 ifname=wifibe master=5 operstate=2 ifi_family=7 ifi_flags=0x1003 ([UP]) 1732881245.637505: nl80211: Add ifindex 5 for bridge brvswitch 1732881245.637514: nl80211: Add own interface ifindex 5 (ifidx_reason 6) 1732881245.637521: nl80211: ifindex 5 already in the list 1732881245.637540: nl80211: Event message available 1732881245.637563: nl80211: Drv Event 36 (NL80211_CMD_REG_CHANGE) received for wifibe 1732881245.637574: nl80211: Regulatory domain change 1732881245.637580: * initiator=1 1732881245.637590: * type=0 1732881245.637595: * alpha2=DE 1732881245.637609: wifibe: Event CHANNEL_LIST_CHANGED (27) received 1732881245.637619: Channel list updated - continue setup 1732881245.638475: nl80211: Regulatory information - country=na 1732881245.638499: nl80211: 2402-2472 @ 40 MHz 20 mBm 1732881245.638512: nl80211: 2457-2482 @ 20 MHz 20 mBm (no IR) [...] --- Interestingly, iw reg get shows the new CC/regdomain after hostapd terminates, so I suspect a race condition: --- phy#0 (self-managed) country DE: DFS-ETSI --- Starting hostapd again after it failed the first time around works, since the CC + regdomain are correctly updated by that time. You recently re-submitted a patch set for ath11k by Wen Gong[0] that is supposed to fix a race condition during reg updates and this smells like the same issue. I'll try to port it to ath12k on top of this patch set to see if it fixes this issue. Mihai [0] https://lore.kernel.org/ath11k/20241129070714.226-1-quic_kangyang@quicinc.com [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 840 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-11-29 12:18 ` Mihai Moldovan @ 2024-12-02 1:53 ` Kang Yang 2024-12-02 8:47 ` Mihai Moldovan 0 siblings, 1 reply; 19+ messages in thread From: Kang Yang @ 2024-12-02 1:53 UTC (permalink / raw) To: Mihai Moldovan, ath12k On 11/29/2024 8:18 PM, Mihai Moldovan wrote: > > Have you tested this in AP mode or was testing limited to STA mode? > Not yet. > Even with this patch set, hostapd fails to start on a channel that is > disabled in the default regdomain, even if 11d is enabled and a CC > specified, even after a CC update is requested and CHANEL_LIST_UPDATE is > being received. > What is the probability of failure? > --- > 1732881245.637059: wifibe: interface state UNINITIALIZED->COUNTRY_UPDATE > > 1732881245.637268: Previous country code na, new country code DEI > 1732881245.637283: Continue interface setup after channel list update > 1732881245.637291: ctrl_iface not configured! > 1732881245.637318: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=0 > linkmode=0 ifi_family=0 ifi_flags=0x1043 ([UP][RUNNING]) > 1732881245.637371: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=2 > linkmode=0 ifi_family=0 ifi_flags=0x1003 ([UP]) > 1732881245.637404: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=2 > linkmode=0 master=5 ifi_family=0 ifi_flags=0x1003 ([UP]) > 1732881245.637434: RTM_NEWLINK: ifi_index=6 ifname=wifibe operstate=2 > linkmode=0 master=5 ifi_family=0 ifi_flags=0x1003 ([UP]) > 1732881245.637464: RTM_NEWLINK: ifi_index=6 ifname=wifibe master=5 > operstate=2 ifi_family=7 ifi_flags=0x1003 ([UP]) > 1732881245.637505: nl80211: Add ifindex 5 for bridge brvswitch > 1732881245.637514: nl80211: Add own interface ifindex 5 (ifidx_reason 6) > 1732881245.637521: nl80211: ifindex 5 already in the list > 1732881245.637540: nl80211: Event message available > 1732881245.637563: nl80211: Drv Event 36 (NL80211_CMD_REG_CHANGE) > received for wifibe > 1732881245.637574: nl80211: Regulatory domain change > 1732881245.637580: * initiator=1 > 1732881245.637590: * type=0 > 1732881245.637595: * alpha2=DE > 1732881245.637609: wifibe: Event CHANNEL_LIST_CHANGED (27) received > > 1732881245.637619: Channel list updated - continue setup > > 1732881245.638475: nl80211: Regulatory information - country=na > 1732881245.638499: nl80211: 2402-2472 @ 40 MHz 20 mBm > 1732881245.638512: nl80211: 2457-2482 @ 20 MHz 20 mBm (no IR) > [...] > --- > > Interestingly, iw reg get shows the new CC/regdomain after hostapd > terminates, so I suspect a race condition: > > --- > phy#0 (self-managed) > country DE: DFS-ETSI > --- > > Starting hostapd again after it failed the first time around works, > since the CC + regdomain are correctly updated by that time. > > > You recently re-submitted a patch set for ath11k by Wen Gong[0] that is > supposed to fix a race condition during reg updates and this smells like > the same issue. I'll try to port it to ath12k on top of this patch set > to see if it fixes this issue. > > Thanks for trying, currently, i'm occupied by other tasks... > > Mihai > > > > [0] https://lore.kernel.org/ath11k/20241129070714.226-1- > quic_kangyang@quicinc.com ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-12-02 1:53 ` Kang Yang @ 2024-12-02 8:47 ` Mihai Moldovan 2024-12-09 21:47 ` [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier Mihai Moldovan 2024-12-11 4:32 ` [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 0 siblings, 2 replies; 19+ messages in thread From: Mihai Moldovan @ 2024-12-02 8:47 UTC (permalink / raw) To: Kang Yang, ath12k [-- Attachment #1.1: Type: text/plain, Size: 2574 bytes --] * On 12/2/24 02:53, Kang Yang wrote: > On 11/29/2024 8:18 PM, Mihai Moldovan wrote: >> Have you tested this in AP mode or was testing limited to STA mode? > > Not yet. Okay, so a useful heads-up, I guess! >> Even with this patch set, hostapd fails to start on a channel that is >> disabled in the default regdomain, even if 11d is enabled and a CC >> specified, even after a CC update is requested and CHANEL_LIST_UPDATE is >> being received. >> > > What is the probability of failure? In my tests, 100 % reproducible, but I admit I haven't stress-tested it. It always fails the first time hostapd is started if the default rules define NO_IR on the channel you want to use (even if CC rules disagree) and can also easily be reproduced by, e.g., using channel 100 with hostapd and setting CC for instance to DE or US in the hostapd config file: # Chinese regulatory does not allow operation on channels 96 to 128. iw reg set CN; hostapd ... => fails iw reg set DE; hostapd ... => works Luckily it's really easy to reproduce. hostapd is special in the sense that it's using netlink directly and this is probably very fast. I was never able to reproduce the issue with iw reg set CN; iw reg set DE; iw list, but I don't find that surprising due to all the overhead and highly different code path. >> You recently re-submitted a patch set for ath11k by Wen Gong[0] that is >> supposed to fix a race condition during reg updates and this smells like >> the same issue. I'll try to port it to ath12k on top of this patch set >> to see if it fixes this issue. >> >> > > Thanks for trying, currently, i'm occupied by other tasks... All good. If and when you try, another heads-up: ath12k is currently running into an rtln deadlock quite often (but not always) when hostapd is stopped (or fails) because that's also bringing the interface down. Fortunately, Baochen Qiang ported the fix for this issue from ath11k to ath12k[0], but it wasn't applied to ath-next or main yet, so you will likely see a very irritating deadlock requiring a hard machine reset if you don't also use his patch when testing. His patch, apart from fixing the deadlock, also ports some parts of the ath11k patch set I mentioned in my previous mail, but unfortunately doesn't fix the chan list update race I'm seeing. I'll dig further into it and hope to come up with something usable in the next few days. Mihai [0] https://lore.kernel.org/ath12k/20240830023901.204746-1-quic_bqiang@quicinc.com/ [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 840 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier 2024-12-02 8:47 ` Mihai Moldovan @ 2024-12-09 21:47 ` Mihai Moldovan 2024-12-09 22:00 ` Ionic 2024-12-10 23:19 ` [RFC] [PATCH v2] " Mihai Moldovan 2024-12-11 4:32 ` [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 1 sibling, 2 replies; 19+ messages in thread From: Mihai Moldovan @ 2024-12-09 21:47 UTC (permalink / raw) To: ath12k, Kang Yang Currently, setting a new regdomain is asynchronous in ath12k, in the sense that the reg_notifier function does not wait for the actual regdomain change to complete, including handling the channel list update. This causes issues with user space programs like hostapd, which listen on a netlink socket, set a new country code, see a reg change event and assume that the reg change actually completed within the driver as well. Unfortunately, this has almost never been the case in my testing, which lead to failures when trying to use channels that are disallowed in the old regdomain, but allowed in the new regdomain. Easy reproducer: iw reg set CN hostapd hostapd.conf # should contain e.g., channel=100 and country_code=DE => fails to start Be nice to user space and wait for ath12k_regd_update to complete prior to exiting the reg_notifier, which is triggered by receiving the channel list update event from the FW. Signed-off-by: Mihai Moldovan <ionic@ionic.de> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 --- drivers/net/wireless/ath/ath12k/core.c | 2 ++ drivers/net/wireless/ath/ath12k/core.h | 3 +++ drivers/net/wireless/ath/ath12k/mac.c | 3 +++ drivers/net/wireless/ath/ath12k/reg.c | 11 +++++++++++ 4 files changed, 19 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 07c6cdd9fcd5..9a226484062f 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1073,6 +1073,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ieee80211_stop_queues(ah->hw); + complete(&ah->completed_regd_update); + for (j = 0; j < ah->num_radio; j++) { ar = &ah->radio[j]; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 0be274f99c99..6507eee32056 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -360,6 +360,7 @@ struct ath12k_vif_iter { #define ATH12K_RX_RATE_TABLE_NUM 320 #define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ) +#define ATH12K_REGD_UPDATE_TIMEOUT_HZ (60 * HZ) struct ath12k_rx_peer_rate_stats { u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1]; @@ -742,6 +743,8 @@ struct ath12k_hw { DECLARE_BITMAP(free_ml_peer_id_map, ATH12K_MAX_MLO_PEERS); + struct completion completed_regd_update; + /* protected by wiphy_lock() */ struct list_head ml_peers; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4cbe8dbdcba9..b76135b4b164 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10649,6 +10649,8 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) ieee80211_unregister_hw(hw); + reinit_completion(&ah->completed_regd_update); + for_each_ar(ah, ar, i) ath12k_mac_cleanup_unregister(ar); @@ -10861,6 +10863,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT); ath12k_reg_init(hw); + init_completion(&ah->completed_regd_update); if (!is_raw_mode) { hw->netdev_features = NETIF_F_HW_CSUM; diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 7d2d887c5dbe..046ad0eadf7e 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -52,6 +52,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret, i; + unsigned long left = 0; ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Regulatory Notification received for %s\n", wiphy_name(wiphy)); @@ -125,6 +126,15 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) ar->regdom_set_by_user = true; } + + left = wait_for_completion_timeout(&ah->completed_regd_update, + ATH12K_REGD_UPDATE_TIMEOUT_HZ); + if (!left) { + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "failed to receive regd update complete: timed out\n"); + } + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "regd update wait left time %ld\n", left); } int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) @@ -343,6 +353,7 @@ int ath12k_regd_update(struct ath12k *ar, bool init) goto skip; ah->regd_updated = true; + complete(&ah->completed_regd_update); skip: return 0; err: -- 2.45.2 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier 2024-12-09 21:47 ` [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier Mihai Moldovan @ 2024-12-09 22:00 ` Ionic 2024-12-11 2:18 ` Kang Yang 2024-12-10 23:19 ` [RFC] [PATCH v2] " Mihai Moldovan 1 sibling, 1 reply; 19+ messages in thread From: Ionic @ 2024-12-09 22:00 UTC (permalink / raw) To: ath12k, Kang Yang * On 12/9/24 22:47, Mihai Moldovan wrote: > Currently, setting a new regdomain is asynchronous in ath12k, in the > [...] Making the reg_notifier synchronous with the actual reg update fixes the issue. In short, when setting a new reg domain, the reg notifier is called as the last step by cfg80211 before sending a regdom change event over netlink, but since the reg_notifier is not waiting for the hardware to apply the new country code to the firmware and update things like the channel list, things can fail in user space. I implemented a regd_update completion in ah and added a wait call in reg_notifier, as well as completing it in regd_update, with (re-)initializers in mac_hw_register and mac_hw_unregister. I'm not quite sure if ah is the correct place for that, but it felt like the most appropriate. ar is too low-level (since multiple ar can share an ah IIRC) and it should generally not be possible to set per-ar regdomains, although per-phy regdomains are possible, but every phy should have an ah (I guess?). Not sure how vdevs play into this. Can you please test and review this? If it's already good, feel free to include it in your series. ath11k is suffering from the same issue - I just haven't noticed it before because the default regdomain of the ath11k-based card I use is set to US, which allows operations on channel 96 to 144. If I set CN first, I can easily reproduce the same issue with ath11k, so I'll have to backport a good patch to ath11k as well. Mihai ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier 2024-12-09 22:00 ` Ionic @ 2024-12-11 2:18 ` Kang Yang 2024-12-11 16:14 ` Mihai Moldovan 0 siblings, 1 reply; 19+ messages in thread From: Kang Yang @ 2024-12-11 2:18 UTC (permalink / raw) To: Ionic, ath12k On 12/10/2024 6:00 AM, Ionic wrote: > * On 12/9/24 22:47, Mihai Moldovan wrote: >> Currently, setting a new regdomain is asynchronous in ath12k, in the >> [...] > > Making the reg_notifier synchronous with the actual reg update fixes the > issue. > > In short, when setting a new reg domain, the reg notifier is called as > the last step by cfg80211 before sending a regdom change event over > netlink, but since the reg_notifier is not waiting for the hardware to > apply the new country code to the firmware and update things like the > channel list, things can fail in user space. > > > I implemented a regd_update completion in ah and added a wait call in > reg_notifier, as well as completing it in regd_update, with > (re-)initializers in mac_hw_register and mac_hw_unregister. > > I'm not quite sure if ah is the correct place for that, but it felt like > the most appropriate. I think this place is right. > ar is too low-level (since multiple ar can share > an ah IIRC) and it should generally not be possible to set per-ar > regdomains, although per-phy regdomains are possible, but every phy > should have an ah (I guess?). If the "phy" you mentioned is one wifi chip, i think you are right. > Not sure how vdevs play into this. Each chip at least have one vdev. > > > Can you please test and review this? If it's already good, feel free to > include it in your series. I will review and test your "RFC v2" > > > ath11k is suffering from the same issue - I just haven't noticed it > before because the default regdomain of the ath11k-based card I use is > set to US, which allows operations on channel 96 to 144. If I set CN > first, I can easily reproduce the same issue with ath11k, so I'll have > to backport a good patch to ath11k as well. > > > > Mihai ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier 2024-12-11 2:18 ` Kang Yang @ 2024-12-11 16:14 ` Mihai Moldovan 0 siblings, 0 replies; 19+ messages in thread From: Mihai Moldovan @ 2024-12-11 16:14 UTC (permalink / raw) To: Kang Yang, ath12k [-- Attachment #1.1: Type: text/plain, Size: 293 bytes --] * On 12/11/24 03:18, Kang Yang wrote: > I will review and test your "RFC v2" Don't test it yet. I found out that it's broken when switching between regdoms (running into the timeout) via: iw reg set CN iw reg set DE ... Will have to fix that first. Wait for v3. Mihai [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 840 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC] [PATCH v2] wifi: ath12k: wait for chan update in reg_notifier 2024-12-09 21:47 ` [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier Mihai Moldovan 2024-12-09 22:00 ` Ionic @ 2024-12-10 23:19 ` Mihai Moldovan 1 sibling, 0 replies; 19+ messages in thread From: Mihai Moldovan @ 2024-12-10 23:19 UTC (permalink / raw) To: ath12k, Kang Yang Currently, setting a new regdomain is asynchronous in ath12k, in the sense that the reg_notifier function does not wait for the actual regdomain change to complete, including handling the channel list update. This causes issues with user space programs like hostapd, which listen on a netlink socket, set a new country code, see a reg change event and assume that the reg change actually completed within the driver as well. Unfortunately, this has almost never been the case in my testing, which lead to failures when trying to use channels that are disallowed in the old regdomain, but allowed in the new regdomain. Easy reproducer: iw reg set CN hostapd hostapd.conf # should contain e.g., channel=100 and country_code=DE => fails to start Be nice to user space and wait for ath12k_regd_update to complete prior to exiting the reg_notifier, which is triggered by receiving the channel list update event from the FW. Signed-off-by: Mihai Moldovan <ionic@ionic.de> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 --- drivers/net/wireless/ath/ath12k/core.c | 2 ++ drivers/net/wireless/ath/ath12k/core.h | 3 +++ drivers/net/wireless/ath/ath12k/mac.c | 3 +++ drivers/net/wireless/ath/ath12k/reg.c | 13 +++++++++++++ 4 files changed, 21 insertions(+) v2: - reinitialize completion in reg_notifier, otherwise the wait call will always time out on subsequent regdom changes diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 07c6cdd9fcd5..9a226484062f 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1073,6 +1073,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ieee80211_stop_queues(ah->hw); + complete(&ah->completed_regd_update); + for (j = 0; j < ah->num_radio; j++) { ar = &ah->radio[j]; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 0be274f99c99..6507eee32056 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -360,6 +360,7 @@ struct ath12k_vif_iter { #define ATH12K_RX_RATE_TABLE_NUM 320 #define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ) +#define ATH12K_REGD_UPDATE_TIMEOUT_HZ (60 * HZ) struct ath12k_rx_peer_rate_stats { u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1]; @@ -742,6 +743,8 @@ struct ath12k_hw { DECLARE_BITMAP(free_ml_peer_id_map, ATH12K_MAX_MLO_PEERS); + struct completion completed_regd_update; + /* protected by wiphy_lock() */ struct list_head ml_peers; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4cbe8dbdcba9..b76135b4b164 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -10649,6 +10649,8 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) ieee80211_unregister_hw(hw); + reinit_completion(&ah->completed_regd_update); + for_each_ar(ah, ar, i) ath12k_mac_cleanup_unregister(ar); @@ -10861,6 +10863,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT); ath12k_reg_init(hw); + init_completion(&ah->completed_regd_update); if (!is_raw_mode) { hw->netdev_features = NETIF_F_HW_CSUM; diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 7d2d887c5dbe..00588b53673d 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -52,6 +52,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret, i; + unsigned long left = 0; ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Regulatory Notification received for %s\n", wiphy_name(wiphy)); @@ -99,6 +100,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) /* Allow fresh updates to wiphy regd */ ah->regd_updated = false; + reinit_completion(&ah->completed_regd_update); + /* Send the reg change request to all the radios */ for_each_ar(ah, ar, i) { if (ar->ab->hw_params->current_cc_support) { @@ -125,6 +128,15 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) ar->regdom_set_by_user = true; } + + left = wait_for_completion_timeout(&ah->completed_regd_update, + ATH12K_REGD_UPDATE_TIMEOUT_HZ); + if (!left) { + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "failed to receive regd update complete: timed out\n"); + } + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "regd update wait left time %ld\n", left); } int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) @@ -343,6 +355,7 @@ int ath12k_regd_update(struct ath12k *ar, bool init) goto skip; ah->regd_updated = true; + complete(&ah->completed_regd_update); skip: return 0; err: -- 2.45.2 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-12-02 8:47 ` Mihai Moldovan 2024-12-09 21:47 ` [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier Mihai Moldovan @ 2024-12-11 4:32 ` Kang Yang 2024-12-11 16:22 ` Mihai Moldovan 1 sibling, 1 reply; 19+ messages in thread From: Kang Yang @ 2024-12-11 4:32 UTC (permalink / raw) To: Mihai Moldovan, ath12k On 12/2/2024 4:47 PM, Mihai Moldovan wrote: > * On 12/2/24 02:53, Kang Yang wrote: >> On 11/29/2024 8:18 PM, Mihai Moldovan wrote: >>> Have you tested this in AP mode or was testing limited to STA mode? >> >> Not yet. > > Okay, so a useful heads-up, I guess! > > >>> Even with this patch set, hostapd fails to start on a channel that is >>> disabled in the default regdomain, even if 11d is enabled and a CC >>> specified, even after a CC update is requested and CHANEL_LIST_UPDATE is >>> being received. >>> >> >> What is the probability of failure? > > In my tests, 100 % reproducible, but I admit I haven't stress-tested it. > > It always fails the first time hostapd is started if the default rules > define NO_IR on the channel you want to use (even if CC rules disagree) > and can also easily be reproduced by, e.g., using channel 100 with > hostapd and setting CC for instance to DE or US in the hostapd config file: > root@NUC8:/home/yk/Desktop/sigma-script# wls1: interface state UNINITIALIZED->COUNTRY_UPDATE Frequency 5500 (primary) not allowed for AP mode, flags: 0x100959 RADAR Primary frequency not allowed wls1: IEEE 802.11 Configured channel (100) or frequency (5500) (secondary_channel=0) not found from the channel list of the current mode (2) IEEE 802.11a Don't know how you test with channel 100, it's a DFS channel. Can you show me your whole hostapd.conf? > # Chinese regulatory does not allow operation on channels 96 to 128. > iw reg set CN; hostapd ... => fails > iw reg set DE; hostapd ... => works > my steps: rmmod ath12k insmod ath12k iw reg set CN hostapd... > Luckily it's really easy to reproduce. > > > hostapd is special in the sense that it's using netlink directly and > this is probably very fast. > > I was never able to reproduce the issue with iw reg set CN; iw reg set > DE; iw list, but I don't find that surprising due to all the overhead > and highly different code path. > > >>> You recently re-submitted a patch set for ath11k by Wen Gong[0] that is >>> supposed to fix a race condition during reg updates and this smells like >>> the same issue. I'll try to port it to ath12k on top of this patch set >>> to see if it fixes this issue. >>> >>> >> >> Thanks for trying, currently, i'm occupied by other tasks... > > All good. > > If and when you try, another heads-up: ath12k is currently running into > an rtln deadlock quite often (but not always) when hostapd is stopped > (or fails) because that's also bringing the interface down. > > Fortunately, Baochen Qiang ported the fix for this issue from ath11k to > ath12k[0], but it wasn't applied to ath-next or main yet, so you will > likely see a very irritating deadlock requiring a hard machine reset if > you don't also use his patch when testing. > > His patch, apart from fixing the deadlock, also ports some parts of the > ath11k patch set I mentioned in my previous mail, but unfortunately > doesn't fix the chan list update race I'm seeing. > > I'll dig further into it and hope to come up with something usable in > the next few days. > > > > Mihai > > > [0] https://lore.kernel.org/ath12k/20240830023901.204746-1- > quic_bqiang@quicinc.com/ ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery 2024-12-11 4:32 ` [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang @ 2024-12-11 16:22 ` Mihai Moldovan 0 siblings, 0 replies; 19+ messages in thread From: Mihai Moldovan @ 2024-12-11 16:22 UTC (permalink / raw) To: Kang Yang, ath12k [-- Attachment #1.1: Type: text/plain, Size: 4009 bytes --] * On 12/11/24 05:32, Kang Yang wrote: > root@NUC8:/home/yk/Desktop/sigma-script# wls1: interface state > UNINITIALIZED->COUNTRY_UPDATE > Frequency 5500 (primary) not allowed for AP mode, flags: 0x100959 RADAR > Primary frequency not allowed > wls1: IEEE 802.11 Configured channel (100) or frequency (5500) > (secondary_channel=0) not found from the channel list of the current > mode (2) IEEE 802.11a > > Don't know how you test with channel 100, it's a DFS channel. > Can you show me your whole hostapd.conf? Sure. DFS must be enabled of course - both in the kernel and in hostapd. Complete hostapd.conf I'm testing with (80 MHz operation on channels 100+): interface=wifibe #bridge=brvswitch # Enabling that will likely fail for you out of the box. driver=nl80211 logger_syslog=-1 logger_syslog_level=0 logger_stdout=-1 logger_stdout_level=2 ctrl_interface=/run/hostapd ctrl_interface_group=0 ssid=WRTKA04 utf8_ssid=1 country_code=DE country3=0x49 ieee80211d=1 ieee80211h=1 hw_mode=a channel=100 acs_num_scans=100 acs_exclude_dfs=0 enable_background_radar=1 min_tx_power=0 beacon_int=100 dtim_period=2 max_num_sta=255 rts_threshold=65535 fragm_threshold=-1 preamble=1 macaddr_acl=1 accept_mac_file=/etc/hostapd/hostapd.accept deny_mac_file=/etc/hostapd/hostapd.deny auth_algs=1 ignore_broadcast_ssid=0 wmm_enabled=1 wmm_ac_bk_cwmin=4 wmm_ac_bk_cwmax=10 wmm_ac_bk_aifs=7 wmm_ac_bk_txop_limit=0 wmm_ac_bk_acm=0 wmm_ac_be_aifs=3 wmm_ac_be_cwmin=4 wmm_ac_be_cwmax=10 wmm_ac_be_txop_limit=0 wmm_ac_be_acm=0 wmm_ac_vi_aifs=2 wmm_ac_vi_cwmin=3 wmm_ac_vi_cwmax=4 wmm_ac_vi_txop_limit=94 wmm_ac_vi_acm=0 wmm_ac_vo_aifs=2 wmm_ac_vo_cwmin=2 wmm_ac_vo_cwmax=3 wmm_ac_vo_txop_limit=47 wmm_ac_vo_acm=0 ap_max_inactivity=7200 bss_max_idle=1 disassoc_low_ack=0 start_disabled=0 ieee80211n=1 disable_11n=0 ht_capab=[HT20][HT40+][HT40-][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][LDCP][DSSS_CCK-40][MAX-AMSDU-7935] require_ht=0 obss_interval=30 ht_vht_twt_responder=1 ieee80211ac=1 disable_11ac=0 vht_capab=[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][SU-BEAMFORMER][SU-BEAMFORMEE][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN] require_vht=0 vht_oper_chwidth=1 vht_oper_centr_freq_seg0_idx=106 vht_oper_centr_freq_seg1_idx=0 ieee80211ax=1 require_he=0 disable_11ax=0 he_su_beamformer=1 he_su_beamformee=1 he_mu_beamformer=1 he_bss_color=39 he_twt_required=0 he_twt_responder=1 he_er_su_disable=0 he_oper_chwidth=1 he_oper_centr_freq_seg0_idx=106 he_oper_centr_freq_seg1_idx=0 he_6ghz_max_mpdu=2 he_6ghz_max_ampdu_len_exp=7 he_6ghz_rx_ant_pat=1 he_6ghz_tx_ant_pat=1 he_6ghz_reg_pwr_type=4 reg_def_cli_eirp_psd=0 reg_sub_cli_eirp_psd=1 unsol_bcast_probe_resp_interval=0 channel_usage=1 peer_to_peer_twt=1 ieee80211be=1 disable_11be=0 eht_su_beamformer=1 eht_su_beamformee=1 eht_mu_beamformer=0 eht_oper_chwidth=1 eht_oper_centr_freq_seg0_idx=106 eht_default_pe_duration=0 eht_bw320_offset=0 punct_bitmap=0 punct_acs_threshold=0 mld_ap=0 eapol_key_index_workaround=0 own_ip_addr=127.0.0.1 wpa=2 extended_key_id=0 wpa_passphrase=BREAKMEnottheactualpassphraseofc wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256 SAE wpa_pairwise=CCMP CCMP-256 GCMP GCMP-256 rsn_pairwise=CCMP CCMP-256 GCMP GCMP-256 ieee80211w=1 group_mgmt_cipher=AES-128-CMAC beacon_prot=1 ocv=1 sae_require_mfp=1 fils_discovery_min_interval=20 fils_discovery_max_interval=8000 ssid_protection=1 ap_table_max_size=255 ap_table_expiration_time=3600 wps_cred_add_sae=1 multi_ap_profile=2 multi_ap_client_disallow=0 friendly_name=WPS 802.11be Access Point manufacturer_url=http://www.ionic.de/ model_description=Wireless 802.11be Access Point wps_rf_bands=a tdls_prohibit=1 tdls_prohibit_chan_switch=1 mbo=0 mbo_cell_data_conn_pref=1 rssi_ignore_probe_request=0 > my steps: > rmmod ath12k > insmod ath12k > iw reg set CN > hostapd... Yep, that should do the trick. Mihai [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 840 bytes --] ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2024-12-11 16:22 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-10-17 3:09 [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 2024-10-17 3:09 ` [PATCH v6 1/4] wifi: ath12k: add configure country code for WCN7850 Kang Yang 2024-10-17 3:09 ` [PATCH v6 2/4] wifi: ath12k: add 11d scan offload support Kang Yang 2024-10-17 3:09 ` [PATCH v6 3/4] wifi: ath12k: use correct WMI command to set country code for WCN7850 Kang Yang 2024-10-17 3:09 ` [PATCH v6 4/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 2024-10-17 18:55 ` [PATCH v6 0/4] " Jeff Johnson 2024-11-20 16:50 ` Mihai Moldovan 2024-11-21 11:03 ` Kalle Valo 2024-11-22 20:17 ` Mihai Moldovan 2024-11-29 12:18 ` Mihai Moldovan 2024-12-02 1:53 ` Kang Yang 2024-12-02 8:47 ` Mihai Moldovan 2024-12-09 21:47 ` [RFC] [PATCH] wifi: ath12k: wait for chan update in reg_notifier Mihai Moldovan 2024-12-09 22:00 ` Ionic 2024-12-11 2:18 ` Kang Yang 2024-12-11 16:14 ` Mihai Moldovan 2024-12-10 23:19 ` [RFC] [PATCH v2] " Mihai Moldovan 2024-12-11 4:32 ` [PATCH v6 0/4] wifi: ath12k: store and send country code to firmware after recovery Kang Yang 2024-12-11 16:22 ` Mihai Moldovan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox