wifi: ath12k: fix firmware assert during insmod in memory segment mode
authorAaradhana Sahu <quic_aarasahu@quicinc.com>
Mon, 29 Jan 2024 06:57:17 +0000 (12:27 +0530)
committerKalle Valo <quic_kvalo@quicinc.com>
Fri, 2 Feb 2024 12:32:50 +0000 (14:32 +0200)
In segment memory mode, firmware allocates memory segments of size
2 MB. This 2 MB memory is used by firmware for the number of peers.
This number of peer is sent from host to firmware during WMI init
command. For single-phy the number of peers sent is
TARGET_NUM_PEERS_SINGLE = 529 (512 + 17). While for split-phy number
of peers sent to firmware is TARGET_NUM_PEERS_DBS = 2 *(512 + 17) =
1058. With this 1058 number of peers firmware is unable to allocate
memory in 2 MB segment and firmware crash is observed.

Hence, fix this firmware crash by reducing the number of stations
TARGET_NUM_STATIONS for split-phy.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Signed-off-by: Aaradhana Sahu <quic_aarasahu@quicinc.com>
Co-developed-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240129065724.2310207-7-quic_rajkbhag@quicinc.com
drivers/net/wireless/ath/ath12k/core.c
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/hw.h
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/wmi.c

index 634a9ddc2fe5ae917fa507f813eb9e406c5a2222..7f0b395f12969659c097eeeb8f7c76ba979bc5e9 100644 (file)
@@ -510,6 +510,33 @@ exit:
        return ret;
 }
 
+u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab)
+{
+       if (ab->num_radios == 2)
+               return TARGET_NUM_STATIONS_DBS;
+       else if (ab->num_radios == 3)
+               return TARGET_NUM_PEERS_PDEV_DBS_SBS;
+       return TARGET_NUM_STATIONS_SINGLE;
+}
+
+u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab)
+{
+       if (ab->num_radios == 2)
+               return TARGET_NUM_PEERS_PDEV_DBS;
+       else if (ab->num_radios == 3)
+               return TARGET_NUM_PEERS_PDEV_DBS_SBS;
+       return TARGET_NUM_PEERS_PDEV_SINGLE;
+}
+
+u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab)
+{
+       if (ab->num_radios == 2)
+               return TARGET_NUM_TIDS(DBS);
+       else if (ab->num_radios == 3)
+               return TARGET_NUM_TIDS(DBS_SBS);
+       return TARGET_NUM_TIDS(SINGLE);
+}
+
 static void ath12k_core_stop(struct ath12k_base *ab)
 {
        if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
index fc906d7acd42df513b10ee5624492dc5f939dfe5..68b4031ac4842e8092918e1a23c170549f683862 100644 (file)
@@ -869,6 +869,9 @@ int ath12k_core_suspend(struct ath12k_base *ab);
 
 const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
                                                    const char *filename);
+u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab);
+u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab);
+u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab);
 
 static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state)
 {
index 44ba3a50e0755684eafd871450832cb5417be8fc..efa3411dc63d73248ff6c475d7553b27f5e65787 100644 (file)
 /* Num VDEVS per radio */
 #define TARGET_NUM_VDEVS       (16 + 1)
 
-#define TARGET_NUM_PEERS_PDEV  (512 + TARGET_NUM_VDEVS)
+#define TARGET_NUM_PEERS_PDEV_SINGLE   (TARGET_NUM_STATIONS_SINGLE + \
+                                        TARGET_NUM_VDEVS)
+#define TARGET_NUM_PEERS_PDEV_DBS      (TARGET_NUM_STATIONS_DBS + \
+                                        TARGET_NUM_VDEVS)
+#define TARGET_NUM_PEERS_PDEV_DBS_SBS  (TARGET_NUM_STATIONS_DBS_SBS + \
+                                        TARGET_NUM_VDEVS)
 
 /* Num of peers for Single Radio mode */
-#define TARGET_NUM_PEERS_SINGLE                (TARGET_NUM_PEERS_PDEV)
+#define TARGET_NUM_PEERS_SINGLE                (TARGET_NUM_PEERS_PDEV_SINGLE)
 
 /* Num of peers for DBS */
-#define TARGET_NUM_PEERS_DBS           (2 * TARGET_NUM_PEERS_PDEV)
+#define TARGET_NUM_PEERS_DBS           (2 * TARGET_NUM_PEERS_PDEV_DBS)
 
 /* Num of peers for DBS_SBS */
-#define TARGET_NUM_PEERS_DBS_SBS       (3 * TARGET_NUM_PEERS_PDEV)
+#define TARGET_NUM_PEERS_DBS_SBS       (3 * TARGET_NUM_PEERS_PDEV_DBS_SBS)
 
-/* Max num of stations (per radio) */
-#define TARGET_NUM_STATIONS    512
+/* Max num of stations for Single Radio mode */
+#define TARGET_NUM_STATIONS_SINGLE     512
+
+/* Max num of stations for DBS */
+#define TARGET_NUM_STATIONS_DBS                128
+
+/* Max num of stations for DBS_SBS */
+#define TARGET_NUM_STATIONS_DBS_SBS    128
 
 #define TARGET_NUM_PEERS(x)    TARGET_NUM_PEERS_##x
 #define TARGET_NUM_PEER_KEYS   2
index 672c9d3470979f88d6b1a325901bc2e78d349d1f..046bb466a391f30fb3c1ee931f84ac3d389684ea 100644 (file)
@@ -7624,8 +7624,8 @@ static int ath12k_mac_setup_register(struct ath12k *ar,
        ath12k_mac_setup_ht_vht_cap(ar, cap, ht_cap);
        ath12k_mac_setup_sband_iftype_data(ar, cap);
 
-       ar->max_num_stations = TARGET_NUM_STATIONS;
-       ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
+       ar->max_num_stations = ath12k_core_get_max_station_per_radio(ar->ab);
+       ar->max_num_peers = ath12k_core_get_max_peers_per_radio(ar->ab);
 
        return 0;
 }
index 276351d68efb0b9a824d2a9ebb799c954cdaaa8f..7fc269eb4a0c43170c4be83275e7692fe699b69f 100644 (file)
@@ -179,18 +179,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
                             struct ath12k_wmi_resource_config_arg *config)
 {
        config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS;
-
-       if (ab->num_radios == 2) {
-               config->num_peers = TARGET_NUM_PEERS(DBS);
-               config->num_tids = TARGET_NUM_TIDS(DBS);
-       } else if (ab->num_radios == 3) {
-               config->num_peers = TARGET_NUM_PEERS(DBS_SBS);
-               config->num_tids = TARGET_NUM_TIDS(DBS_SBS);
-       } else {
-               /* Control should not reach here */
-               config->num_peers = TARGET_NUM_PEERS(SINGLE);
-               config->num_tids = TARGET_NUM_TIDS(SINGLE);
-       }
+       config->num_peers = ab->num_radios *
+               ath12k_core_get_max_peers_per_radio(ab);
+       config->num_tids = ath12k_core_get_max_num_tids(ab);
        config->num_offload_peers = TARGET_NUM_OFFLD_PEERS;
        config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
        config->num_peer_keys = TARGET_NUM_PEER_KEYS;