ath11k: add read variant from SMBIOS for download board data
authorWen Gong <quic_wgong@quicinc.com>
Mon, 22 Nov 2021 11:13:58 +0000 (13:13 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 22 Nov 2021 14:35:10 +0000 (16:35 +0200)
This is to read variant from SMBIOS such as read from DT, the variant
string will be used to one part of string which used to search board
data from board-2.bin.

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1

Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20211118100033.8384-1-quic_wgong@quicinc.com
drivers/net/wireless/ath/ath11k/core.c
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/qmi.c

index dd1a1bb078c39be0467252a628935ab9dfa7e8d9..a3a9bfef0c38b2e33cd3faa6cd9cb2701b57aba0 100644 (file)
@@ -8,6 +8,9 @@
 #include <linux/remoteproc.h>
 #include <linux/firmware.h>
 #include <linux/of.h>
+#include <linux/dmi.h>
+#include <linux/ctype.h>
+
 #include "core.h"
 #include "dp_tx.h"
 #include "dp_rx.h"
@@ -384,6 +387,82 @@ int ath11k_core_resume(struct ath11k_base *ab)
 }
 EXPORT_SYMBOL(ath11k_core_resume);
 
+static void ath11k_core_check_bdfext(const struct dmi_header *hdr, void *data)
+{
+       struct ath11k_base *ab = data;
+       const char *bdf_ext;
+       const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC;
+       u8 bdf_enabled;
+       int i;
+       size_t len;
+
+       if (ab->qmi.target.bdf_ext[0] != '\0')
+               return;
+
+       if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE)
+               return;
+
+       if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) {
+               ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                          "wrong smbios bdf ext type length (%d).\n",
+                          hdr->length);
+               return;
+       }
+
+       bdf_enabled = *((u8 *)hdr + ATH11K_SMBIOS_BDF_EXT_OFFSET);
+       if (!bdf_enabled) {
+               ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n");
+               return;
+       }
+
+       /* Only one string exists (per spec) */
+       bdf_ext = (char *)hdr + hdr->length;
+
+       if (memcmp(bdf_ext, magic, strlen(magic)) != 0) {
+               ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                          "bdf variant magic does not match.\n");
+               return;
+       }
+
+       len = strlen(bdf_ext);
+       for (i = 0; i < len; i++) {
+               if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) {
+                       ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                                  "bdf variant name contains non ascii chars.\n");
+                       return;
+               }
+       }
+
+       /* Copy extension name without magic prefix */
+       if (strscpy(ab->qmi.target.bdf_ext, bdf_ext + strlen(magic),
+                   sizeof(ab->qmi.target.bdf_ext)) < 0) {
+               ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                          "bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
+                           bdf_ext);
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                  "found and validated bdf variant smbios_type 0x%x bdf %s\n",
+                  ATH11K_SMBIOS_BDF_EXT_TYPE, bdf_ext);
+}
+
+int ath11k_core_check_smbios(struct ath11k_base *ab)
+{
+       int ret;
+
+       ab->qmi.target.bdf_ext[0] = '\0';
+
+       ret = dmi_walk(ath11k_core_check_bdfext, ab);
+       if (ret)
+               return ret;
+
+       if (ab->qmi.target.bdf_ext[0] == '\0')
+               return -ENODATA;
+
+       return 0;
+}
+
 int ath11k_core_check_dt(struct ath11k_base *ab)
 {
        size_t max_len = sizeof(ab->qmi.target.bdf_ext);
index 0103cfd0508d5df6a0103786f81f407c2cc2cd0a..7b1770ae0e7c8317ec30d3b364064b3dba736e5d 100644 (file)
@@ -938,6 +938,18 @@ struct ath11k_fw_stats_bcn {
        u32 tx_bcn_outage_cnt;
 };
 
+/* SMBIOS type containing Board Data File Name Extension */
+#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8
+
+/* SMBIOS type structure length (excluding strings-set) */
+#define ATH11K_SMBIOS_BDF_EXT_LENGTH 0x9
+
+/* Offset pointing to Board Data File Name Extension */
+#define ATH11K_SMBIOS_BDF_EXT_OFFSET 0x8
+
+/* The magic used by QCA spec */
+#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_"
+
 extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[];
 extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[];
 extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[];
@@ -959,6 +971,7 @@ int ath11k_core_fetch_bdf(struct ath11k_base *ath11k,
                          struct ath11k_board_data *bd);
 void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
 int ath11k_core_check_dt(struct ath11k_base *ath11k);
+int ath11k_core_check_smbios(struct ath11k_base *ab);
 
 void ath11k_core_halt(struct ath11k *ar);
 int ath11k_core_resume(struct ath11k_base *ab);
index 25eb22cbeaebb1308b8691f45bdd249bb76cb8d2..700a9c1370189d8a11761fb75d2a3722426fb4ec 100644 (file)
@@ -1991,6 +1991,10 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab)
                    ab->qmi.target.fw_build_timestamp,
                    ab->qmi.target.fw_build_id);
 
+       r = ath11k_core_check_smbios(ab);
+       if (r)
+               ath11k_dbg(ab, ATH11K_DBG_QMI, "SMBIOS bdf variant name not set.\n");
+
        r = ath11k_core_check_dt(ab);
        if (r)
                ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n");