From 1c01e02575bd2af96741ba79ed12004fdfb15544 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 30 Nov 2017 14:30:06 +0100 Subject: [PATCH] ath10k-ct: search DT for BDF variant info Board Data File (BDF) is loaded upon driver boot-up procedure. The right board data file is identified on QCA4019 using bus, bmi-chip-id and bmi-board-id. The problem, however, can occur when the (default) board data file cannot fulfill the vendor requirements and it is necessary to use a different board data file. This problem was solved for SMBIOS by adding a special SMBIOS type 0xF8. Something similar has to be provided for systems without SMBIOS but with device trees. No solution was specified by QCA and therefore a new one has to be found for ath10k. The device tree requires addition strings to define the variant name wifi@a000000 { status = "okay"; qcom,ath10k-calibration-variant = "RT-AC58U"; }; wifi@a800000 { status = "okay"; qcom,ath10k-calibration-variant = "RT-AC58U"; }; This would create the boarddata identifiers for the board-2.bin search * bus=ahb,bmi-chip-id=0,bmi-board-id=16,variant=RT-AC58U * bus=ahb,bmi-chip-id=0,bmi-board-id=17,variant=RT-AC58U Signed-off-by: Sven Eckelmann --- package/kernel/ath10k-ct/Makefile | 2 +- .../081-ath10k-calibration-variant.patch | 113 ++++++++ ...-IEs-for-variant-before-falling-back.patch | 249 ++++++++++++++++++ 3 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 package/kernel/ath10k-ct/patches/081-ath10k-calibration-variant.patch create mode 100644 package/kernel/ath10k-ct/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch diff --git a/package/kernel/ath10k-ct/Makefile b/package/kernel/ath10k-ct/Makefile index e5d505b9f6..634bdf14be 100644 --- a/package/kernel/ath10k-ct/Makefile +++ b/package/kernel/ath10k-ct/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ath10k-ct -PKG_RELEASE=2 +PKG_RELEASE=3 PKG_LICENSE:=GPLv2 PKG_LICENSE_FILES:= diff --git a/package/kernel/ath10k-ct/patches/081-ath10k-calibration-variant.patch b/package/kernel/ath10k-ct/patches/081-ath10k-calibration-variant.patch new file mode 100644 index 0000000000..d51451b596 --- /dev/null +++ b/package/kernel/ath10k-ct/patches/081-ath10k-calibration-variant.patch @@ -0,0 +1,113 @@ +From d06f26c5c8a41f246a9c40862a77a55725cedbd3 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Fri, 8 Dec 2017 11:37:42 +0100 +Subject: ath10k: search DT for qcom,ath10k-calibration-variant + +Board Data File (BDF) is loaded upon driver boot-up procedure. The right +board data file is identified on QCA4019 using bus, bmi-chip-id and +bmi-board-id. + +The problem, however, can occur when the (default) board data file cannot +fulfill with the vendor requirements and it is necessary to use a different +board data file. + +This problem was solved for SMBIOS by adding a special SMBIOS type 0xF8. +Something similar has to be provided for systems without SMBIOS but with +device trees. No solution was specified by QCA and therefore a new one has +to be found for ath10k. + +The device tree requires addition strings to define the variant name + + wifi@a000000 { + status = "okay"; + qcom,ath10k-calibration-variant = "RT-AC58U"; + }; + + wifi@a800000 { + status = "okay"; + qcom,ath10k-calibration-variant = "RT-AC58U"; + }; + +This would create the boarddata identifiers for the board-2.bin search + + * bus=ahb,bmi-chip-id=0,bmi-board-id=16,variant=RT-AC58U + * bus=ahb,bmi-chip-id=0,bmi-board-id=17,variant=RT-AC58U + +Signed-off-by: Sven Eckelmann +Signed-off-by: Kalle Valo + +Origin: upstream, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d06f26c5c8a41f246a9c40862a77a55725cedbd3 +--- + ath10k-4.13/core.c | 40 ++++++++++++++++++++++++++++------ + 1 file changed, 33 insertions(+), 7 deletions(-) + +--- a/ath10k-4.13/core.c ++++ b/ath10k-4.13/core.c +@@ -889,6 +889,28 @@ static int ath10k_core_check_smbios(stru + return 0; + } + ++static int ath10k_core_check_dt(struct ath10k *ar) ++{ ++ struct device_node *node; ++ const char *variant = NULL; ++ ++ node = ar->dev->of_node; ++ if (!node) ++ return -ENOENT; ++ ++ of_property_read_string(node, "qcom,ath10k-calibration-variant", ++ &variant); ++ if (!variant) ++ return -ENODATA; ++ ++ if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0) ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, ++ "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", ++ variant); ++ ++ return 0; ++} ++ + static int ath10k_download_and_run_otp(struct ath10k *ar) + { + u32 result, address = ar->hw_params.patch_load_addr; +@@ -1522,19 +1544,19 @@ static int ath10k_core_create_board_name + /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ + char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; + ++ if (ar->id.bdf_ext[0] != '\0') ++ scnprintf(variant, sizeof(variant), ",variant=%s", ++ ar->id.bdf_ext); ++ + if (ar->id.bmi_ids_valid) { + scnprintf(name, name_len, +- "bus=%s,bmi-chip-id=%d,bmi-board-id=%d", ++ "bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s", + ath10k_bus_str(ar->hif.bus), + ar->id.bmi_chip_id, +- ar->id.bmi_board_id); ++ ar->id.bmi_board_id, variant); + goto out; + } + +- if (ar->id.bdf_ext[0] != '\0') +- scnprintf(variant, sizeof(variant), ",variant=%s", +- ar->id.bdf_ext); +- + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s", + ath10k_bus_str(ar->hif.bus), +@@ -2964,7 +2986,11 @@ static int ath10k_core_probe_fw(struct a + + ret = ath10k_core_check_smbios(ar); + if (ret) +- ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not set.\n"); ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n"); ++ ++ ret = ath10k_core_check_dt(ar); ++ if (ret) ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n"); + + ret = ath10k_core_fetch_board_file(ar); + if (ret) { diff --git a/package/kernel/ath10k-ct/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch b/package/kernel/ath10k-ct/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch new file mode 100644 index 0000000000..a82bbda3cc --- /dev/null +++ b/package/kernel/ath10k-ct/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch @@ -0,0 +1,249 @@ +From: Thomas Hebb +Date: Fri, 13 Apr 2018 17:40:26 +0300 +Subject: [PATCH] ath10k: search all IEs for variant before falling back + +commit f2593cb1b291 ("ath10k: Search SMBIOS for OEM board file +extension") added a feature to ath10k that allows Board Data File +(BDF) conflicts between multiple devices that use the same device IDs +but have different calibration requirements to be resolved by allowing +a "variant" string to be stored in SMBIOS [and later device tree, added +by commit d06f26c5c8a4 ("ath10k: search DT for qcom,ath10k-calibration- +variant")] that gets appended to the ID stored in board-2.bin. + +This original patch had a regression, however. Namely that devices with +a variant present in SMBIOS that didn't need custom BDFs could no longer +find the default BDF, which has no variant appended. The patch was +reverted and re-applied with a fix for this issue in commit 1657b8f84ed9 +("search SMBIOS for OEM board file extension"). + +But the fix to fall back to a default BDF introduced another issue: the +driver currently parses IEs in board-2.bin one by one, and for each one +it first checks to see if it matches the ID with the variant appended. +If it doesn't, it checks to see if it matches the "fallback" ID with no +variant. If a matching BDF is found at any point during this search, the +search is terminated and that BDF is used. The issue is that it's very +possible (and is currently the case for board-2.bin files present in the +ath10k-firmware repository) for the default BDF to occur in an earlier +IE than the variant-specific BDF. In this case, the current code will +happily choose the default BDF even though a better-matching BDF is +present later in the file. + +This patch fixes the issue by first searching the entire file for the ID +with variant, and searching for the fallback ID only if that search +fails. It also includes some code cleanup in the area, as +ath10k_core_fetch_board_data_api_n() no longer does its own string +mangling to remove the variant from an ID, instead leaving that job to a +new flag passed to ath10k_core_create_board_name(). + +I've tested this patch on a QCA4019 and verified that the driver behaves +correctly for 1) both fallback and variant BDFs present, 2) only fallback +BDF present, and 3) no matching BDFs present. + +Fixes: 1657b8f84ed9 ("ath10k: search SMBIOS for OEM board file extension") +Signed-off-by: Thomas Hebb +Signed-off-by: Kalle Valo + +Origin: backport, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c8489668065a283d3027e86e877b103a87f99d22 +--- + ath10k-4.13/core.c | 134 ++++++++++++++++++--------------- + 1 file changed, 72 insertions(+), 62 deletions(-) + +--- a/ath10k-4.13/core.c ++++ b/ath10k-4.13/core.c +@@ -1419,14 +1419,61 @@ out: + return ret; + } + ++static int ath10k_core_search_bd(struct ath10k *ar, ++ const char *boardname, ++ const u8 *data, ++ size_t len) ++{ ++ size_t ie_len; ++ struct ath10k_fw_ie *hdr; ++ int ret = -ENOENT, ie_id; ++ ++ while (len > sizeof(struct ath10k_fw_ie)) { ++ hdr = (struct ath10k_fw_ie *)data; ++ ie_id = le32_to_cpu(hdr->id); ++ ie_len = le32_to_cpu(hdr->len); ++ ++ len -= sizeof(*hdr); ++ data = hdr->data; ++ ++ if (len < ALIGN(ie_len, 4)) { ++ ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", ++ ie_id, ie_len, len); ++ return -EINVAL; ++ } ++ ++ switch (ie_id) { ++ case ATH10K_BD_IE_BOARD: ++ ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, ++ boardname); ++ if (ret == -ENOENT) ++ /* no match found, continue */ ++ break; ++ ++ /* either found or error, so stop searching */ ++ goto out; ++ } ++ ++ /* jump over the padding */ ++ ie_len = ALIGN(ie_len, 4); ++ ++ len -= ie_len; ++ data += ie_len; ++ } ++ ++out: ++ /* return result of parse_bd_ie_board() or -ENOENT */ ++ return ret; ++} ++ + static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, + const char *boardname, ++ const char *fallback_boardname, + const char *filename) + { +- size_t len, magic_len, ie_len; +- struct ath10k_fw_ie *hdr; ++ size_t len, magic_len; + const u8 *data; +- int ret, ie_id; ++ int ret; + + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, +@@ -1464,73 +1511,28 @@ static int ath10k_core_fetch_board_data_ + data += magic_len; + len -= magic_len; + +- while (len > sizeof(struct ath10k_fw_ie)) { +- hdr = (struct ath10k_fw_ie *)data; +- ie_id = le32_to_cpu(hdr->id); +- ie_len = le32_to_cpu(hdr->len); +- +- len -= sizeof(*hdr); +- data = hdr->data; +- +- if (len < ALIGN(ie_len, 4)) { +- ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", +- ie_id, ie_len, len); +- ret = -EINVAL; +- goto err; +- } +- +- switch (ie_id) { +- case ATH10K_BD_IE_BOARD: +- ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, +- boardname); +- if (ret == -ENOENT && ar->id.bdf_ext[0] != '\0') { +- /* try default bdf if variant was not found */ +- char *s, *v = ",variant="; +- char boardname2[100]; +- +- strlcpy(boardname2, boardname, +- sizeof(boardname2)); +- +- s = strstr(boardname2, v); +- if (s) +- *s = '\0'; /* strip ",variant=%s" */ +- +- ret = ath10k_core_parse_bd_ie_board(ar, data, +- ie_len, +- boardname2); +- } +- +- if (ret == -ENOENT) +- /* no match found, continue */ +- break; +- else if (ret) +- /* there was an error, bail out */ +- goto err; +- +- /* board data found */ +- goto out; +- } ++ /* attempt to find boardname in the IE list */ ++ ret = ath10k_core_search_bd(ar, boardname, data, len); + +- /* jump over the padding */ +- ie_len = ALIGN(ie_len, 4); +- +- len -= ie_len; +- data += ie_len; +- } ++ /* if we didn't find it and have a fallback name, try that */ ++ if (ret == -ENOENT && fallback_boardname) ++ ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); + + out: +- if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) { ++ if (ret == -ENOENT) { + ath10k_err(ar, + "failed to fetch board data for %s from %s/%s\n", + boardname, ar->hw_params.fw.dir, filename); + ret = -ENODATA; +- goto err; + } + + /* Save firmware board name so we can display it later. */ + strlcpy(ar->normal_mode_fw.fw_file.fw_board_name, filename, + sizeof(ar->normal_mode_fw.fw_file.fw_board_name)); + ++ if (ret) ++ goto err; ++ + return 0; + + err: +@@ -1539,12 +1541,12 @@ err: + } + + static int ath10k_core_create_board_name(struct ath10k *ar, char *name, +- size_t name_len) ++ size_t name_len, bool with_variant) + { + /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ + char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; + +- if (ar->id.bdf_ext[0] != '\0') ++ if (with_variant && ar->id.bdf_ext[0] != '\0') + scnprintf(variant, sizeof(variant), ",variant=%s", + ar->id.bdf_ext); + +@@ -1570,21 +1572,31 @@ out: + + static int ath10k_core_fetch_board_file(struct ath10k *ar) + { +- char boardname[100]; ++ char boardname[100], fallback_boardname[100]; + int ret; + +- ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname)); ++ ret = ath10k_core_create_board_name(ar, boardname, ++ sizeof(boardname), true); + if (ret) { + ath10k_err(ar, "failed to create board name: %d", ret); + return ret; + } + ++ ret = ath10k_core_create_board_name(ar, fallback_boardname, ++ sizeof(boardname), false); ++ if (ret) { ++ ath10k_err(ar, "failed to create fallback board name: %d", ret); ++ return ret; ++ } ++ + ar->bd_api = 2; + if (ar->fwcfg.bname[0]) + ret = ath10k_core_fetch_board_data_api_n(ar, boardname, ++ fallback_boardname, + ar->fwcfg.bname); + else + ret = ath10k_core_fetch_board_data_api_n(ar, boardname, ++ fallback_boardname, + ATH10K_BOARD_API2_FILE); + if (!ret) + goto success; -- 2.30.2