From cf8f3d4deb02a8fdc806c46d4112b69868544697 Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Raja Date: Wed, 15 Feb 2023 20:31:36 +0200 Subject: [PATCH 01/29] wifi: ath11k: Set ext passive scan flag to adjust passive scan start time Set the WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE flag while sending the scan command. If this flag is enabled when the incoming scan request comes with a strict start time and its duration overlaps with next TBTT, then target adjust the start time accordingly for passive scan. Target supporting this feature will advertise WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 Signed-off-by: Tamizh Chelvam Raja Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20221222131720.11368-1-quic_tamizhr@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.c | 8 ++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index b3a7d7bfe17c..7057c7916d5d 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2068,6 +2068,12 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + + if (test_bit(WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE, + ar->ab->wmi_ab.svc_map)) + arg->scan_ctrl_flags_ext |= + WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE; + arg->num_bssid = 1; /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be @@ -2149,6 +2155,8 @@ ath11k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd, /* for adaptive scan mode using 3 bits (21 - 23 bits) */ WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags, param->adaptive_dwell_time_mode); + + cmd->scan_ctrl_flags_ext = param->scan_ctrl_flags_ext; } int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 0a045af5419b..2273d885f7fa 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2093,6 +2093,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_EXT2_MSG = 220, WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246, WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249, + WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263, /* The second 128 bits */ WMI_MAX_EXT_SERVICE = 256, @@ -3223,6 +3224,7 @@ struct wmi_start_scan_cmd { #define WMI_SCAN_DWELL_MODE_MASK 0x00E00000 #define WMI_SCAN_DWELL_MODE_SHIFT 21 +#define WMI_SCAN_FLAG_EXT_PASSIVE_SCAN_START_TIME_ENHANCE 0x00000800 enum { WMI_SCAN_DWELL_MODE_DEFAULT = 0, @@ -3270,6 +3272,7 @@ struct scan_req_params { }; u32 scan_events; }; + u32 scan_ctrl_flags_ext; u32 dwell_time_active; u32 dwell_time_active_2g; u32 dwell_time_passive; From 778f83f889e7fca37780d9640fcbd0229ae38eaa Mon Sep 17 00:00:00 2001 From: "Alexey V. Vissarionov" Date: Wed, 15 Feb 2023 20:31:37 +0200 Subject: [PATCH 02/29] wifi: ath6kl: minor fix for allocation size Although the "param" pointer occupies more or equal space compared to "*param", the allocation size should use the size of variable itself. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: bdcd81707973cf8a ("Add ath6kl cleaned up driver") Signed-off-by: Alexey V. Vissarionov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230117110414.GC12547@altlinux.org --- drivers/net/wireless/ath/ath6kl/bmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c index bde5a10d470c..af98e871199d 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.c +++ b/drivers/net/wireless/ath/ath6kl/bmi.c @@ -246,7 +246,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) return -EACCES; } - size = sizeof(cid) + sizeof(addr) + sizeof(param); + size = sizeof(cid) + sizeof(addr) + sizeof(*param); if (size > ar->bmi.max_cmd_size) { WARN_ON(1); return -EINVAL; From 480c9df5778774117546f6389be1a8dc8cc935db Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 15 Feb 2023 20:31:37 +0200 Subject: [PATCH 03/29] wifi: ath12k: Fix spelling mistakes in warning messages and comments There are quite a few spelling mistakes in warning messages and a lot of the comments. Fix these. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230214092122.265336-1-colin.i.king@gmail.com --- drivers/net/wireless/ath/ath12k/ce.c | 2 +- drivers/net/wireless/ath/ath12k/core.h | 2 +- drivers/net/wireless/ath/ath12k/dp.c | 2 +- drivers/net/wireless/ath/ath12k/dp.h | 6 +++--- drivers/net/wireless/ath/ath12k/dp_mon.c | 10 +++++----- drivers/net/wireless/ath/ath12k/dp_rx.c | 8 ++++---- drivers/net/wireless/ath/ath12k/hal.c | 2 +- drivers/net/wireless/ath/ath12k/hal.h | 12 ++++++------ drivers/net/wireless/ath/ath12k/hal_desc.h | 10 +++++----- drivers/net/wireless/ath/ath12k/rx_desc.h | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 6 +++--- drivers/net/wireless/ath/ath12k/wmi.h | 4 ++-- 12 files changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index aed6987804bf..be0d669d31fc 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -946,7 +946,7 @@ int ath12k_ce_alloc_pipes(struct ath12k_base *ab) ret = ath12k_ce_alloc_pipe(ab, i); if (ret) { - /* Free any parial successful allocation */ + /* Free any partial successful allocation */ ath12k_ce_free_pipes(ab); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index a54ae74543c1..dffa687ee40e 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -691,7 +691,7 @@ struct ath12k_base { /* Below regd's are protected by ab->data_lock */ /* This is the regd set for every radio - * by the firmware during initializatin + * by the firmware during initialization */ struct ieee80211_regdomain *default_regd[MAX_RADIOS]; /* This regd is set during dynamic country setting diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index eb0261500ab0..9926d81c5fe4 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1429,7 +1429,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) } if (dp->spt_info[i].paddr & ATH12K_SPT_4K_ALIGN_CHECK) { - ath12k_warn(ab, "SPT allocated memoty is not 4K aligned"); + ath12k_warn(ab, "SPT allocated memory is not 4K aligned"); ret = -EINVAL; goto free; } diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 36a876d7f61d..7c5dafce5a68 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -371,7 +371,7 @@ struct ath12k_dp { #define HTT_TX_WBM_COMP_STATUS_OFFSET 8 -/* HTT tx completion is overlayed in wbm_release_ring */ +/* HTT tx completion is overlaid in wbm_release_ring */ #define HTT_TX_WBM_COMP_INFO0_STATUS GENMASK(16, 13) #define HTT_TX_WBM_COMP_INFO1_REINJECT_REASON GENMASK(3, 0) #define HTT_TX_WBM_COMP_INFO1_EXCEPTION_FRAME BIT(4) @@ -545,7 +545,7 @@ enum htt_srng_ring_id { * 3'b010: 4 usec * 3'b011: 8 usec (default) * 3'b100: 16 usec - * Others: Reserverd + * Others: Reserved * b'19 - response_required: * Host needs HTT_T2H_MSG_TYPE_SRING_SETUP_DONE as response * b'20:31 - reserved: reserved for future use @@ -1126,7 +1126,7 @@ struct htt_tx_ring_selection_cfg_cmd { __le32 tlv_filter_mask_in1; __le32 tlv_filter_mask_in2; __le32 tlv_filter_mask_in3; - __le32 reserverd[3]; + __le32 reserved[3]; } __packed; #define HTT_TX_RING_TLV_FILTER_MGMT_DMA_LEN GENMASK(3, 0) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index a214797c96a2..4f93e4c95fed 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -813,7 +813,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, spin_unlock_bh(&buf_ring->idr_lock); if (unlikely(!msdu)) { - ath12k_warn(ab, "montior destination with invalid buf_id %d\n", + ath12k_warn(ab, "monitor destination with invalid buf_id %d\n", buf_id); return HAL_RX_MON_STATUS_PPDU_NOT_DONE; } @@ -1124,7 +1124,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct /* PN for multicast packets are not validate in HW, * so skip 802.3 rx path - * Also, fast_rx expectes the STA to be authorized, hence + * Also, fast_rx expects the STA to be authorized, hence * eapol packets are sent in slow path. */ if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol_tkip && @@ -1917,7 +1917,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, spin_unlock_bh(&buf_ring->idr_lock); if (unlikely(!msdu)) { - ath12k_warn(ab, "montior destination with invalid buf_id %d\n", + ath12k_warn(ab, "monitor destination with invalid buf_id %d\n", buf_id); return DP_MON_TX_STATUS_PPDU_NOT_DONE; } @@ -2110,7 +2110,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget, spin_unlock_bh(&buf_ring->idr_lock); if (unlikely(!skb)) { - ath12k_warn(ab, "montior destination with invalid buf_id %d\n", + ath12k_warn(ab, "monitor destination with invalid buf_id %d\n", buf_id); goto move_next; } @@ -2511,7 +2511,7 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, spin_unlock_bh(&buf_ring->idr_lock); if (unlikely(!skb)) { - ath12k_warn(ab, "montior destination with invalid buf_id %d\n", + ath12k_warn(ab, "monitor destination with invalid buf_id %d\n", buf_id); goto move_next; } diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 83a43ad48c51..eb67b3409f85 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2443,7 +2443,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap /* PN for multicast packets are not validate in HW, * so skip 802.3 rx path - * Also, fast_rx expectes the STA to be authorized, hence + * Also, fast_rx expects the STA to be authorized, hence * eapol packets are sent in slow path. */ if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && @@ -2611,7 +2611,7 @@ try_again: if (!desc_info) { desc_info = ath12k_dp_get_rx_desc(ab, cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual desc retrival"); + ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); continue; } } @@ -3297,7 +3297,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, if (!desc_info) { desc_info = ath12k_dp_get_rx_desc(ab, cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual desc retrival"); + ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); return -EINVAL; } } @@ -3718,7 +3718,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!desc_info) { desc_info = ath12k_dp_get_rx_desc(ab, err_info.cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual desc retrival"); + ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); continue; } } diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 95d04819083f..0ec53afe9915 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -609,7 +609,7 @@ static int ath12k_hal_srng_create_config_qcn9274(struct ath12k_base *ab) HAL_WBM0_RELEASE_RING_BASE_LSB(ab); s->reg_size[1] = HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP; - /* Some LMAC rings are not accesed from the host: + /* Some LMAC rings are not accessed from the host: * RXDMA_BUG, RXDMA_DST, RXDMA_MONITOR_BUF, RXDMA_MONITOR_STATUS, * RXDMA_MONITOR_DST, RXDMA_MONITOR_DESC, RXDMA_DIR_BUF_SRC, * RXDMA_RX_MONITOR_BUF, TX_MONITOR_BUF, TX_MONITOR_DST, SW2RXDMA diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index dfbd8bce70e5..0d4fa12ea622 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -270,7 +270,7 @@ struct ath12k_base; #define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW4_EN BIT(5) #define HAL_WBM_SW_COOKIE_CONV_CFG_GLOBAL_EN BIT(8) -/* TCL ring feild mask and offset */ +/* TCL ring field mask and offset */ #define HAL_TCL1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8) #define HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0) #define HAL_TCL1_RING_ID_ENTRY_SIZE GENMASK(7, 0) @@ -296,7 +296,7 @@ struct ath12k_base; #define HAL_TCL1_RING_FIELD_DSCP_TID_MAP6 GENMASK(20, 18) #define HAL_TCL1_RING_FIELD_DSCP_TID_MAP7 GENMASK(23, 21) -/* REO ring feild mask and offset */ +/* REO ring field mask and offset */ #define HAL_REO1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8) #define HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0) #define HAL_REO1_RING_ID_RING_ID GENMASK(15, 8) @@ -738,7 +738,7 @@ struct hal_srng { } u; }; -/* Interrupt mitigation - Batch threshold in terms of numer of frames */ +/* Interrupt mitigation - Batch threshold in terms of number of frames */ #define HAL_SRNG_INT_BATCH_THRESHOLD_TX 256 #define HAL_SRNG_INT_BATCH_THRESHOLD_RX 128 #define HAL_SRNG_INT_BATCH_THRESHOLD_OTHER 1 @@ -813,7 +813,7 @@ enum hal_rx_buf_return_buf_manager { #define HAL_REO_CMD_FLG_UNBLK_RESOURCE BIT(7) #define HAL_REO_CMD_FLG_UNBLK_CACHE BIT(8) -/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* feilds */ +/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* fields */ #define HAL_REO_CMD_UPD0_RX_QUEUE_NUM BIT(8) #define HAL_REO_CMD_UPD0_VLD BIT(9) #define HAL_REO_CMD_UPD0_ALDC BIT(10) @@ -838,7 +838,7 @@ enum hal_rx_buf_return_buf_manager { #define HAL_REO_CMD_UPD0_PN_VALID BIT(29) #define HAL_REO_CMD_UPD0_PN BIT(30) -/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO1_* feilds */ +/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO1_* fields */ #define HAL_REO_CMD_UPD1_VLD BIT(16) #define HAL_REO_CMD_UPD1_ALDC GENMASK(18, 17) #define HAL_REO_CMD_UPD1_DIS_DUP_DETECTION BIT(19) @@ -854,7 +854,7 @@ enum hal_rx_buf_return_buf_manager { #define HAL_REO_CMD_UPD1_PN_HANDLE_ENABLE BIT(30) #define HAL_REO_CMD_UPD1_IGNORE_AMPDU_FLG BIT(31) -/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO2_* feilds */ +/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO2_* fields */ #define HAL_REO_CMD_UPD2_SVLD BIT(10) #define HAL_REO_CMD_UPD2_SSN GENMASK(22, 11) #define HAL_REO_CMD_UPD2_SEQ_2K_ERR BIT(23) diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 2250ca2d19a3..6c17adc6d60b 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -706,7 +706,7 @@ struct rx_msdu_desc { * * msdu_continuation * When set, this MSDU buffer was not able to hold the entire MSDU. - * The next buffer will therefor contain additional information + * The next buffer will therefore contain additional information * related to this MSDU. * * msdu_length @@ -1294,7 +1294,7 @@ struct hal_tcl_data_cmd { * link descriptor. * * tcl_cmd_type - * used to select the type of TCL Command decriptor + * used to select the type of TCL Command descriptor * * desc_type * Indicates the type of address provided in the buf_addr_info. @@ -1408,7 +1408,7 @@ struct hal_tcl_data_cmd { * index_loop_override * When set, address search and packet routing is forced to use * 'search_index' instead of following the register configuration - * seleced by Bank_id. + * selected by Bank_id. * * ring_id * The buffer pointer ring ID. @@ -1990,7 +1990,7 @@ struct hal_wbm_release_ring { * Producer: SW/TQM/RXDMA/REO/SWITCH * Consumer: WBM/SW/FW * - * HTT tx status is overlayed on wbm_release ring on 4-byte words 2, 3, 4 and 5 + * HTT tx status is overlaid on wbm_release ring on 4-byte words 2, 3, 4 and 5 * for software based completions. * * buf_addr_info @@ -2552,7 +2552,7 @@ struct hal_reo_status_hdr { * commands. * * execution_time (in us) - * The amount of time REO took to excecute the command. Note that + * The amount of time REO took to execute the command. Note that * this time does not include the duration of the command waiting * in the command ring, before the execution started. * diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index 5feaff6450ad..f99556a253e5 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -1072,7 +1072,7 @@ struct rx_msdu_end_qcn9274 { * * l4_offset * Depending upon mode bit, this field either indicates the - * L4 offset nin bytes from the start of RX_HEADER (only valid + * L4 offset in bytes from the start of RX_HEADER (only valid * if either ipv4_proto or ipv6_proto is set to 1) or indicates * the offset in bytes to the start of TCP or UDP header from * the start of the IP header after decapsulation (Only valid if diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index f6df14149531..3e6991120e53 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -494,7 +494,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, /* tx/rx chainmask reported from fw depends on the actual hw chains used, * For example, for 4x4 capable macphys, first 4 chains can be used for first - * mac and the remaing 4 chains can be used for the second mac or vice-versa. + * mac and the remaining 4 chains can be used for the second mac or vice-versa. * In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0 * will be advertised for second mac or vice-versa. Compute the shift value * for tx/rx chainmask which will be used to advertise supported ht/vht rates to @@ -1743,7 +1743,7 @@ int ath12k_wmi_vdev_install_key(struct ath12k *ar, int ret, len, key_len_aligned; /* WMI_TAG_ARRAY_BYTE needs to be aligned with 4, the actual key - * length is specifed in cmd->key_len. + * length is specified in cmd->key_len. */ key_len_aligned = roundup(arg->key_len, 4); @@ -5995,7 +5995,7 @@ static void ath12k_service_available_event(struct ath12k_base *ab, struct sk_buf } /* TODO: Use wmi_service_segment_offset information to get the service - * especially when more services are advertised in multiple sevice + * especially when more services are advertised in multiple service * available events. */ for (i = 0, j = WMI_MAX_SERVICE; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 84e3fb918e43..08a8c9e0f59f 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4002,7 +4002,7 @@ struct ath12k_wmi_pdev_radar_event { } __packed; struct wmi_pdev_temperature_event { - /* temperature value in Celcius degree */ + /* temperature value in Celsius degree */ a_sle32 temp; __le32 pdev_id; } __packed; @@ -4192,7 +4192,7 @@ enum wmi_sta_ps_param_tx_wake_threshold { */ enum wmi_sta_ps_param_pspoll_count { WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0, - /* Values greater than 0 indicate the maximum numer of PS-Poll frames + /* Values greater than 0 indicate the maximum number of PS-Poll frames * FW will send before waking up. */ }; From 731e1b36656a30ffa9c77de673695cdc733d6c92 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 15 Feb 2023 20:31:37 +0200 Subject: [PATCH 04/29] wifi: ath12k: dp_mon: Fix unsigned comparison with less than zero The return value from the call to idr_alloc() is int. However, the return value is being assigned to an unsigned int variable 'buf_id', so making 'buf_id' an int. Eliminate the following warning: ./drivers/net/wireless/ath/ath12k/dp_mon.c:1300:15-21: WARNING: Unsigned expression compared with zero: buf_id < 0 Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4060 Signed-off-by: Yang Li Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230215011453.73466-1-yang.lee@linux.alibaba.com --- drivers/net/wireless/ath/ath12k/dp_mon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 4f93e4c95fed..85f8f802340d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1268,7 +1268,8 @@ int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab, struct sk_buff *skb; struct hal_srng *srng; dma_addr_t paddr; - u32 cookie, buf_id; + u32 cookie; + int buf_id; srng = &ab->hal.srng_list[buf_ring->refill_buf_ring.ring_id]; spin_lock_bh(&srng->lock); From df8e8db22c25f3d0f75ee0c79342d4a0841f4757 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 15 Feb 2023 20:31:38 +0200 Subject: [PATCH 05/29] wifi: ath12k: dp_mon: clean up some inconsistent indentings drivers/net/wireless/ath/ath12k/dp_mon.c:532 ath12k_dp_mon_parse_he_sig_su() warn: inconsistent indenting Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4062 Signed-off-by: Yang Li Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230215012548.90989-1-yang.lee@linux.alibaba.com --- drivers/net/wireless/ath/ath12k/dp_mon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 85f8f802340d..f1e57e98bdc6 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -529,12 +529,12 @@ static void ath12k_dp_mon_parse_he_sig_su(u8 *tlv_data, case 3: if (he_dcm && he_stbc) { he_gi = HE_GI_0_8; - he_ltf = HE_LTF_4_X; + he_ltf = HE_LTF_4_X; } else { he_gi = HE_GI_3_2; he_ltf = HE_LTF_4_X; - } - break; + } + break; } ppdu_info->gi = he_gi; value = he_gi << HE_GI_SHIFT; From 3c3ab8c9a29662ef25f8f62b8f118cd9b0eadd88 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 15 Feb 2023 20:31:38 +0200 Subject: [PATCH 06/29] wifi: ath10k: Remove the unused function shadow_dst_wr_ind_addr() and ath10k_ce_error_intr_enable() The function shadow_dst_wr_ind_addr() and ath10k_ce_error_intr_enable() are defined in the ce.c file, the code calling them has been removed, so remove these unused functions. Eliminate the following warnings: drivers/net/wireless/ath/ath10k/ce.c:80:19: warning: unused function 'shadow_dst_wr_ind_addr' drivers/net/wireless/ath/ath10k/ce.c:441:20: warning: unused function 'ath10k_ce_error_intr_enable' Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4063 Signed-off-by: Yang Li Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230215014058.116775-1-yang.lee@linux.alibaba.com --- drivers/net/wireless/ath/ath10k/ce.c | 52 ---------------------------- 1 file changed, 52 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index c2f3bd35c392..b656cfc03648 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -77,45 +77,6 @@ static inline u32 shadow_sr_wr_ind_addr(struct ath10k *ar, return addr; } -static inline u32 shadow_dst_wr_ind_addr(struct ath10k *ar, - struct ath10k_ce_pipe *ce_state) -{ - u32 ce_id = ce_state->id; - u32 addr = 0; - - switch (ce_id) { - case 1: - addr = 0x00032034; - break; - case 2: - addr = 0x00032038; - break; - case 5: - addr = 0x00032044; - break; - case 7: - addr = 0x0003204C; - break; - case 8: - addr = 0x00032050; - break; - case 9: - addr = 0x00032054; - break; - case 10: - addr = 0x00032058; - break; - case 11: - addr = 0x0003205C; - break; - default: - ath10k_warn(ar, "invalid CE id: %d", ce_id); - break; - } - - return addr; -} - static inline unsigned int ath10k_set_ring_byte(unsigned int offset, struct ath10k_hw_ce_regs_addr_map *addr_map) @@ -438,19 +399,6 @@ static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, host_ie_addr & ~(wm_regs->wm_mask)); } -static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, - u32 ce_ctrl_addr) -{ - struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; - - u32 misc_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->misc_ie_addr); - - ath10k_ce_write32(ar, - ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, - misc_ie_addr | misc_regs->err_mask); -} - static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { From bfcc8ba45eb87bfaaff900bbad2b87b204899d41 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 15 Feb 2023 20:31:38 +0200 Subject: [PATCH 07/29] wifi: ath: Silence memcpy run-time false positive warning The memcpy() in ath_key_config() was attempting to write across neighboring struct members in struct ath_keyval. Introduce a wrapping struct_group, kv_values, to be the addressable target of the memcpy without overflowing an individual member. Silences the false positive run-time warning: memcpy: detected field-spanning write (size 32) of single field "hk.kv_val" at drivers/net/wireless/ath/key.c:506 (size 16) Link: https://bbs.archlinux.org/viewtopic.php?id=282254 Cc: Kalle Valo Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230210054310.never.554-kees@kernel.org --- drivers/net/wireless/ath/ath.h | 12 +++++++----- drivers/net/wireless/ath/key.c | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index f083fb9038c3..f02a308a9ffc 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -96,11 +96,13 @@ struct ath_keyval { u8 kv_type; u8 kv_pad; u16 kv_len; - u8 kv_val[16]; /* TK */ - u8 kv_mic[8]; /* Michael MIC key */ - u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware - * supports both MIC keys in the same key cache entry; - * in that case, kv_mic is the RX key) */ + struct_group(kv_values, + u8 kv_val[16]; /* TK */ + u8 kv_mic[8]; /* Michael MIC key */ + u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware + * supports both MIC keys in the same key cache entry; + * in that case, kv_mic is the RX key) */ + ); }; enum ath_cipher { diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 61b59a804e30..b7b61d4f02ba 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -503,7 +503,7 @@ int ath_key_config(struct ath_common *common, hk.kv_len = key->keylen; if (key->keylen) - memcpy(hk.kv_val, key->key, key->keylen); + memcpy(&hk.kv_values, key->key, key->keylen); if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { switch (vif->type) { From 8c464d16809fa02982f6341ea598ec5d07457f19 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 16 Feb 2023 15:16:14 +0300 Subject: [PATCH 08/29] wifi: ath12k: use kfree_skb() instead of kfree() Sk_buffs are supposed to be freed with kfree_skb(). Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/Y+4ejiYakhEvEw7c@kili --- drivers/net/wireless/ath/ath12k/dp_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 95294f35155c..fd8d850f9818 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -270,7 +270,7 @@ tcl_ring_sel: skb_ext_desc->len, DMA_TO_DEVICE); ret = dma_mapping_error(ab->dev, ti.paddr); if (ret) { - kfree(skb_ext_desc); + kfree_skb(skb_ext_desc); goto fail_unmap_dma; } From 342fcde9d91460f01f65707e16368a1571271a3a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 17 Feb 2023 11:00:31 +0800 Subject: [PATCH 09/29] wifi: ath11k: fix return value check in ath11k_ahb_probe() ioremap() returns NULL pointer not PTR_ERR() when it fails, so replace the IS_ERR() check with NULL pointer check. Fixes: b42b3678c91f ("wifi: ath11k: remap ce register space for IPQ5018") Signed-off-by: Yang Yingliang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230217030031.4021289-1-yangyingliang@huawei.com --- drivers/net/wireless/ath/ath11k/ahb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index cd48eca494ed..022caacd2822 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1174,7 +1174,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) * to a new space for accessing them. */ ab->mem_ce = ioremap(ce_remap->base, ce_remap->size); - if (IS_ERR(ab->mem_ce)) { + if (!ab->mem_ce) { dev_err(&pdev->dev, "ce ioremap error\n"); ret = -ENOMEM; goto err_core_free; From 7654cc03eb699297130b693ec34e25f77b17c947 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Thu, 16 Feb 2023 22:23:01 +0300 Subject: [PATCH 10/29] wifi: ath9k: hif_usb: fix memory leak of remain_skbs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hif_dev->remain_skb is allocated and used exclusively in ath9k_hif_usb_rx_stream(). It is implied that an allocated remain_skb is processed and subsequently freed (in error paths) only during the next call of ath9k_hif_usb_rx_stream(). So, if the urbs are deallocated between those two calls due to the device deinitialization or suspend, it is possible that ath9k_hif_usb_rx_stream() is not called next time and the allocated remain_skb is leaked. Our local Syzkaller instance was able to trigger that. remain_skb makes sense when receiving two consecutive urbs which are logically linked together, i.e. a specific data field from the first skb indicates a cached skb to be allocated, memcpy'd with some data and subsequently processed in the next call to ath9k_hif_usb_rx_stream(). Urbs deallocation supposedly makes that link irrelevant so we need to free the cached skb in those cases. Fix the leak by introducing a function to explicitly free remain_skb (if it is not NULL) when the rx urbs have been deallocated. remain_skb is NULL when it has not been allocated at all (hif_dev struct is kzalloced) or when it has been processed in next call to ath9k_hif_usb_rx_stream(). Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.") Signed-off-by: Fedor Pchelkin Signed-off-by: Alexey Khoroshilov Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230216192301.171225-1-pchelkin@ispras.ru --- drivers/net/wireless/ath/ath9k/hif_usb.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f521dfa2f194..e0130beb304d 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -534,6 +534,24 @@ static struct ath9k_htc_hif hif_usb = { .send = hif_usb_send, }; +/* Need to free remain_skb allocated in ath9k_hif_usb_rx_stream + * in case ath9k_hif_usb_rx_stream wasn't called next time to + * process the buffer and subsequently free it. + */ +static void ath9k_hif_usb_free_rx_remain_skb(struct hif_device_usb *hif_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&hif_dev->rx_lock, flags); + if (hif_dev->remain_skb) { + dev_kfree_skb_any(hif_dev->remain_skb); + hif_dev->remain_skb = NULL; + hif_dev->rx_remain_len = 0; + RX_STAT_INC(hif_dev, skb_dropped); + } + spin_unlock_irqrestore(&hif_dev->rx_lock, flags); +} + static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, struct sk_buff *skb) { @@ -868,6 +886,7 @@ err: static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev) { usb_kill_anchored_urbs(&hif_dev->rx_submitted); + ath9k_hif_usb_free_rx_remain_skb(hif_dev); } static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) From 95a389e2ff3212d866cc51c77d682d2934074eb8 Mon Sep 17 00:00:00 2001 From: Ramya Gnanasekar Date: Sun, 22 Jan 2023 07:19:36 +0530 Subject: [PATCH 11/29] wifi: ath12k: Handle lock during peer_id find ath12k_peer_find_by_id() requires that the caller hold the ab->base_lock. Currently the WBM error path does not hold the lock and calling that function, leads to the following lockdep_assert()in QCN9274: [105162.160893] ------------[ cut here ]------------ [105162.160916] WARNING: CPU: 3 PID: 0 at drivers/net/wireless/ath/ath12k/peer.c:71 ath12k_peer_find_by_id+0x52/0x60 [ath12k] [105162.160933] Modules linked in: ath12k(O) qrtr_mhi qrtr mac80211 cfg80211 mhi qmi_helpers libarc4 nvme nvme_core [last unloaded: ath12k(O)] [105162.160967] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G W O 6.1.0-rc2+ #3 [105162.160972] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0056.2019.0506.1527 05/06/2019 [105162.160977] RIP: 0010:ath12k_peer_find_by_id+0x52/0x60 [ath12k] [105162.160990] Code: 07 eb 0f 39 68 24 74 0a 48 8b 00 48 39 f8 75 f3 31 c0 5b 5d c3 48 8d bf b0 f2 00 00 be ff ff ff ff e8 22 20 c4 e2 85 c0 75 bf <0f> 0b eb bb 66 2e 0f 1f 84 00 00 00 00 00 41 54 4c 8d a7 98 f2 00 [105162.160996] RSP: 0018:ffffa223001acc60 EFLAGS: 00010246 [105162.161003] RAX: 0000000000000000 RBX: ffff9f0573940000 RCX: 0000000000000000 [105162.161008] RDX: 0000000000000001 RSI: ffffffffa3951c8e RDI: ffffffffa39a96d7 [105162.161013] RBP: 000000000000000a R08: 0000000000000000 R09: 0000000000000000 [105162.161017] R10: ffffa223001acb40 R11: ffffffffa3d57c60 R12: ffff9f057394f2e0 [105162.161022] R13: ffff9f0573940000 R14: ffff9f04ecd659c0 R15: ffff9f04d5a9b040 [105162.161026] FS: 0000000000000000(0000) GS:ffff9f0575600000(0000) knlGS:0000000000000000 [105162.161031] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [105162.161036] CR2: 00001d5c8277a008 CR3: 00000001e6224006 CR4: 00000000003706e0 [105162.161041] Call Trace: [105162.161046] [105162.161051] ath12k_dp_rx_process_wbm_err+0x6da/0xaf0 [ath12k] [105162.161072] ? ath12k_dp_rx_process_err+0x80e/0x15a0 [ath12k] [105162.161084] ? __lock_acquire+0x4ca/0x1a60 [105162.161104] ath12k_dp_service_srng+0x263/0x310 [ath12k] [105162.161120] ath12k_pci_ext_grp_napi_poll+0x1c/0x70 [ath12k] [105162.161133] __napi_poll+0x22/0x260 [105162.161141] net_rx_action+0x2f8/0x380 [105162.161153] __do_softirq+0xd0/0x4c9 [105162.161162] irq_exit_rcu+0x88/0xe0 [105162.161169] common_interrupt+0xa5/0xc0 [105162.161174] [105162.161179] [105162.161184] asm_common_interrupt+0x22/0x40 Handle spin lock/unlock in WBM error path to hold the necessary lock expected by ath12k_peer_find_by_id(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-03171-QCAHKSWPL_SILICONZ-1 Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230122014936.3594-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index eb67b3409f85..0adcbcfa0db5 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3494,11 +3494,14 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu, msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); peer_id = ath12k_dp_rx_h_peer_id(ab, desc); + spin_lock(&ab->base_lock); if (!ath12k_peer_find_by_id(ab, peer_id)) { + spin_unlock(&ab->base_lock); ath12k_dbg(ab, ATH12K_DBG_DATA, "invalid peer id received in wbm err pkt%d\n", peer_id); return -EINVAL; } + spin_unlock(&ab->base_lock); if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) { /* First buffer will be freed by the caller, so deduct it's length */ From 80e396586d0a94c42015dd9472176d89a3b0e4ca Mon Sep 17 00:00:00 2001 From: Ramya Gnanasekar Date: Mon, 23 Jan 2023 15:21:41 +0530 Subject: [PATCH 12/29] wifi: ath12k: PCI ops for wakeup/release MHI Wakeup/release MHI is not needed before pci_read/write for QCN9274. Since wakeup & release MHI is enabled for all QCN9274 and WCN7850, below MHI assert is seen in QCN9274 [ 784.906613] BUG: sleeping function called from invalid context at drivers/bus/mhi/host/pm.c:989 [ 784.906633] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 0, name: swapper/3 [ 784.906637] preempt_count: 503, expected: 0 [ 784.906641] RCU nest depth: 0, expected: 0 [ 784.906644] 2 locks held by swapper/3/0: [ 784.906646] #0: ffff8ed348e429e0 (&ab->ce.ce_lock){+.-.}-{2:2}, at: ath12k_ce_recv_process_cb+0xb3/0x2f0 [ath12k] [ 784.906664] #1: ffff8ed348e491f0 (&srng->lock_key#3){+.-.}-{2:2}, at: ath12k_ce_recv_process_cb+0xfb/0x2f0 [ath12k] [ 784.906678] Preemption disabled at: [ 784.906680] [<0000000000000000>] 0x0 [ 784.906686] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G W O 6.1.0-rc2+ #3 [ 784.906688] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0056.2019.0506.1527 05/06/2019 [ 784.906690] Call Trace: [ 784.906691] [ 784.906693] dump_stack_lvl+0x56/0x7b [ 784.906698] __might_resched+0x21c/0x270 [ 784.906704] __mhi_device_get_sync+0x7d/0x1c0 [mhi] [ 784.906714] mhi_device_get_sync+0xd/0x20 [mhi] [ 784.906719] ath12k_pci_write32+0x75/0x170 [ath12k] [ 784.906729] ath12k_hal_srng_access_end+0x55/0xc0 [ath12k] [ 784.906737] ath12k_ce_recv_process_cb+0x1f3/0x2f0 [ath12k] [ 784.906776] ? ath12k_pci_ce_tasklet+0x11/0x30 [ath12k] [ 784.906788] ath12k_pci_ce_tasklet+0x11/0x30 [ath12k] [ 784.906813] tasklet_action_common.isra.18+0xb7/0xe0 [ 784.906820] __do_softirq+0xd0/0x4c9 [ 784.906826] irq_exit_rcu+0x88/0xe0 [ 784.906828] common_interrupt+0xa5/0xc0 [ 784.906831] [ 784.906832] Adding function callbacks for MHI wakeup and release operations. QCN9274 does not need wakeup/release, function callbacks are initialized to NULL. In case of WCN7850, shadow registers are used to access rings. Since, shadow register's offset is less than ACCESS_ALWAYS_OFF, mhi_device_get_sync() or mhi_device_put() to wakeup and release mhi will not be called during service ring accesses. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-03171-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230123095141.5310-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 47 ++++++++++++++++++++++----- drivers/net/wireless/ath/ath12k/pci.h | 6 ++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index ae7f6083c9fc..d32637b0113d 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -119,6 +119,30 @@ static const char *irq_name[ATH12K_IRQ_NUM_MAX] = { "tcl2host-status-ring", }; +static int ath12k_pci_bus_wake_up(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + + return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); +} + +static void ath12k_pci_bus_release(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); +} + +static const struct ath12k_pci_ops ath12k_pci_ops_qcn9274 = { + .wakeup = NULL, + .release = NULL, +}; + +static const struct ath12k_pci_ops ath12k_pci_ops_wcn7850 = { + .wakeup = ath12k_pci_bus_wake_up, + .release = ath12k_pci_bus_release, +}; + static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset) { struct ath12k_base *ab = ab_pci->ab; @@ -989,13 +1013,14 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); u32 val, window_start; + int ret = 0; /* for offset beyond BAR + 4K - 32, may * need to wakeup MHI to access. */ if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && - offset >= ACCESS_ALWAYS_OFF) - mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->wakeup) + ret = ab_pci->pci_ops->wakeup(ab); if (offset < WINDOW_START) { val = ioread32(ab->mem + offset); @@ -1023,9 +1048,9 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset) } if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && - offset >= ACCESS_ALWAYS_OFF) - mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); - + offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->release && + !ret) + ab_pci->pci_ops->release(ab); return val; } @@ -1033,13 +1058,14 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); u32 window_start; + int ret = 0; /* for offset beyond BAR + 4K - 32, may * need to wakeup MHI to access. */ if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && - offset >= ACCESS_ALWAYS_OFF) - mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->wakeup) + ret = ab_pci->pci_ops->wakeup(ab); if (offset < WINDOW_START) { iowrite32(value, ab->mem + offset); @@ -1067,8 +1093,9 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) } if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && - offset >= ACCESS_ALWAYS_OFF) - mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->release && + !ret) + ab_pci->pci_ops->release(ab); } int ath12k_pci_power_up(struct ath12k_base *ab) @@ -1182,6 +1209,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, case QCN9274_DEVICE_ID: ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = true; + ab_pci->pci_ops = &ath12k_pci_ops_qcn9274; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { @@ -1202,6 +1230,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; ab->hw_rev = ATH12K_HW_WCN7850_HW20; + ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; break; default: diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 0d9e40ab31f2..0f24fd9395cd 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -86,6 +86,11 @@ enum ath12k_pci_flags { ATH12K_PCI_ASPM_RESTORE, }; +struct ath12k_pci_ops { + int (*wakeup)(struct ath12k_base *ab); + void (*release)(struct ath12k_base *ab); +}; + struct ath12k_pci { struct pci_dev *pdev; struct ath12k_base *ab; @@ -103,6 +108,7 @@ struct ath12k_pci { /* enum ath12k_pci_flags */ unsigned long flags; u16 link_ctl; + const struct ath12k_pci_ops *pci_ops; }; static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab) From f117276638b7600b981b3fe28550823cfbe1ef23 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 1 Feb 2023 08:54:42 -0800 Subject: [PATCH 13/29] wifi: ath11k: Use platform_get_irq() to get the interrupt As of commit a1a2b7125e10 ("of/platform: Drop static setup of IRQ resource from DT core"), we need to use platform_get_irq() instead of platform_get_resource() to get our IRQs because platform_get_resource() simply won't get them anymore. This was already fixed in several other Atheros WiFi drivers, apparently in response to Zeal Robot reports. An example of another fix is commit 9503a1fc123d ("ath9k: Use platform_get_irq() to get the interrupt"). ath11k seems to have been missed in this effort, though. Without this change, WiFi wasn't coming up on my Qualcomm sc7280-based hardware. Specifically, "platform_get_resource(pdev, IORESOURCE_IRQ, i)" was failing even for i=0. Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00887-QCAMSLSWPLZ-1 Fixes: a1a2b7125e10 ("of/platform: Drop static setup of IRQ resource from DT core") Fixes: 00402f49d26f ("ath11k: Add support for WCN6750 device") Signed-off-by: Douglas Anderson Tested-by: Jun Yu Reviewed-by: Lad Prabhakar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230201084131.v2.1.I69cf3d56c97098287fe3a70084ee515098390b70@changeid --- drivers/net/wireless/ath/ath11k/ahb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 022caacd2822..6b6059d5dc38 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -874,11 +874,11 @@ static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab) ab->pci.msi.ep_base_data = int_prop + 32; for (i = 0; i < ab->pci.msi.config->total_vectors; i++) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, i); - if (!res) - return -ENODEV; + ret = platform_get_irq(pdev, i); + if (ret < 0) + return ret; - ab->pci.msi.irqs[i] = res->start; + ab->pci.msi.irqs[i] = ret; } set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); From 95c95251d0547b46d6571e4fbd51b42865c15a4a Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 1 Feb 2023 08:54:43 -0800 Subject: [PATCH 14/29] wifi: ath5k: Use platform_get_irq() to get the interrupt As of commit a1a2b7125e10 ("of/platform: Drop static setup of IRQ resource from DT core"), we need to use platform_get_irq() instead of platform_get_resource() to get our IRQs because platform_get_resource() simply won't get them anymore. This was already fixed in several other Atheros WiFi drivers, apparently in response to Zeal Robot reports. An example of another fix is commit 9503a1fc123d ("ath9k: Use platform_get_irq() to get the interrupt"). ath5k seems to have been missed in this effort, though. Fixes: a1a2b7125e10 ("of/platform: Drop static setup of IRQ resource from DT core") Signed-off-by: Douglas Anderson Reviewed-by: Lad Prabhakar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230201084131.v2.2.Ic4f8542b0588d7eb4bc6e322d4af3d2064e84ff0@changeid --- drivers/net/wireless/ath/ath5k/ahb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 2c9cec8b53d9..28a1e5eff204 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -113,15 +113,13 @@ static int ath_ahb_probe(struct platform_device *pdev) goto err_out; } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no IRQ resource found\n"); - ret = -ENXIO; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq); + ret = irq; goto err_iounmap; } - irq = res->start; - hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops); if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); From 4c856ee12df85aabd437c3836ed9f68d94268358 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Feb 2023 16:15:48 +0300 Subject: [PATCH 15/29] wifi: ath5k: fix an off by one check in ath5k_eeprom_read_freq_list() This loop checks that i < max at the start of loop but then it does i++ which could put it past the end of the array. It's harmless to check again and prevent a potential out of bounds. Fixes: 1048643ea94d ("ath5k: Clean up eeprom parsing and add missing calibration data") Signed-off-by: Dan Carpenter Reviewed-by: Luis Chamberlain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/Y+D9hPQrHfWBJhXz@kili --- drivers/net/wireless/ath/ath5k/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index d444b3d70ba2..58d3e86f6256 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -529,7 +529,7 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, ee->ee_n_piers[mode]++; freq2 = (val >> 8) & 0xff; - if (!freq2) + if (!freq2 || i >= max) break; pc[i++].freq = ath5k_eeprom_bin2freq(ee, From 8c68fe00344c01bfba95b9f978af0aa236a821f7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 3 Feb 2023 00:01:40 +0000 Subject: [PATCH 16/29] wifi: ath10k: snoc: enable threaded napi on WCN3990 NAPI poll can be done in threaded context along with soft irq context. Threaded context can be scheduled efficiently, thus creating less of bottleneck during Rx processing. This patch is to enable threaded NAPI on ath10k driver. Based on testing, it was observed that on WCN3990, the CPU0 reaches 100% utilization when napi runs in softirq context. At the same time the other CPUs are at low consumption percentage. This does not allow device to reach its maximum throughput potential. After enabling threaded napi, CPU load is balanced across all CPUs and following improvments were observed: - UDP_RX increase by ~22-25% - TCP_RX increase by ~15% Here are some of the additional raw data with and without threaded napi: ================================================== udp_rx(Without threaded NAPI) 435.98+-5.16 : Channel 44 439.06+-0.66 : Channel 157 udp_rx(With threaded NAPI) 509.73+-41.03 : Channel 44 549.97+-7.62 : Channel 157 =================================================== udp_tx(Without threaded NAPI) 461.31+-0.69 : Channel 44 461.46+-0.78 : Channel 157 udp_tx(With threaded NAPI) 459.20+-0.77 : Channel 44 459.78+-1.08 : Channel 157 =================================================== tcp_rx(Without threaded NAPI) 472.63+-2.35 : Channel 44 469.29+-6.31 : Channel 157 tcp_rx(With threaded NAPI) 498.49+-2.44 : Channel 44 541.14+-40.65 : Channel 157 =================================================== tcp_tx(Without threaded NAPI) 317.34+-2.37 : Channel 44 317.01+-2.56 : Channel 157 tcp_tx(With threaded NAPI) 371.34+-2.36 : Channel 44 376.95+-9.40 : Channel 157 =================================================== Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.3.2.2-00696-QCAHLSWMTPL-1 Signed-off-by: Abhishek Kumar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230203000116.v2.1.I5bb9c164a2d2025655dee810b983e01ecd81c14e@changeid --- drivers/net/wireless/ath/ath10k/snoc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index cfcb759a87de..0f6d2f67ff6b 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -927,6 +927,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX); + dev_set_threaded(&ar->napi_dev, true); ath10k_core_napi_enable(ar); ath10k_snoc_irq_enable(ar); ath10k_snoc_rx_post(ar); From 7c4c511f74ba65a18f0beeb9b2fc0e34f28ee79d Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 7 Feb 2023 13:24:10 +0800 Subject: [PATCH 17/29] wifi: ath10k: Remove redundant assignment to changed_flags Variable changed_flags is assigned, but is not effectively used, so delete it. drivers/net/wireless/ath/ath10k/mac.c:6024:22: warning: parameter 'changed_flags' set but not used. Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3963 Signed-off-by: Jiapeng Chong Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230207052410.26337-1-jiapeng.chong@linux.alibaba.com --- drivers/net/wireless/ath/ath10k/mac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ec8d5b29bc72..7675858f069b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6030,7 +6030,6 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); - changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; ar->filter_flags = *total_flags; From 60b7d62ba8cdbd073997bff0f1cdae8d844002c0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 9 Feb 2023 23:26:22 +0100 Subject: [PATCH 18/29] wifi: ath11k: fix SAC bug on peer addition with sta band migration Fix sleep in atomic context warning detected by Smatch static checker analyzer. Following the locking pattern for peer_rhash_add lock tbl_mtx_lock mutex always even if sta is not transitioning to another band. This is peer_add function and a more secure locking should not cause performance regression. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1 Fixes: d673cb6fe6c0 ("wifi: ath11k: fix peer addition/deletion error on sta band migration") Reported-by: Dan Carpenter Signed-off-by: Christian Marangi Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230209222622.1751-1-ansuelsmth@gmail.com --- drivers/net/wireless/ath/ath11k/peer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 1ae7af02c364..1380811827a8 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -382,22 +382,23 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, return -ENOBUFS; } + mutex_lock(&ar->ab->tbl_mtx_lock); spin_lock_bh(&ar->ab->base_lock); peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr); if (peer) { if (peer->vdev_id == param->vdev_id) { spin_unlock_bh(&ar->ab->base_lock); + mutex_unlock(&ar->ab->tbl_mtx_lock); return -EINVAL; } /* Assume sta is transitioning to another band. * Remove here the peer from rhash. */ - mutex_lock(&ar->ab->tbl_mtx_lock); ath11k_peer_rhash_delete(ar->ab, peer); - mutex_unlock(&ar->ab->tbl_mtx_lock); } spin_unlock_bh(&ar->ab->base_lock); + mutex_unlock(&ar->ab->tbl_mtx_lock); ret = ath11k_wmi_send_peer_create_cmd(ar, param); if (ret) { From 4a51e66fe96dfde76894c4eb445ef1b14d312014 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 2 Feb 2023 21:58:10 +0100 Subject: [PATCH 19/29] wifi: wcn36xx: Slightly optimize PREPARE_HAL_BUF() In most (likely all) cases, INIT_HAL_MSG() is called before PREPARE_HAL_BUF(). In such cases calling memset() is useless because: msg_body.header.len = sizeof(msg_body) So, instead of writing twice the memory, we just have a sanity check to make sure that some potential trailing memory is zeroed. It even gives the opportunity to see that by itself and optimize it away. Signed-off-by: Christophe JAILLET Acked-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/7d8ab7fee45222cdbaf80c507525f2d3941587c1.1675371372.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 566f0b9c1584..17e1919d1cd8 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -475,8 +475,8 @@ out: #define PREPARE_HAL_BUF(send_buf, msg_body) \ do { \ - memset(send_buf, 0, msg_body.header.len); \ - memcpy(send_buf, &msg_body, sizeof(msg_body)); \ + memcpy_and_pad(send_buf, msg_body.header.len, \ + &msg_body, sizeof(msg_body), 0); \ } while (0) \ #define PREPARE_HAL_PTT_MSG_BUF(send_buf, p_msg_body) \ From 28013c35629647679e10cb1bbf36c3feec2af756 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 22 Feb 2023 18:40:14 +0200 Subject: [PATCH 20/29] wifi: ath12k: remove memset with byte count of 278528 Sparse warns: drivers/net/wireless/ath/ath12k/dp.c:1471:15: warning: memset with byte count of 278528 There's no need to use memset() here, instead call dma_alloc_coherent() with __GFP_ZERO. While at it, remove an extra line before the error handler. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230222164014.860-1-kvalo@kernel.org --- drivers/net/wireless/ath/ath12k/dp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 9926d81c5fe4..ae1645d0f42a 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1461,15 +1461,12 @@ static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab) dp->reoq_lut.vaddr = dma_alloc_coherent(ab->dev, DP_REOQ_LUT_SIZE, &dp->reoq_lut.paddr, - GFP_KERNEL); - + GFP_KERNEL | __GFP_ZERO); if (!dp->reoq_lut.vaddr) { ath12k_warn(ab, "failed to allocate memory for reoq table"); return -ENOMEM; } - memset(dp->reoq_lut.vaddr, 0, DP_REOQ_LUT_SIZE); - ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE0(ab), dp->reoq_lut.paddr); return 0; From 75c4a8154cb6c7239fb55d5550f481f6765fb83c Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Fri, 24 Feb 2023 12:28:05 +0200 Subject: [PATCH 21/29] wifi: ath6kl: reduce WARN to dev_dbg() in callback The warn is triggered on a known race condition, documented in the code above the test, that is correctly handled. Using WARN() hinders automated testing. Reducing severity. Fixes: de2070fc4aa7 ("ath6kl: Fix kernel panic on continuous driver load/unload") Reported-and-tested-by: syzbot+555908813b2ea35dae9a@syzkaller.appspotmail.com Signed-off-by: Oliver Neukum Signed-off-by: Fedor Pchelkin Signed-off-by: Alexey Khoroshilov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230126182431.867984-1-pchelkin@ispras.ru --- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index c68848819a52..9b88d96bfe96 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -960,8 +960,8 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, * Thus the possibility of ar->htc_target being NULL * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work. */ - if (WARN_ON_ONCE(!target)) { - ath6kl_err("Target not yet initialized\n"); + if (!target) { + ath6kl_dbg(ATH6KL_DBG_HTC, "Target not yet initialized\n"); status = -EINVAL; goto free_skb; } From a96f10422e74cde27c100b321b127ec32ae75747 Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Fri, 24 Feb 2023 12:28:03 +0200 Subject: [PATCH 22/29] wifi: ath11k: modify accessor macros to match index size HE PHY is only 11 bytes, therefore it should be using byte indexes instead of dword. Change corresponding macros to reflect this. Signed-off-by: Muna Sinada Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1666128501-12364-2-git-send-email-quic_msinada@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 2273d885f7fa..9f50be411a8c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2859,30 +2859,32 @@ struct rx_reorder_queue_remove_params { #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) -#define HECAP_PHYDWORD_0 0 -#define HECAP_PHYDWORD_1 1 -#define HECAP_PHYDWORD_2 2 +#define HE_PHYCAP_BYTE_0 0 +#define HE_PHYCAP_BYTE_1 1 +#define HE_PHYCAP_BYTE_2 2 +#define HE_PHYCAP_BYTE_3 3 +#define HE_PHYCAP_BYTE_4 4 -#define HECAP_PHY_SU_BFER BIT(31) +#define HECAP_PHY_SU_BFER BIT(7) #define HECAP_PHY_SU_BFEE BIT(0) #define HECAP_PHY_MU_BFER BIT(1) -#define HECAP_PHY_UL_MUMIMO BIT(22) -#define HECAP_PHY_UL_MUOFDMA BIT(23) +#define HECAP_PHY_UL_MUMIMO BIT(6) +#define HECAP_PHY_UL_MUOFDMA BIT(7) #define HECAP_PHY_SUBFMR_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HECAP_PHYDWORD_0]) + FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HE_PHYCAP_BYTE_3]) #define HECAP_PHY_SUBFME_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HECAP_PHYDWORD_1]) + FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HE_PHYCAP_BYTE_4]) #define HECAP_PHY_MUBFMR_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HECAP_PHYDWORD_1]) + FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HE_PHYCAP_BYTE_4]) #define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HECAP_PHYDWORD_0]) + FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HE_PHYCAP_BYTE_2]) #define HECAP_PHY_ULOFDMA_GET(hecap_phy) \ - FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HECAP_PHYDWORD_0]) + FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HE_PHYCAP_BYTE_2]) #define HE_MODE_SU_TX_BFEE BIT(0) #define HE_MODE_SU_TX_BFER BIT(1) From 38dfe775d0abf511341f37c1cb77b919a3ad410b Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Fri, 24 Feb 2023 12:28:04 +0200 Subject: [PATCH 23/29] wifi: ath11k: push MU-MIMO params from hostapd to hardware In the previous behaviour only HE IE in management frames are changed regarding MU-MIMO configurations and not in hardware. Adding push of MU-MIMO configurations to the hardware as well. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00356-QCAHKSWPL_SILICONZ-1 Co-developed-by: Anilkumar Kolli Signed-off-by: Anilkumar Kolli Signed-off-by: Muna Sinada Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1666128501-12364-3-git-send-email-quic_msinada@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 200 ++++++++++++++++---------- drivers/net/wireless/ath/ath11k/wmi.h | 3 + 2 files changed, 130 insertions(+), 73 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 110a38cce0a7..7c4f424180dc 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2699,6 +2699,117 @@ static int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif, ath11k_smps_map[smps]); } +static bool ath11k_mac_set_he_txbf_conf(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + u32 param, value; + int ret; + + if (!arvif->vif->bss_conf.he_support) + return true; + + param = WMI_VDEV_PARAM_SET_HEMU_MODE; + value = 0; + if (arvif->vif->bss_conf.he_su_beamformer) { + value |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE); + if (arvif->vif->bss_conf.he_mu_beamformer && + arvif->vdev_type == WMI_VDEV_TYPE_AP) + value |= FIELD_PREP(HE_MODE_MU_TX_BFER, HE_MU_BFER_ENABLE); + } + + if (arvif->vif->type != NL80211_IFTYPE_MESH_POINT) { + value |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) | + FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE); + + if (arvif->vif->bss_conf.he_full_ul_mumimo) + value |= FIELD_PREP(HE_MODE_UL_MUMIMO, HE_UL_MUMIMO_ENABLE); + + if (arvif->vif->bss_conf.he_su_beamformee) + value |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE); + } + + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value); + if (ret) { + ath11k_warn(ar->ab, "failed to set vdev %d HE MU mode: %d\n", + arvif->vdev_id, ret); + return false; + } + + param = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; + value = FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) | + FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE, + HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE); + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + param, value); + if (ret) { + ath11k_warn(ar->ab, "failed to set vdev %d sounding mode: %d\n", + arvif->vdev_id, ret); + return false; + } + return true; +} + +static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta_he_cap *he_cap) +{ + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ieee80211_he_cap_elem he_cap_elem = {0}; + struct ieee80211_sta_he_cap *cap_band = NULL; + struct cfg80211_chan_def def; + u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE; + u32 hemode = 0; + int ret; + + if (!vif->bss_conf.he_support) + return true; + + if (vif->type != NL80211_IFTYPE_STATION) + return false; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return false; + + if (def.chan->band == NL80211_BAND_2GHZ) + cap_band = &ar->mac.iftype[NL80211_BAND_2GHZ][vif->type].he_cap; + else + cap_band = &ar->mac.iftype[NL80211_BAND_5GHZ][vif->type].he_cap; + + memcpy(&he_cap_elem, &cap_band->he_cap_elem, sizeof(he_cap_elem)); + + if (HECAP_PHY_SUBFME_GET(he_cap_elem.phy_cap_info)) { + if (HECAP_PHY_SUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE); + if (HECAP_PHY_MUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE); + } + + if (vif->type != NL80211_IFTYPE_MESH_POINT) { + hemode |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) | + FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE); + + if (HECAP_PHY_ULMUMIMO_GET(he_cap_elem.phy_cap_info)) + if (HECAP_PHY_ULMUMIMO_GET(he_cap->he_cap_elem.phy_cap_info)) + hemode |= FIELD_PREP(HE_MODE_UL_MUMIMO, + HE_UL_MUMIMO_ENABLE); + + if (FIELD_GET(HE_MODE_MU_TX_BFEE, hemode)) + hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE); + + if (FIELD_GET(HE_MODE_MU_TX_BFER, hemode)) + hemode |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE); + } + + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, hemode); + if (ret) { + ath11k_warn(ar->ab, "failed to submit vdev param txbf 0x%x: %d\n", + hemode, ret); + return false; + } + + return true; +} + static void ath11k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) @@ -2709,6 +2820,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_sta *ap_sta; struct ath11k_peer *peer; bool is_auth = false; + struct ieee80211_sta_he_cap he_cap; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2726,6 +2838,9 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, return; } + /* he_cap here is updated at assoc success for sta mode only */ + he_cap = ap_sta->deflink.he_cap; + ath11k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false); rcu_read_unlock(); @@ -2753,6 +2868,12 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, return; } + if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { + ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", + arvif->vdev_id, bss_conf->bssid); + return; + } + WARN_ON(arvif->is_up); arvif->aid = vif->cfg.aid; @@ -3202,6 +3323,8 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ether_addr_copy(arvif->bssid, info->bssid); if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (info->enable_beacon) + ath11k_mac_set_he_txbf_conf(arvif); ath11k_control_beaconing(arvif, info); if (arvif->is_up && vif->bss_conf.he_support && @@ -5392,6 +5515,10 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, he_cap_elem->mac_cap_info[1] &= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; + he_cap_elem->phy_cap_info[0] &= + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + he_cap_elem->phy_cap_info[0] &= + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; he_cap_elem->phy_cap_info[5] &= ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; @@ -6026,69 +6153,6 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, } } -static u32 -ath11k_mac_prepare_he_mode(struct ath11k_pdev *pdev, u32 viftype) -{ - struct ath11k_pdev_cap *pdev_cap = &pdev->cap; - struct ath11k_band_cap *cap_band = NULL; - u32 *hecap_phy_ptr = NULL; - u32 hemode = 0; - - if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) - cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; - else - cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; - - hecap_phy_ptr = &cap_band->he_cap_phy_info[0]; - - hemode = FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE) | - FIELD_PREP(HE_MODE_SU_TX_BFER, HECAP_PHY_SUBFMR_GET(hecap_phy_ptr)) | - FIELD_PREP(HE_MODE_UL_MUMIMO, HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr)); - - /* TODO WDS and other modes */ - if (viftype == NL80211_IFTYPE_AP) { - hemode |= FIELD_PREP(HE_MODE_MU_TX_BFER, - HECAP_PHY_MUBFMR_GET(hecap_phy_ptr)) | - FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) | - FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE); - } else { - hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE); - } - - return hemode; -} - -static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar, - struct ath11k_vif *arvif) -{ - u32 param_id, param_value; - struct ath11k_base *ab = ar->ab; - int ret = 0; - - param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; - param_value = ath11k_mac_prepare_he_mode(ar->pdev, arvif->vif->type); - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n", - arvif->vdev_id, ret, param_value); - return ret; - } - param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; - param_value = - FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) | - FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE, - HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE); - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d\n", - arvif->vdev_id, ret); - return ret; - } - return ret; -} - static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -6757,7 +6821,6 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, struct ath11k_base *ab = ar->ab; struct wmi_vdev_start_req_arg arg = {}; const struct cfg80211_chan_def *chandef = &ctx->def; - int he_support = arvif->vif->bss_conf.he_support; int ret = 0; lockdep_assert_held(&ar->conf_mutex); @@ -6798,15 +6861,6 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, spin_lock_bh(&ab->base_lock); arg.regdomain = ar->ab->dfs_region; spin_unlock_bh(&ab->base_lock); - - if (he_support) { - ret = ath11k_set_he_mu_sounding_mode(ar, arvif); - if (ret) { - ath11k_warn(ar->ab, "failed to set he mode vdev %i\n", - arg.vdev_id); - return ret; - } - } } arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 9f50be411a8c..d3b74f1346f5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2897,8 +2897,11 @@ struct rx_reorder_queue_remove_params { #define HE_DL_MUOFDMA_ENABLE 1 #define HE_UL_MUOFDMA_ENABLE 1 #define HE_DL_MUMIMO_ENABLE 1 +#define HE_UL_MUMIMO_ENABLE 1 #define HE_MU_BFEE_ENABLE 1 #define HE_SU_BFEE_ENABLE 1 +#define HE_MU_BFER_ENABLE 1 +#define HE_SU_BFER_ENABLE 1 #define HE_VHT_SOUNDING_MODE_ENABLE 1 #define HE_SU_MU_SOUNDING_MODE_ENABLE 1 From 8077c1bbbc28e527fb29143c46f32c6a9d6cadf0 Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Fri, 24 Feb 2023 12:28:04 +0200 Subject: [PATCH 24/29] wifi: ath11k: move HE MCS mapper to a separate function Move HE MCS mapper to a separate function and call new function in ath11k_mac_copy_he_cap(). Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00356-QCAHKSWPL_SILICONZ-1 Signed-off-by: Muna Sinada Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1666128501-12364-4-git-send-email-quic_msinada@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 34 +++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7c4f424180dc..0835ab8b389a 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -5483,6 +5483,27 @@ static __le16 ath11k_mac_setup_he_6ghz_cap(struct ath11k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } +static void ath11k_mac_set_hemcsmap(struct ath11k *ar, + struct ath11k_pdev_cap *cap, + struct ieee80211_sta_he_cap *he_cap, + int band) +{ + struct ath11k_band_cap *band_cap = &cap->band[band]; + + he_cap->he_mcs_nss_supp.rx_mcs_80 = + cpu_to_le16(band_cap->he_mcs & 0xffff); + he_cap->he_mcs_nss_supp.tx_mcs_80 = + cpu_to_le16(band_cap->he_mcs & 0xffff); + he_cap->he_mcs_nss_supp.rx_mcs_160 = + cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + he_cap->he_mcs_nss_supp.tx_mcs_160 = + cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + he_cap->he_mcs_nss_supp.rx_mcs_80p80 = + cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + he_cap->he_mcs_nss_supp.tx_mcs_80p80 = + cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); +} + static int ath11k_mac_copy_he_cap(struct ath11k *ar, struct ath11k_pdev_cap *cap, struct ieee80211_sband_iftype_data *data, @@ -5544,18 +5565,7 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, break; } - he_cap->he_mcs_nss_supp.rx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); - he_cap->he_mcs_nss_supp.rx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.rx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - he_cap->he_mcs_nss_supp.tx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + ath11k_mac_set_hemcsmap(ar, cap, he_cap, band); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & From ebf82988f844dd98e6b007cffcc5e95986056995 Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Fri, 24 Feb 2023 12:28:04 +0200 Subject: [PATCH 25/29] wifi: ath11k: generate rx and tx mcs maps for supported HE mcs Generate rx and tx mcs maps in ath11k_mac_set_hemcsmap() and set them in supported mcs/nss for HE capabilities. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00356-QCAHKSWPL_SILICONZ-1 Signed-off-by: Muna Sinada Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1666128501-12364-5-git-send-email-quic_msinada@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 30 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 0835ab8b389a..fd1a23ead5e2 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -5488,20 +5488,36 @@ static void ath11k_mac_set_hemcsmap(struct ath11k *ar, struct ieee80211_sta_he_cap *he_cap, int band) { - struct ath11k_band_cap *band_cap = &cap->band[band]; + u16 txmcs_map, rxmcs_map; + u32 i; + rxmcs_map = 0; + txmcs_map = 0; + for (i = 0; i < 8; i++) { + if (i < ar->num_tx_chains && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + txmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + txmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < ar->num_rx_chains && + (ar->cfg_rx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + } he_cap->he_mcs_nss_supp.rx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); + cpu_to_le16(rxmcs_map & 0xffff); he_cap->he_mcs_nss_supp.tx_mcs_80 = - cpu_to_le16(band_cap->he_mcs & 0xffff); + cpu_to_le16(txmcs_map & 0xffff); he_cap->he_mcs_nss_supp.rx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + cpu_to_le16(rxmcs_map & 0xffff); he_cap->he_mcs_nss_supp.tx_mcs_160 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + cpu_to_le16(txmcs_map & 0xffff); he_cap->he_mcs_nss_supp.rx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + cpu_to_le16(rxmcs_map & 0xffff); he_cap->he_mcs_nss_supp.tx_mcs_80p80 = - cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); + cpu_to_le16(txmcs_map & 0xffff); } static int ath11k_mac_copy_he_cap(struct ath11k *ar, From 01c6c9fccbd51c1d9eab0f5794b0271b026178df Mon Sep 17 00:00:00 2001 From: Abinaya Kalaiselvan Date: Mon, 19 Dec 2022 11:08:44 +0530 Subject: [PATCH 26/29] wifi: ath11k: Add tx ack signal support for management packets Add support to notify tx ack signal values for management packets to userspace through nl80211 interface. Advertise NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT flag to enable this feature and it will be used for data packets as well. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Abinaya Kalaiselvan Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20221219053844.4084486-1-quic_mkenna@quicinc.com --- drivers/net/wireless/ath/ath11k/hw.c | 1 + drivers/net/wireless/ath/ath11k/mac.c | 5 +++++ drivers/net/wireless/ath/ath11k/wmi.c | 27 ++++++++++++++++----------- drivers/net/wireless/ath/ath11k/wmi.h | 3 +++ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index ab8f0ccacc6b..60ac215e0678 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -201,6 +201,7 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; + config->flag1 |= WMI_RSRC_CFG_FLAG1_ACK_RSSI; } static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index fd1a23ead5e2..cad832e0e6b8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9174,6 +9174,11 @@ static int __ath11k_mac_register(struct ath11k *ar) goto err_free_if_combs; } + if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI, + ar->ab->wmi_ab.svc_map)) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); + ar->hw->queues = ATH11K_HW_MAX_QUEUES; ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 7057c7916d5d..815f49c3b3ad 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -5229,8 +5229,8 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab, return 0; } -static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, - u32 status) +static int wmi_process_mgmt_tx_comp(struct ath11k *ar, + struct wmi_mgmt_tx_compl_event *tx_compl_param) { struct sk_buff *msdu; struct ieee80211_tx_info *info; @@ -5238,24 +5238,29 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, int num_mgmt; spin_lock_bh(&ar->txmgmt_idr_lock); - msdu = idr_find(&ar->txmgmt_idr, desc_id); + msdu = idr_find(&ar->txmgmt_idr, tx_compl_param->desc_id); if (!msdu) { ath11k_warn(ar->ab, "received mgmt tx compl for invalid msdu_id: %d\n", - desc_id); + tx_compl_param->desc_id); spin_unlock_bh(&ar->txmgmt_idr_lock); return -ENOENT; } - idr_remove(&ar->txmgmt_idr, desc_id); + idr_remove(&ar->txmgmt_idr, tx_compl_param->desc_id); spin_unlock_bh(&ar->txmgmt_idr_lock); skb_cb = ATH11K_SKB_CB(msdu); dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(msdu); - if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) + if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && + !tx_compl_param->status) { info->flags |= IEEE80211_TX_STAT_ACK; + if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI, + ar->ab->wmi_ab.svc_map)) + info->status.ack_signal = tx_compl_param->ack_rssi; + } ieee80211_tx_status_irqsafe(ar->hw, msdu); @@ -5267,7 +5272,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi mgmt tx comp pending %d desc id %d\n", - num_mgmt, desc_id); + num_mgmt, tx_compl_param->desc_id); if (!num_mgmt) wake_up(&ar->txmgmt_empty_waitq); @@ -5300,6 +5305,7 @@ static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab, param->pdev_id = ev->pdev_id; param->desc_id = ev->desc_id; param->status = ev->status; + param->ack_rssi = ev->ack_rssi; kfree(tb); return 0; @@ -7070,13 +7076,12 @@ static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *s goto exit; } - wmi_process_mgmt_tx_comp(ar, tx_compl_param.desc_id, - tx_compl_param.status); + wmi_process_mgmt_tx_comp(ar, &tx_compl_param); ath11k_dbg(ab, ATH11K_DBG_MGMT, - "mgmt tx compl ev pdev_id %d, desc_id %d, status %d", + "mgmt tx compl ev pdev_id %d, desc_id %d, status %d ack_rssi %d", tx_compl_param.pdev_id, tx_compl_param.desc_id, - tx_compl_param.status); + tx_compl_param.status, tx_compl_param.ack_rssi); exit: rcu_read_unlock(); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index d3b74f1346f5..63dbb085949f 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2311,6 +2311,7 @@ struct wmi_init_cmd { } __packed; #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) +#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) struct wmi_resource_config { u32 tlv_header; @@ -4550,6 +4551,8 @@ struct wmi_mgmt_tx_compl_event { u32 desc_id; u32 status; u32 pdev_id; + u32 ppdu_id; + u32 ack_rssi; } __packed; struct wmi_scan_event { From 25e289e1f52e1f4fb1d07622c6a24f8d8a8e420d Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 1 Mar 2023 16:20:58 +0200 Subject: [PATCH 27/29] wifi: ath11k: use proper regulatory reference for bands Currently, during regulatory event, 2 GHz/5 GHz is referred to as 2G/5G including variable names. However, there is no such entity as 2G or 5G. Re-name such occurences to its proper name. No functional changes. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230110121024.14051-2-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 20 ++++----- drivers/net/wireless/ath/ath11k/wmi.c | 58 ++++++++++++++------------- drivers/net/wireless/ath/ath11k/wmi.h | 28 ++++++------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 6fae4e61ede7..c231abdf49cb 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -619,7 +619,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab, u32 flags; char alpha2[3]; - num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules; + num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; if (!num_rules) goto ret; @@ -644,20 +644,20 @@ ath11k_reg_build_regd(struct ath11k_base *ab, alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region), reg_info->dfs_region, num_rules); /* Update reg_rules[] below. Firmware is expected to - * send these rules in order(2G rules first and then 5G) + * send these rules in order(2 GHz rules first and then 5 GHz) */ for (; i < num_rules; i++) { - if (reg_info->num_2g_reg_rules && - (i < reg_info->num_2g_reg_rules)) { - reg_rule = reg_info->reg_rules_2g_ptr + i; + if (reg_info->num_2ghz_reg_rules && + (i < reg_info->num_2ghz_reg_rules)) { + reg_rule = reg_info->reg_rules_2ghz_ptr + i; max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_2g); + reg_info->max_bw_2ghz); flags = 0; - } else if (reg_info->num_5g_reg_rules && - (j < reg_info->num_5g_reg_rules)) { - reg_rule = reg_info->reg_rules_5g_ptr + j++; + } else if (reg_info->num_5ghz_reg_rules && + (j < reg_info->num_5ghz_reg_rules)) { + reg_rule = reg_info->reg_rules_5ghz_ptr + j++; max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_5g); + reg_info->max_bw_5ghz); /* FW doesn't pass NL80211_RRF_AUTO_BW flag for * BW Auto correction, we can enable this by default diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 815f49c3b3ad..ecd51d285103 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -4959,7 +4959,7 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, const void **tb; const struct wmi_reg_chan_list_cc_event *chan_list_event_hdr; struct wmi_regulatory_rule_struct *wmi_reg_rule; - u32 num_2g_reg_rules, num_5g_reg_rules; + u32 num_2ghz_reg_rules, num_5ghz_reg_rules; int ret; ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n"); @@ -4978,10 +4978,10 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, return -EPROTO; } - reg_info->num_2g_reg_rules = chan_list_event_hdr->num_2g_reg_rules; - reg_info->num_5g_reg_rules = chan_list_event_hdr->num_5g_reg_rules; + reg_info->num_2ghz_reg_rules = chan_list_event_hdr->num_2ghz_reg_rules; + reg_info->num_5ghz_reg_rules = chan_list_event_hdr->num_5ghz_reg_rules; - if (!(reg_info->num_2g_reg_rules + reg_info->num_5g_reg_rules)) { + if (!(reg_info->num_2ghz_reg_rules + reg_info->num_5ghz_reg_rules)) { ath11k_warn(ab, "No regulatory rules available in the event info\n"); kfree(tb); return -EINVAL; @@ -5008,46 +5008,48 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL) reg_info->status_code = REG_SET_CC_STATUS_FAIL; - reg_info->min_bw_2g = chan_list_event_hdr->min_bw_2g; - reg_info->max_bw_2g = chan_list_event_hdr->max_bw_2g; - reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g; - reg_info->max_bw_5g = chan_list_event_hdr->max_bw_5g; + reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz; + reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz; + reg_info->min_bw_5ghz = chan_list_event_hdr->min_bw_5ghz; + reg_info->max_bw_5ghz = chan_list_event_hdr->max_bw_5ghz; - num_2g_reg_rules = reg_info->num_2g_reg_rules; - num_5g_reg_rules = reg_info->num_5g_reg_rules; + num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules; + num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules; ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s:cc %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d", + "%s:cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", __func__, reg_info->alpha2, reg_info->dfs_region, - reg_info->min_bw_2g, reg_info->max_bw_2g, - reg_info->min_bw_5g, reg_info->max_bw_5g); + reg_info->min_bw_2ghz, reg_info->max_bw_2ghz, + reg_info->min_bw_5ghz, reg_info->max_bw_5ghz); ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s: num_2g_reg_rules %d num_5g_reg_rules %d", __func__, - num_2g_reg_rules, num_5g_reg_rules); + "%s: num_2ghz_reg_rules %d num_5ghz_reg_rules %d", __func__, + num_2ghz_reg_rules, num_5ghz_reg_rules); wmi_reg_rule = (struct wmi_regulatory_rule_struct *)((u8 *)chan_list_event_hdr + sizeof(*chan_list_event_hdr) + sizeof(struct wmi_tlv)); - if (num_2g_reg_rules) { - reg_info->reg_rules_2g_ptr = create_reg_rules_from_wmi(num_2g_reg_rules, - wmi_reg_rule); - if (!reg_info->reg_rules_2g_ptr) { + if (num_2ghz_reg_rules) { + reg_info->reg_rules_2ghz_ptr = + create_reg_rules_from_wmi(num_2ghz_reg_rules, + wmi_reg_rule); + if (!reg_info->reg_rules_2ghz_ptr) { kfree(tb); - ath11k_warn(ab, "Unable to Allocate memory for 2g rules\n"); + ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n"); return -ENOMEM; } } - if (num_5g_reg_rules) { - wmi_reg_rule += num_2g_reg_rules; - reg_info->reg_rules_5g_ptr = create_reg_rules_from_wmi(num_5g_reg_rules, - wmi_reg_rule); - if (!reg_info->reg_rules_5g_ptr) { + if (num_5ghz_reg_rules) { + wmi_reg_rule += num_2ghz_reg_rules; + reg_info->reg_rules_5ghz_ptr = + create_reg_rules_from_wmi(num_5ghz_reg_rules, + wmi_reg_rule); + if (!reg_info->reg_rules_5ghz_ptr) { kfree(tb); - ath11k_warn(ab, "Unable to Allocate memory for 5g rules\n"); + ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n"); return -ENOMEM; } } @@ -6619,8 +6621,8 @@ fallback: WARN_ON(1); mem_free: if (reg_info) { - kfree(reg_info->reg_rules_2g_ptr); - kfree(reg_info->reg_rules_5g_ptr); + kfree(reg_info->reg_rules_2ghz_ptr); + kfree(reg_info->reg_rules_5ghz_ptr); kfree(reg_info); } return ret; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 63dbb085949f..858403f190c2 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4129,14 +4129,14 @@ struct cur_regulatory_info { u8 alpha2[REG_ALPHA2_LEN + 1]; u32 dfs_region; u32 phybitmap; - u32 min_bw_2g; - u32 max_bw_2g; - u32 min_bw_5g; - u32 max_bw_5g; - u32 num_2g_reg_rules; - u32 num_5g_reg_rules; - struct cur_reg_rule *reg_rules_2g_ptr; - struct cur_reg_rule *reg_rules_5g_ptr; + u32 min_bw_2ghz; + u32 max_bw_2ghz; + u32 min_bw_5ghz; + u32 max_bw_5ghz; + u32 num_2ghz_reg_rules; + u32 num_5ghz_reg_rules; + struct cur_reg_rule *reg_rules_2ghz_ptr; + struct cur_reg_rule *reg_rules_5ghz_ptr; }; struct wmi_reg_chan_list_cc_event { @@ -4148,12 +4148,12 @@ struct wmi_reg_chan_list_cc_event { u32 domain_code; u32 dfs_region; u32 phybitmap; - u32 min_bw_2g; - u32 max_bw_2g; - u32 min_bw_5g; - u32 max_bw_5g; - u32 num_2g_reg_rules; - u32 num_5g_reg_rules; + u32 min_bw_2ghz; + u32 max_bw_2ghz; + u32 min_bw_5ghz; + u32 max_bw_5ghz; + u32 num_2ghz_reg_rules; + u32 num_5ghz_reg_rules; } __packed; struct wmi_regulatory_rule_struct { From 91fa00fa69224aae5afb720c5e68b22e4c4f7333 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 1 Mar 2023 16:20:59 +0200 Subject: [PATCH 28/29] wifi: ath11k: add support to parse new WMI event for 6 GHz In order to support different power levels of 6 GHz AP and client, new WMI event for regulatory - WMI_REG_CHAN_LIST_CC_EXT_EVENTID is added in firmware. This event provides new parameters required for 6 GHz regulatory rules. Add support for parsing 2.4 GHz, 5 GHz and 6 GHz reg rules and other parameters from WMI_REG_CHAN_LIST_CC_EXT_EVENTID. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 Signed-off-by: Lavanya Suresh Signed-off-by: Wen Gong Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230110121024.14051-3-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 37 ++- drivers/net/wireless/ath/ath11k/wmi.c | 418 +++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/wmi.h | 163 +++++++++- 3 files changed, 584 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index c231abdf49cb..08621bd13a12 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -613,7 +613,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab, { struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; struct cur_reg_rule *reg_rule; - u8 i = 0, j = 0; + u8 i = 0, j = 0, k = 0; u8 num_rules; u16 max_bw; u32 flags; @@ -621,6 +621,12 @@ ath11k_reg_build_regd(struct ath11k_base *ab, num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; + /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list. + * This can be updated after complete 6 GHz regulatory support is added. + */ + if (reg_info->is_ext_reg_event) + num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + if (!num_rules) goto ret; @@ -666,6 +672,14 @@ ath11k_reg_build_regd(struct ath11k_base *ab, * per other BW rule flags we pass from here */ flags = NL80211_RRF_AUTO_BW; + } else if (reg_info->is_ext_reg_event && + reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] && + (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) { + reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] + + k++; + max_bw = min_t(u16, reg_rule->max_bw, + reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]); + flags = NL80211_RRF_AUTO_BW; } else { break; } @@ -693,12 +707,21 @@ ath11k_reg_build_regd(struct ath11k_base *ab, continue; } - ath11k_dbg(ab, ATH11K_DBG_REG, - "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", - i + 1, reg_rule->start_freq, reg_rule->end_freq, - max_bw, reg_rule->ant_gain, reg_rule->reg_power, - tmp_regd->reg_rules[i].dfs_cac_ms, - flags); + if (reg_info->is_ext_reg_event) { + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n", + i + 1, reg_rule->start_freq, reg_rule->end_freq, + max_bw, reg_rule->ant_gain, reg_rule->reg_power, + tmp_regd->reg_rules[i].dfs_cac_ms, flags, + reg_rule->psd_flag, reg_rule->psd_eirp); + } else { + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", + i + 1, reg_rule->start_freq, reg_rule->end_freq, + max_bw, reg_rule->ant_gain, reg_rule->reg_power, + tmp_regd->reg_rules[i].dfs_cac_ms, + flags); + } } tmp_regd->n_reg_rules = i; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index ecd51d285103..34731d0d1efc 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -105,6 +105,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { = { .min_len = sizeof(struct wmi_vdev_stopped_event) }, [WMI_TAG_REG_CHAN_LIST_CC_EVENT] = { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) }, + [WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT] + = { .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) }, [WMI_TAG_MGMT_RX_HDR] = { .min_len = sizeof(struct wmi_mgmt_rx_hdr) }, [WMI_TAG_MGMT_TX_COMPL_EVENT] @@ -3974,6 +3976,10 @@ ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg, wmi_cfg->sched_params = tg_cfg->sched_params; wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count; wmi_cfg->twt_ap_sta_count = tg_cfg->twt_ap_sta_count; + wmi_cfg->host_service_flags &= + ~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT); + wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported << + WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT); } static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, @@ -4192,6 +4198,10 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) ab->hw_params.hw_ops->wmi_init_config(ab, &config); + if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, + ab->wmi_ab.svc_map)) + config.is_reg_cc_ext_event_supported = 1; + memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config)); init_param.res_cfg = &wmi_sc->wlan_resource_config; @@ -4995,18 +5005,11 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, reg_info->phy_id = chan_list_event_hdr->phy_id; reg_info->ctry_code = chan_list_event_hdr->country_id; reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code; - if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_PASS) - reg_info->status_code = REG_SET_CC_STATUS_PASS; - else if (chan_list_event_hdr->status_code == WMI_REG_CURRENT_ALPHA2_NOT_FOUND) - reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND; - else if (chan_list_event_hdr->status_code == WMI_REG_INIT_ALPHA2_NOT_FOUND) - reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND; - else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_CHANGE_NOT_ALLOWED) - reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED; - else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_NO_MEMORY) - reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY; - else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL) - reg_info->status_code = REG_SET_CC_STATUS_FAIL; + + reg_info->status_code = + ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code); + + reg_info->is_ext_reg_event = false; reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz; reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz; @@ -5060,6 +5063,372 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, return 0; } +static struct cur_reg_rule +*create_ext_reg_rules_from_wmi(u32 num_reg_rules, + struct wmi_regulatory_ext_rule *wmi_reg_rule) +{ + struct cur_reg_rule *reg_rule_ptr; + u32 count; + + reg_rule_ptr = kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), GFP_ATOMIC); + + if (!reg_rule_ptr) + return NULL; + + for (count = 0; count < num_reg_rules; count++) { + reg_rule_ptr[count].start_freq = + u32_get_bits(wmi_reg_rule[count].freq_info, + REG_RULE_START_FREQ); + reg_rule_ptr[count].end_freq = + u32_get_bits(wmi_reg_rule[count].freq_info, + REG_RULE_END_FREQ); + reg_rule_ptr[count].max_bw = + u32_get_bits(wmi_reg_rule[count].bw_pwr_info, + REG_RULE_MAX_BW); + reg_rule_ptr[count].reg_power = + u32_get_bits(wmi_reg_rule[count].bw_pwr_info, + REG_RULE_REG_PWR); + reg_rule_ptr[count].ant_gain = + u32_get_bits(wmi_reg_rule[count].bw_pwr_info, + REG_RULE_ANT_GAIN); + reg_rule_ptr[count].flags = + u32_get_bits(wmi_reg_rule[count].flag_info, + REG_RULE_FLAGS); + reg_rule_ptr[count].psd_flag = + u32_get_bits(wmi_reg_rule[count].psd_power_info, + REG_RULE_PSD_INFO); + reg_rule_ptr[count].psd_eirp = + u32_get_bits(wmi_reg_rule[count].psd_power_info, + REG_RULE_PSD_EIRP); + } + + return reg_rule_ptr; +} + +static u8 +ath11k_invalid_5ghz_reg_ext_rules_from_wmi(u32 num_reg_rules, + const struct wmi_regulatory_ext_rule *rule) +{ + u8 num_invalid_5ghz_rules = 0; + u32 count, start_freq; + + for (count = 0; count < num_reg_rules; count++) { + start_freq = u32_get_bits(rule[count].freq_info, + REG_RULE_START_FREQ); + + if (start_freq >= ATH11K_MIN_6G_FREQ) + num_invalid_5ghz_rules++; + } + + return num_invalid_5ghz_rules; +} + +static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, + struct sk_buff *skb, + struct cur_regulatory_info *reg_info) +{ + const void **tb; + const struct wmi_reg_chan_list_cc_ext_event *ext_chan_list_event_hdr; + struct wmi_regulatory_ext_rule *ext_wmi_reg_rule; + u32 num_2ghz_reg_rules, num_5ghz_reg_rules; + u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 num_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 total_reg_rules = 0; + int ret, i, j, num_invalid_5ghz_ext_rules = 0; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n"); + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ext_chan_list_event_hdr = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]; + if (!ext_chan_list_event_hdr) { + ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n"); + kfree(tb); + return -EPROTO; + } + + reg_info->num_2ghz_reg_rules = + ext_chan_list_event_hdr->num_2ghz_reg_rules; + reg_info->num_5ghz_reg_rules = + ext_chan_list_event_hdr->num_5ghz_reg_rules; + reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] = + ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_lpi; + reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] = + ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_sp; + reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] = + ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_vlp; + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] = + ext_chan_list_event_hdr->num_6ghz_reg_rules_client_lpi[i]; + reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] = + ext_chan_list_event_hdr->num_6ghz_reg_rules_client_sp[i]; + reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ext_chan_list_event_hdr->num_6ghz_reg_rules_client_vlp[i]; + } + + num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules; + num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules; + + total_reg_rules += num_2ghz_reg_rules; + total_reg_rules += num_5ghz_reg_rules; + + if ((num_2ghz_reg_rules > MAX_REG_RULES) || + (num_5ghz_reg_rules > MAX_REG_RULES)) { + ath11k_warn(ab, "Num reg rules for 2.4 GHz/5 GHz exceeds max limit (num_2ghz_reg_rules: %d num_5ghz_reg_rules: %d max_rules: %d)\n", + num_2ghz_reg_rules, num_5ghz_reg_rules, MAX_REG_RULES); + kfree(tb); + return -EINVAL; + } + + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { + num_6ghz_reg_rules_ap[i] = reg_info->num_6ghz_rules_ap[i]; + + if (num_6ghz_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) { + ath11k_warn(ab, "Num 6 GHz reg rules for AP mode(%d) exceeds max limit (num_6ghz_reg_rules_ap: %d, max_rules: %d)\n", + i, num_6ghz_reg_rules_ap[i], MAX_6GHZ_REG_RULES); + kfree(tb); + return -EINVAL; + } + + total_reg_rules += num_6ghz_reg_rules_ap[i]; + } + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + num_6ghz_client[WMI_REG_INDOOR_AP][i] = + reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i]; + total_reg_rules += num_6ghz_client[WMI_REG_INDOOR_AP][i]; + + num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i]; + total_reg_rules += num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i]; + + num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i]; + total_reg_rules += num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i]; + + if ((num_6ghz_client[WMI_REG_INDOOR_AP][i] > MAX_6GHZ_REG_RULES) || + (num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] > + MAX_6GHZ_REG_RULES) || + (num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] > + MAX_6GHZ_REG_RULES)) { + ath11k_warn(ab, + "Num 6 GHz client reg rules exceeds max limit, for client(type: %d)\n", + i); + kfree(tb); + return -EINVAL; + } + } + + if (!total_reg_rules) { + ath11k_warn(ab, "No reg rules available\n"); + kfree(tb); + return -EINVAL; + } + + memcpy(reg_info->alpha2, &ext_chan_list_event_hdr->alpha2, + REG_ALPHA2_LEN); + + reg_info->dfs_region = ext_chan_list_event_hdr->dfs_region; + reg_info->phybitmap = ext_chan_list_event_hdr->phybitmap; + reg_info->num_phy = ext_chan_list_event_hdr->num_phy; + reg_info->phy_id = ext_chan_list_event_hdr->phy_id; + reg_info->ctry_code = ext_chan_list_event_hdr->country_id; + reg_info->reg_dmn_pair = ext_chan_list_event_hdr->domain_code; + + reg_info->status_code = + ath11k_wmi_cc_setting_code_to_reg(ext_chan_list_event_hdr->status_code); + + reg_info->is_ext_reg_event = true; + + reg_info->min_bw_2ghz = ext_chan_list_event_hdr->min_bw_2ghz; + reg_info->max_bw_2ghz = ext_chan_list_event_hdr->max_bw_2ghz; + reg_info->min_bw_5ghz = ext_chan_list_event_hdr->min_bw_5ghz; + reg_info->max_bw_5ghz = ext_chan_list_event_hdr->max_bw_5ghz; + + reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] = + ext_chan_list_event_hdr->min_bw_6ghz_ap_lpi; + reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] = + ext_chan_list_event_hdr->max_bw_6ghz_ap_lpi; + reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = + ext_chan_list_event_hdr->min_bw_6ghz_ap_sp; + reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = + ext_chan_list_event_hdr->max_bw_6ghz_ap_sp; + reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = + ext_chan_list_event_hdr->min_bw_6ghz_ap_vlp; + reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = + ext_chan_list_event_hdr->max_bw_6ghz_ap_vlp; + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] = + ext_chan_list_event_hdr->min_bw_6ghz_client_lpi[i]; + reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] = + ext_chan_list_event_hdr->max_bw_6ghz_client_lpi[i]; + reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + ext_chan_list_event_hdr->min_bw_6ghz_client_sp[i]; + reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + ext_chan_list_event_hdr->max_bw_6ghz_client_sp[i]; + reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ext_chan_list_event_hdr->min_bw_6ghz_client_vlp[i]; + reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ext_chan_list_event_hdr->max_bw_6ghz_client_vlp[i]; + } + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "%s:cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", + __func__, reg_info->alpha2, reg_info->dfs_region, + reg_info->min_bw_2ghz, reg_info->max_bw_2ghz, + reg_info->min_bw_5ghz, reg_info->max_bw_5ghz); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "num_2ghz_reg_rules %d num_5ghz_reg_rules %d", + num_2ghz_reg_rules, num_5ghz_reg_rules); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "num_6ghz_reg_rules_ap_lpi: %d num_6ghz_reg_rules_ap_sp: %d num_6ghz_reg_rules_ap_vlp: %d", + num_6ghz_reg_rules_ap[WMI_REG_INDOOR_AP], + num_6ghz_reg_rules_ap[WMI_REG_STANDARD_POWER_AP], + num_6ghz_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP]); + + j = WMI_REG_DEFAULT_CLIENT; + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz Regular client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d", + num_6ghz_client[WMI_REG_INDOOR_AP][j], + num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j], + num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]); + + j = WMI_REG_SUBORDINATE_CLIENT; + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz Subordinate client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d", + num_6ghz_client[WMI_REG_INDOOR_AP][j], + num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j], + num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]); + + ext_wmi_reg_rule = + (struct wmi_regulatory_ext_rule *)((u8 *)ext_chan_list_event_hdr + + sizeof(*ext_chan_list_event_hdr) + + sizeof(struct wmi_tlv)); + if (num_2ghz_reg_rules) { + reg_info->reg_rules_2ghz_ptr = + create_ext_reg_rules_from_wmi(num_2ghz_reg_rules, + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_2ghz_ptr) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n"); + return -ENOMEM; + } + } + + ext_wmi_reg_rule += num_2ghz_reg_rules; + + /* Firmware might include 6 GHz reg rule in 5 GHz rule list + * for few countries along with separate 6 GHz rule. + * Having same 6 GHz reg rule in 5 GHz and 6 GHz rules list + * causes intersect check to be true, and same rules will be + * shown multiple times in iw cmd. + * Hence, avoid parsing 6 GHz rule from 5 GHz reg rule list + */ + num_invalid_5ghz_ext_rules = + ath11k_invalid_5ghz_reg_ext_rules_from_wmi(num_5ghz_reg_rules, + ext_wmi_reg_rule); + + if (num_invalid_5ghz_ext_rules) { + ath11k_dbg(ab, ATH11K_DBG_WMI, + "CC: %s 5 GHz reg rules number %d from fw, %d number of invalid 5 GHz rules", + reg_info->alpha2, reg_info->num_5ghz_reg_rules, + num_invalid_5ghz_ext_rules); + + num_5ghz_reg_rules = num_5ghz_reg_rules - num_invalid_5ghz_ext_rules; + reg_info->num_5ghz_reg_rules = num_5ghz_reg_rules; + } + + if (num_5ghz_reg_rules) { + reg_info->reg_rules_5ghz_ptr = + create_ext_reg_rules_from_wmi(num_5ghz_reg_rules, + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_5ghz_ptr) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n"); + return -ENOMEM; + } + } + + /* We have adjusted the number of 5 GHz reg rules above. But still those + * many rules needs to be adjusted in ext_wmi_reg_rule. + * + * NOTE: num_invalid_5ghz_ext_rules will be 0 for rest other cases. + */ + ext_wmi_reg_rule += (num_5ghz_reg_rules + num_invalid_5ghz_ext_rules); + + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { + reg_info->reg_rules_6ghz_ap_ptr[i] = + create_ext_reg_rules_from_wmi(num_6ghz_reg_rules_ap[i], + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_6ghz_ap_ptr[i]) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 6 GHz AP rules\n"); + return -ENOMEM; + } + + ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i]; + } + + for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) { + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->reg_rules_6ghz_client_ptr[j][i] = + create_ext_reg_rules_from_wmi(num_6ghz_client[j][i], + ext_wmi_reg_rule); + + if (!reg_info->reg_rules_6ghz_client_ptr[j][i]) { + kfree(tb); + ath11k_warn(ab, "Unable to Allocate memory for 6 GHz client rules\n"); + return -ENOMEM; + } + + ext_wmi_reg_rule += num_6ghz_client[j][i]; + } + } + + reg_info->client_type = ext_chan_list_event_hdr->client_type; + reg_info->rnr_tpe_usable = ext_chan_list_event_hdr->rnr_tpe_usable; + reg_info->unspecified_ap_usable = + ext_chan_list_event_hdr->unspecified_ap_usable; + reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] = + ext_chan_list_event_hdr->domain_code_6ghz_ap_lpi; + reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = + ext_chan_list_event_hdr->domain_code_6ghz_ap_sp; + reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = + ext_chan_list_event_hdr->domain_code_6ghz_ap_vlp; + + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { + reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] = + ext_chan_list_event_hdr->domain_code_6ghz_client_lpi[i]; + reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = + ext_chan_list_event_hdr->domain_code_6ghz_client_sp[i]; + reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = + ext_chan_list_event_hdr->domain_code_6ghz_client_vlp[i]; + } + + reg_info->domain_code_6ghz_super_id = + ext_chan_list_event_hdr->domain_code_6ghz_super_id; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "6 GHz client_type: %d domain_code_6ghz_super_id: %d", + reg_info->client_type, reg_info->domain_code_6ghz_super_id); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n"); + + kfree(tb); + return 0; +} + static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *skb, struct wmi_peer_delete_resp_event *peer_del_resp) { @@ -6507,12 +6876,14 @@ static bool ath11k_reg_is_world_alpha(char *alpha) return false; } -static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb) +static int ath11k_reg_chan_list_event(struct ath11k_base *ab, + struct sk_buff *skb, + enum wmi_reg_chan_list_cmd_type id) { struct cur_regulatory_info *reg_info = NULL; struct ieee80211_regdomain *regd = NULL; bool intersect = false; - int ret = 0, pdev_idx; + int ret = 0, pdev_idx, i, j; struct ath11k *ar; reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC); @@ -6521,7 +6892,11 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk goto fallback; } - ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); + if (id == WMI_REG_CHAN_LIST_CC_ID) + ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); + else + ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info); + if (ret) { ath11k_warn(ab, "failed to extract regulatory info from received event\n"); goto fallback; @@ -6623,6 +6998,14 @@ mem_free: if (reg_info) { kfree(reg_info->reg_rules_2ghz_ptr); kfree(reg_info->reg_rules_5ghz_ptr); + if (reg_info->is_ext_reg_event) { + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) + kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); + + for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) + kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]); + } kfree(reg_info); } return ret; @@ -8054,7 +8437,10 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) ath11k_service_ready_ext2_event(ab, skb); break; case WMI_REG_CHAN_LIST_CC_EVENTID: - ath11k_reg_chan_list_event(ab, skb); + ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_ID); + break; + case WMI_REG_CHAN_LIST_CC_EXT_EVENTID: + ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_EXT_ID); break; case WMI_READY_EVENTID: ath11k_ready_event(ab, skb); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 858403f190c2..3ec3fa0aa5c8 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -797,6 +797,7 @@ enum wmi_tlv_event_id { WMI_RMC_NEW_LEADER_EVENTID = WMI_TLV_CMD(WMI_GRP_RMC), WMI_REG_CHAN_LIST_CC_EVENTID = WMI_TLV_CMD(WMI_GRP_REGULATORY), WMI_11D_NEW_COUNTRY_EVENTID, + WMI_REG_CHAN_LIST_CC_EXT_EVENTID, WMI_NDI_CAP_RSP_EVENTID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE), WMI_NDP_INITIATOR_RSP_EVENTID, WMI_NDP_RESPONDER_RSP_EVENTID, @@ -1865,6 +1866,8 @@ enum wmi_tlv_tag { WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD, WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD, WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD, + WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, + WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD, WMI_TAG_MAX @@ -2097,6 +2100,7 @@ enum wmi_tlv_service { /* The second 128 bits */ WMI_MAX_EXT_SERVICE = 256, + WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326, /* The third 128 bits */ @@ -2313,6 +2317,8 @@ struct wmi_init_cmd { #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) #define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) +#define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4 + struct wmi_resource_config { u32 tlv_header; u32 num_vdevs; @@ -2372,6 +2378,15 @@ struct wmi_resource_config { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + u32 max_nlo_ssids; + u32 num_pkt_filters; + u32 num_max_sta_vdevs; + u32 max_bssid_indicator; + u32 ul_resp_config; + u32 msdu_flow_override_config0; + u32 msdu_flow_override_config1; + u32 flags2; + u32 host_service_flags; } __packed; struct wmi_service_ready_event { @@ -2854,6 +2869,8 @@ struct rx_reorder_queue_remove_params { #define REG_RULE_MAX_BW 0x0000ffff #define REG_RULE_REG_PWR 0x00ff0000 #define REG_RULE_ANT_GAIN 0xff000000 +#define REG_RULE_PSD_INFO BIT(0) +#define REG_RULE_PSD_EIRP 0xff0000 #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) @@ -4049,6 +4066,7 @@ struct wmi_he_rate_set { #define MAX_REG_RULES 10 #define REG_ALPHA2_LEN 2 +#define MAX_6GHZ_REG_RULES 5 enum wmi_start_event_param { WMI_VDEV_START_RESP_EVENT = 0, @@ -4079,16 +4097,6 @@ enum wmi_vdev_start_resp_status_code { WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN = 4, }; -; -enum cc_setting_code { - REG_SET_CC_STATUS_PASS = 0, - REG_CURRENT_ALPHA2_NOT_FOUND = 1, - REG_INIT_ALPHA2_NOT_FOUND = 2, - REG_SET_CC_CHANGE_NOT_ALLOWED = 3, - REG_SET_CC_STATUS_NO_MEMORY = 4, - REG_SET_CC_STATUS_FAIL = 5, -}; - /* Regaulatory Rule Flags Passed by FW */ #define REGULATORY_CHAN_DISABLED BIT(0) #define REGULATORY_CHAN_NO_IR BIT(1) @@ -4102,13 +4110,72 @@ enum cc_setting_code { #define REGULATORY_CHAN_NO_20MHZ BIT(11) #define REGULATORY_CHAN_NO_10MHZ BIT(12) -enum { +enum wmi_reg_chan_list_cmd_type { + WMI_REG_CHAN_LIST_CC_ID = 0, + WMI_REG_CHAN_LIST_CC_EXT_ID = 1, +}; + +enum wmi_reg_cc_setting_code { WMI_REG_SET_CC_STATUS_PASS = 0, WMI_REG_CURRENT_ALPHA2_NOT_FOUND = 1, WMI_REG_INIT_ALPHA2_NOT_FOUND = 2, WMI_REG_SET_CC_CHANGE_NOT_ALLOWED = 3, WMI_REG_SET_CC_STATUS_NO_MEMORY = 4, WMI_REG_SET_CC_STATUS_FAIL = 5, + + /* add new setting code above, update in + * @enum cc_setting_code as well. + * Also handle it in ath11k_wmi_cc_setting_code_to_reg() + */ +}; + +enum cc_setting_code { + REG_SET_CC_STATUS_PASS = 0, + REG_CURRENT_ALPHA2_NOT_FOUND = 1, + REG_INIT_ALPHA2_NOT_FOUND = 2, + REG_SET_CC_CHANGE_NOT_ALLOWED = 3, + REG_SET_CC_STATUS_NO_MEMORY = 4, + REG_SET_CC_STATUS_FAIL = 5, + + /* add new setting code above, update in + * @enum wmi_reg_cc_setting_code as well. + */ +}; + +static inline enum cc_setting_code +ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code) +{ + switch (status_code) { + case WMI_REG_SET_CC_STATUS_PASS: + return REG_SET_CC_STATUS_PASS; + case WMI_REG_CURRENT_ALPHA2_NOT_FOUND: + return REG_CURRENT_ALPHA2_NOT_FOUND; + case WMI_REG_INIT_ALPHA2_NOT_FOUND: + return REG_INIT_ALPHA2_NOT_FOUND; + case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED: + return REG_SET_CC_CHANGE_NOT_ALLOWED; + case WMI_REG_SET_CC_STATUS_NO_MEMORY: + return REG_SET_CC_STATUS_NO_MEMORY; + case WMI_REG_SET_CC_STATUS_FAIL: + return REG_SET_CC_STATUS_FAIL; + } + + return REG_SET_CC_STATUS_FAIL; +} + +enum wmi_reg_6ghz_ap_type { + WMI_REG_INDOOR_AP = 0, + WMI_REG_STANDARD_POWER_AP = 1, + WMI_REG_VERY_LOW_POWER_AP = 2, + + WMI_REG_CURRENT_MAX_AP_TYPE, + WMI_REG_MAX_AP_TYPE = 7, +}; + +enum wmi_reg_6ghz_client_type { + WMI_REG_DEFAULT_CLIENT = 0, + WMI_REG_SUBORDINATE_CLIENT = 1, + WMI_REG_MAX_CLIENT_TYPE = 2, }; struct cur_reg_rule { @@ -4118,6 +4185,8 @@ struct cur_reg_rule { u8 reg_power; u8 ant_gain; u16 flags; + bool psd_flag; + s8 psd_eirp; }; struct cur_regulatory_info { @@ -4137,6 +4206,22 @@ struct cur_regulatory_info { u32 num_5ghz_reg_rules; struct cur_reg_rule *reg_rules_2ghz_ptr; struct cur_reg_rule *reg_rules_5ghz_ptr; + bool is_ext_reg_event; + enum wmi_reg_6ghz_client_type client_type; + bool rnr_tpe_usable; + bool unspecified_ap_usable; + u8 domain_code_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u8 domain_code_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 domain_code_6ghz_super_id; + u32 min_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 max_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 min_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 max_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + u32 num_6ghz_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; + u32 num_6ghz_rules_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; + struct cur_reg_rule *reg_rules_6ghz_ap_ptr[WMI_REG_CURRENT_MAX_AP_TYPE]; + struct cur_reg_rule *reg_rules_6ghz_client_ptr + [WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; }; struct wmi_reg_chan_list_cc_event { @@ -4163,6 +4248,61 @@ struct wmi_regulatory_rule_struct { u32 flag_info; }; +#define WMI_REG_CLIENT_MAX 4 + +struct wmi_reg_chan_list_cc_ext_event { + u32 status_code; + u32 phy_id; + u32 alpha2; + u32 num_phy; + u32 country_id; + u32 domain_code; + u32 dfs_region; + u32 phybitmap; + u32 min_bw_2ghz; + u32 max_bw_2ghz; + u32 min_bw_5ghz; + u32 max_bw_5ghz; + u32 num_2ghz_reg_rules; + u32 num_5ghz_reg_rules; + u32 client_type; + u32 rnr_tpe_usable; + u32 unspecified_ap_usable; + u32 domain_code_6ghz_ap_lpi; + u32 domain_code_6ghz_ap_sp; + u32 domain_code_6ghz_ap_vlp; + u32 domain_code_6ghz_client_lpi[WMI_REG_CLIENT_MAX]; + u32 domain_code_6ghz_client_sp[WMI_REG_CLIENT_MAX]; + u32 domain_code_6ghz_client_vlp[WMI_REG_CLIENT_MAX]; + u32 domain_code_6ghz_super_id; + u32 min_bw_6ghz_ap_sp; + u32 max_bw_6ghz_ap_sp; + u32 min_bw_6ghz_ap_lpi; + u32 max_bw_6ghz_ap_lpi; + u32 min_bw_6ghz_ap_vlp; + u32 max_bw_6ghz_ap_vlp; + u32 min_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX]; + u32 max_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX]; + u32 min_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX]; + u32 max_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX]; + u32 min_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX]; + u32 max_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX]; + u32 num_6ghz_reg_rules_ap_sp; + u32 num_6ghz_reg_rules_ap_lpi; + u32 num_6ghz_reg_rules_ap_vlp; + u32 num_6ghz_reg_rules_client_sp[WMI_REG_CLIENT_MAX]; + u32 num_6ghz_reg_rules_client_lpi[WMI_REG_CLIENT_MAX]; + u32 num_6ghz_reg_rules_client_vlp[WMI_REG_CLIENT_MAX]; +} __packed; + +struct wmi_regulatory_ext_rule { + u32 tlv_header; + u32 freq_info; + u32 bw_pwr_info; + u32 flag_info; + u32 psd_power_info; +} __packed; + struct wmi_vdev_delete_resp_event { u32 vdev_id; } __packed; @@ -5358,6 +5498,7 @@ struct target_resource_config { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + u8 is_reg_cc_ext_event_supported; }; enum wmi_debug_log_param { From e238e62ba8868a784e485eb94451c87cd1b85cee Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 1 Mar 2023 16:20:59 +0200 Subject: [PATCH 29/29] wifi: ath11k: add debug prints in regulatory WMI event processing Add some more debug prints in processing regulatory WMI event in order to increase more debuggability. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230110121024.14051-4-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 207 ++++++++++++++++++-------- drivers/net/wireless/ath/ath11k/wmi.h | 142 ++++++++++++++++++ 3 files changed, 291 insertions(+), 60 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 08621bd13a12..67443457f4da 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -646,7 +646,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab, tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region); ath11k_dbg(ab, ATH11K_DBG_REG, - "\r\nCountry %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n", + "Country %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n", alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region), reg_info->dfs_region, num_rules); /* Update reg_rules[] below. Firmware is expected to diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 34731d0d1efc..27f3fceb33c5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -4925,6 +4925,26 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf return 0; } +static void ath11k_print_reg_rule(struct ath11k_base *ab, const char *band, + u32 num_reg_rules, + struct cur_reg_rule *reg_rule_ptr) +{ + struct cur_reg_rule *reg_rule = reg_rule_ptr; + u32 count; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "number of reg rules in %s band: %d\n", + band, num_reg_rules); + + for (count = 0; count < num_reg_rules; count++) { + ath11k_dbg(ab, ATH11K_DBG_WMI, + "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d)\n", + count + 1, reg_rule->start_freq, reg_rule->end_freq, + reg_rule->max_bw, reg_rule->ant_gain, + reg_rule->reg_power, reg_rule->flags); + reg_rule++; + } +} + static struct cur_reg_rule *create_reg_rules_from_wmi(u32 num_reg_rules, struct wmi_regulatory_rule_struct *wmi_reg_rule) @@ -5006,6 +5026,10 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, reg_info->ctry_code = chan_list_event_hdr->country_id; reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code; + ath11k_dbg(ab, ATH11K_DBG_WMI, + "status_code %s", + ath11k_cc_status_to_str(reg_info->status_code)); + reg_info->status_code = ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code); @@ -5020,13 +5044,13 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules; ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s:cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", - __func__, reg_info->alpha2, reg_info->dfs_region, + "cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", + reg_info->alpha2, reg_info->dfs_region, reg_info->min_bw_2ghz, reg_info->max_bw_2ghz, reg_info->min_bw_5ghz, reg_info->max_bw_5ghz); ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s: num_2ghz_reg_rules %d num_5ghz_reg_rules %d", __func__, + "num_2ghz_reg_rules %d num_5ghz_reg_rules %d", num_2ghz_reg_rules, num_5ghz_reg_rules); wmi_reg_rule = @@ -5043,6 +5067,10 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n"); return -ENOMEM; } + + ath11k_print_reg_rule(ab, "2 GHz", + num_2ghz_reg_rules, + reg_info->reg_rules_2ghz_ptr); } if (num_5ghz_reg_rules) { @@ -5055,6 +5083,10 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n"); return -ENOMEM; } + + ath11k_print_reg_rule(ab, "5 GHz", + num_5ghz_reg_rules, + reg_info->reg_rules_5ghz_ptr); } ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory channel list\n"); @@ -5128,7 +5160,7 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, struct cur_regulatory_info *reg_info) { const void **tb; - const struct wmi_reg_chan_list_cc_ext_event *ext_chan_list_event_hdr; + const struct wmi_reg_chan_list_cc_ext_event *ev; struct wmi_regulatory_ext_rule *ext_wmi_reg_rule; u32 num_2ghz_reg_rules, num_5ghz_reg_rules; u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; @@ -5145,31 +5177,29 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, return ret; } - ext_chan_list_event_hdr = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]; - if (!ext_chan_list_event_hdr) { + ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]; + if (!ev) { ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n"); kfree(tb); return -EPROTO; } - reg_info->num_2ghz_reg_rules = - ext_chan_list_event_hdr->num_2ghz_reg_rules; - reg_info->num_5ghz_reg_rules = - ext_chan_list_event_hdr->num_5ghz_reg_rules; + reg_info->num_2ghz_reg_rules = ev->num_2ghz_reg_rules; + reg_info->num_5ghz_reg_rules = ev->num_5ghz_reg_rules; reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] = - ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_lpi; + ev->num_6ghz_reg_rules_ap_lpi; reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] = - ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_sp; + ev->num_6ghz_reg_rules_ap_sp; reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] = - ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_vlp; + ev->num_6ghz_reg_rules_ap_vlp; for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] = - ext_chan_list_event_hdr->num_6ghz_reg_rules_client_lpi[i]; + ev->num_6ghz_reg_rules_client_lpi[i]; reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] = - ext_chan_list_event_hdr->num_6ghz_reg_rules_client_sp[i]; + ev->num_6ghz_reg_rules_client_sp[i]; reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] = - ext_chan_list_event_hdr->num_6ghz_reg_rules_client_vlp[i]; + ev->num_6ghz_reg_rules_client_vlp[i]; } num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules; @@ -5231,57 +5261,79 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, return -EINVAL; } - memcpy(reg_info->alpha2, &ext_chan_list_event_hdr->alpha2, - REG_ALPHA2_LEN); + memcpy(reg_info->alpha2, &ev->alpha2, REG_ALPHA2_LEN); - reg_info->dfs_region = ext_chan_list_event_hdr->dfs_region; - reg_info->phybitmap = ext_chan_list_event_hdr->phybitmap; - reg_info->num_phy = ext_chan_list_event_hdr->num_phy; - reg_info->phy_id = ext_chan_list_event_hdr->phy_id; - reg_info->ctry_code = ext_chan_list_event_hdr->country_id; - reg_info->reg_dmn_pair = ext_chan_list_event_hdr->domain_code; + reg_info->dfs_region = ev->dfs_region; + reg_info->phybitmap = ev->phybitmap; + reg_info->num_phy = ev->num_phy; + reg_info->phy_id = ev->phy_id; + reg_info->ctry_code = ev->country_id; + reg_info->reg_dmn_pair = ev->domain_code; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "status_code %s", + ath11k_cc_status_to_str(reg_info->status_code)); reg_info->status_code = - ath11k_wmi_cc_setting_code_to_reg(ext_chan_list_event_hdr->status_code); + ath11k_wmi_cc_setting_code_to_reg(ev->status_code); reg_info->is_ext_reg_event = true; - reg_info->min_bw_2ghz = ext_chan_list_event_hdr->min_bw_2ghz; - reg_info->max_bw_2ghz = ext_chan_list_event_hdr->max_bw_2ghz; - reg_info->min_bw_5ghz = ext_chan_list_event_hdr->min_bw_5ghz; - reg_info->max_bw_5ghz = ext_chan_list_event_hdr->max_bw_5ghz; + reg_info->min_bw_2ghz = ev->min_bw_2ghz; + reg_info->max_bw_2ghz = ev->max_bw_2ghz; + reg_info->min_bw_5ghz = ev->min_bw_5ghz; + reg_info->max_bw_5ghz = ev->max_bw_5ghz; reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] = - ext_chan_list_event_hdr->min_bw_6ghz_ap_lpi; + ev->min_bw_6ghz_ap_lpi; reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] = - ext_chan_list_event_hdr->max_bw_6ghz_ap_lpi; + ev->max_bw_6ghz_ap_lpi; reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = - ext_chan_list_event_hdr->min_bw_6ghz_ap_sp; + ev->min_bw_6ghz_ap_sp; reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = - ext_chan_list_event_hdr->max_bw_6ghz_ap_sp; + ev->max_bw_6ghz_ap_sp; reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = - ext_chan_list_event_hdr->min_bw_6ghz_ap_vlp; + ev->min_bw_6ghz_ap_vlp; reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = - ext_chan_list_event_hdr->max_bw_6ghz_ap_vlp; + ev->max_bw_6ghz_ap_vlp; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz AP BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n", + reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP], + reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP], + reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP], + reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP], + reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP], + reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP]); for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] = - ext_chan_list_event_hdr->min_bw_6ghz_client_lpi[i]; + ev->min_bw_6ghz_client_lpi[i]; reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] = - ext_chan_list_event_hdr->max_bw_6ghz_client_lpi[i]; + ev->max_bw_6ghz_client_lpi[i]; reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = - ext_chan_list_event_hdr->min_bw_6ghz_client_sp[i]; + ev->min_bw_6ghz_client_sp[i]; reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = - ext_chan_list_event_hdr->max_bw_6ghz_client_sp[i]; + ev->max_bw_6ghz_client_sp[i]; reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = - ext_chan_list_event_hdr->min_bw_6ghz_client_vlp[i]; + ev->min_bw_6ghz_client_vlp[i]; reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = - ext_chan_list_event_hdr->max_bw_6ghz_client_vlp[i]; + ev->max_bw_6ghz_client_vlp[i]; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz %s BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n", + ath11k_6ghz_client_type_to_str(i), + reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i], + reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i], + reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i], + reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i], + reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i], + reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i]); } ath11k_dbg(ab, ATH11K_DBG_WMI, - "%s:cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", - __func__, reg_info->alpha2, reg_info->dfs_region, + "cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d", + reg_info->alpha2, reg_info->dfs_region, reg_info->min_bw_2ghz, reg_info->max_bw_2ghz, reg_info->min_bw_5ghz, reg_info->max_bw_5ghz); @@ -5310,9 +5362,8 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]); ext_wmi_reg_rule = - (struct wmi_regulatory_ext_rule *)((u8 *)ext_chan_list_event_hdr - + sizeof(*ext_chan_list_event_hdr) - + sizeof(struct wmi_tlv)); + (struct wmi_regulatory_ext_rule *)((u8 *)ev + sizeof(*ev) + + sizeof(struct wmi_tlv)); if (num_2ghz_reg_rules) { reg_info->reg_rules_2ghz_ptr = create_ext_reg_rules_from_wmi(num_2ghz_reg_rules, @@ -5323,6 +5374,10 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n"); return -ENOMEM; } + + ath11k_print_reg_rule(ab, "2 GHz", + num_2ghz_reg_rules, + reg_info->reg_rules_2ghz_ptr); } ext_wmi_reg_rule += num_2ghz_reg_rules; @@ -5358,6 +5413,10 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n"); return -ENOMEM; } + + ath11k_print_reg_rule(ab, "5 GHz", + num_5ghz_reg_rules, + reg_info->reg_rules_5ghz_ptr); } /* We have adjusted the number of 5 GHz reg rules above. But still those @@ -5378,10 +5437,17 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, return -ENOMEM; } + ath11k_print_reg_rule(ab, ath11k_6ghz_ap_type_to_str(i), + num_6ghz_reg_rules_ap[i], + reg_info->reg_rules_6ghz_ap_ptr[i]); + ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i]; } for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) { + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz AP type %s", ath11k_6ghz_ap_type_to_str(j)); + for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { reg_info->reg_rules_6ghz_client_ptr[j][i] = create_ext_reg_rules_from_wmi(num_6ghz_client[j][i], @@ -5393,35 +5459,58 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, return -ENOMEM; } + ath11k_print_reg_rule(ab, + ath11k_6ghz_client_type_to_str(i), + num_6ghz_client[j][i], + reg_info->reg_rules_6ghz_client_ptr[j][i]); + ext_wmi_reg_rule += num_6ghz_client[j][i]; } } - reg_info->client_type = ext_chan_list_event_hdr->client_type; - reg_info->rnr_tpe_usable = ext_chan_list_event_hdr->rnr_tpe_usable; + reg_info->client_type = ev->client_type; + reg_info->rnr_tpe_usable = ev->rnr_tpe_usable; reg_info->unspecified_ap_usable = - ext_chan_list_event_hdr->unspecified_ap_usable; + ev->unspecified_ap_usable; reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] = - ext_chan_list_event_hdr->domain_code_6ghz_ap_lpi; + ev->domain_code_6ghz_ap_lpi; reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] = - ext_chan_list_event_hdr->domain_code_6ghz_ap_sp; + ev->domain_code_6ghz_ap_sp; reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] = - ext_chan_list_event_hdr->domain_code_6ghz_ap_vlp; + ev->domain_code_6ghz_ap_vlp; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s, sp %s, vlp %s\n", + ath11k_6ghz_client_type_to_str(reg_info->client_type), + reg_info->rnr_tpe_usable, + reg_info->unspecified_ap_usable, + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_lpi), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_sp), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_vlp)); for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] = - ext_chan_list_event_hdr->domain_code_6ghz_client_lpi[i]; + ev->domain_code_6ghz_client_lpi[i]; reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] = - ext_chan_list_event_hdr->domain_code_6ghz_client_sp[i]; + ev->domain_code_6ghz_client_sp[i]; reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] = - ext_chan_list_event_hdr->domain_code_6ghz_client_vlp[i]; + ev->domain_code_6ghz_client_vlp[i]; + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz client type %s client sub domain: lpi %s, sp %s, vlp %s\n", + ath11k_6ghz_client_type_to_str(i), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_lpi[i]), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_sp[i]), + ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_vlp[i]) + ); } - reg_info->domain_code_6ghz_super_id = - ext_chan_list_event_hdr->domain_code_6ghz_super_id; + reg_info->domain_code_6ghz_super_id = ev->domain_code_6ghz_super_id; - ath11k_dbg(ab, ATH11K_DBG_WMI, "6 GHz client_type: %d domain_code_6ghz_super_id: %d", - reg_info->client_type, reg_info->domain_code_6ghz_super_id); + ath11k_dbg(ab, ATH11K_DBG_WMI, + "6 GHz client_type %s 6 GHz super domain %s", + ath11k_6ghz_client_type_to_str(reg_info->client_type), + ath11k_super_reg_6ghz_to_str(reg_info->domain_code_6ghz_super_id)); ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n"); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 3ec3fa0aa5c8..b23b7a22bc9a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4139,6 +4139,7 @@ enum cc_setting_code { /* add new setting code above, update in * @enum wmi_reg_cc_setting_code as well. + * Also handle it in ath11k_cc_status_to_str() */ }; @@ -4163,21 +4164,162 @@ ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code) return REG_SET_CC_STATUS_FAIL; } +static inline const char *ath11k_cc_status_to_str(enum cc_setting_code code) +{ + switch (code) { + case REG_SET_CC_STATUS_PASS: + return "REG_SET_CC_STATUS_PASS"; + case REG_CURRENT_ALPHA2_NOT_FOUND: + return "REG_CURRENT_ALPHA2_NOT_FOUND"; + case REG_INIT_ALPHA2_NOT_FOUND: + return "REG_INIT_ALPHA2_NOT_FOUND"; + case REG_SET_CC_CHANGE_NOT_ALLOWED: + return "REG_SET_CC_CHANGE_NOT_ALLOWED"; + case REG_SET_CC_STATUS_NO_MEMORY: + return "REG_SET_CC_STATUS_NO_MEMORY"; + case REG_SET_CC_STATUS_FAIL: + return "REG_SET_CC_STATUS_FAIL"; + } + + return "Unknown CC status"; +} + enum wmi_reg_6ghz_ap_type { WMI_REG_INDOOR_AP = 0, WMI_REG_STANDARD_POWER_AP = 1, WMI_REG_VERY_LOW_POWER_AP = 2, + /* add AP type above, handle in ath11k_6ghz_ap_type_to_str() + */ WMI_REG_CURRENT_MAX_AP_TYPE, WMI_REG_MAX_AP_TYPE = 7, }; +static inline const char * +ath11k_6ghz_ap_type_to_str(enum wmi_reg_6ghz_ap_type type) +{ + switch (type) { + case WMI_REG_INDOOR_AP: + return "INDOOR AP"; + case WMI_REG_STANDARD_POWER_AP: + return "STANDARD POWER AP"; + case WMI_REG_VERY_LOW_POWER_AP: + return "VERY LOW POWER AP"; + case WMI_REG_CURRENT_MAX_AP_TYPE: + return "CURRENT_MAX_AP_TYPE"; + case WMI_REG_MAX_AP_TYPE: + return "MAX_AP_TYPE"; + } + + return "unknown 6 GHz AP type"; +} + enum wmi_reg_6ghz_client_type { WMI_REG_DEFAULT_CLIENT = 0, WMI_REG_SUBORDINATE_CLIENT = 1, WMI_REG_MAX_CLIENT_TYPE = 2, + + /* add client type above, handle it in + * ath11k_6ghz_client_type_to_str() + */ }; +static inline const char * +ath11k_6ghz_client_type_to_str(enum wmi_reg_6ghz_client_type type) +{ + switch (type) { + case WMI_REG_DEFAULT_CLIENT: + return "DEFAULT CLIENT"; + case WMI_REG_SUBORDINATE_CLIENT: + return "SUBORDINATE CLIENT"; + case WMI_REG_MAX_CLIENT_TYPE: + return "MAX_CLIENT_TYPE"; + } + + return "unknown 6 GHz client type"; +} + +enum reg_subdomains_6ghz { + EMPTY_6GHZ = 0x0, + FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01, + FCC1_CLIENT_SP_6GHZ = 0x02, + FCC1_AP_LPI_6GHZ = 0x03, + FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ, + FCC1_AP_SP_6GHZ = 0x04, + ETSI1_LPI_6GHZ = 0x10, + ETSI1_VLP_6GHZ = 0x11, + ETSI2_LPI_6GHZ = 0x12, + ETSI2_VLP_6GHZ = 0x13, + APL1_LPI_6GHZ = 0x20, + APL1_VLP_6GHZ = 0x21, + + /* add sub-domain above, handle it in + * ath11k_sub_reg_6ghz_to_str() + */ +}; + +static inline const char * +ath11k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id) +{ + switch (sub_id) { + case EMPTY_6GHZ: + return "N/A"; + case FCC1_CLIENT_LPI_REGULAR_6GHZ: + return "FCC1_CLIENT_LPI_REGULAR_6GHZ"; + case FCC1_CLIENT_SP_6GHZ: + return "FCC1_CLIENT_SP_6GHZ"; + case FCC1_AP_LPI_6GHZ: + return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE"; + case FCC1_AP_SP_6GHZ: + return "FCC1_AP_SP_6GHZ"; + case ETSI1_LPI_6GHZ: + return "ETSI1_LPI_6GHZ"; + case ETSI1_VLP_6GHZ: + return "ETSI1_VLP_6GHZ"; + case ETSI2_LPI_6GHZ: + return "ETSI2_LPI_6GHZ"; + case ETSI2_VLP_6GHZ: + return "ETSI2_VLP_6GHZ"; + case APL1_LPI_6GHZ: + return "APL1_LPI_6GHZ"; + case APL1_VLP_6GHZ: + return "APL1_VLP_6GHZ"; + } + + return "unknown sub reg id"; +} + +enum reg_super_domain_6ghz { + FCC1_6GHZ = 0x01, + ETSI1_6GHZ = 0x02, + ETSI2_6GHZ = 0x03, + APL1_6GHZ = 0x04, + FCC1_6GHZ_CL = 0x05, + + /* add super domain above, handle it in + * ath11k_super_reg_6ghz_to_str() + */ +}; + +static inline const char * +ath11k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id) +{ + switch (domain_id) { + case FCC1_6GHZ: + return "FCC1_6GHZ"; + case ETSI1_6GHZ: + return "ETSI1_6GHZ"; + case ETSI2_6GHZ: + return "ETSI2_6GHZ"; + case APL1_6GHZ: + return "APL1_6GHZ"; + case FCC1_6GHZ_CL: + return "FCC1_6GHZ_CL"; + } + + return "unknown domain id"; +} + struct cur_reg_rule { u16 start_freq; u16 end_freq;