diff options
author | Christian Lamparter <chunkeey@gmail.com> | 2018-03-01 17:23:22 +0100 |
---|---|---|
committer | Mathias Kresin <dev@kresin.me> | 2018-03-14 19:04:51 +0100 |
commit | e713b5ba6f28617e1db06fdaec6464d1ad7be4b4 (patch) | |
tree | b7bde2346a36c32bd0614b172d69b3488e6a335c /package/kernel | |
parent | 249a9b35e0937150e7557931bcdca8b95a6e274d (diff) | |
download | upstream-e713b5ba6f28617e1db06fdaec6464d1ad7be4b4.tar.gz upstream-e713b5ba6f28617e1db06fdaec6464d1ad7be4b4.tar.bz2 upstream-e713b5ba6f28617e1db06fdaec6464d1ad7be4b4.zip |
mac80211: ath10k: search all IEs for variant before falling back
This patch adds the patch that was posted to ath10k-devel ML:
<https://patchwork.kernel.org/patch/10233491/>
|From: Thomas Hebb <tommyhebb@gmail.com>
|Subject: [PATCH] ath10k: search all IEs for variant before falling back
|Date: Wed, 21 Feb 2018 11:43:39 -0500
|[...]
|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 <tommyhebb@gmail.com>
Note: 937-ath10k-calibration-variant.patch has been reassigned a new 081
number, as it now ships with upstream.... But also because this patch
requires the change in ath10k_core_create_board_name().
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Diffstat (limited to 'package/kernel')
-rw-r--r-- | package/kernel/mac80211/patches/081-ath10k-calibration-variant.patch (renamed from package/kernel/mac80211/patches/937-ath10k-calibration-variant.patch) | 0 | ||||
-rw-r--r-- | package/kernel/mac80211/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch | 237 |
2 files changed, 237 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/937-ath10k-calibration-variant.patch b/package/kernel/mac80211/patches/081-ath10k-calibration-variant.patch index f9a830c7a6..f9a830c7a6 100644 --- a/package/kernel/mac80211/patches/937-ath10k-calibration-variant.patch +++ b/package/kernel/mac80211/patches/081-ath10k-calibration-variant.patch diff --git a/package/kernel/mac80211/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch b/package/kernel/mac80211/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch new file mode 100644 index 0000000000..cac396aeca --- /dev/null +++ b/package/kernel/mac80211/patches/160-ath10k-search-all-IEs-for-variant-before-falling-back.patch @@ -0,0 +1,237 @@ +From: Thomas Hebb <tommyhebb@gmail.com> +Subject: [PATCH] ath10k: search all IEs for variant before falling back +Date: Wed, 21 Feb 2018 11:43:39 -0500 + +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 <tommyhebb@gmail.com> +--- + drivers/net/wireless/ath/ath10k/core.c | 134 ++++++++++++++++++--------------- + 1 file changed, 72 insertions(+), 62 deletions(-) + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -1129,14 +1129,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, +@@ -1174,69 +1221,23 @@ 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; +- } ++ /* attempt to find boardname in the IE list */ ++ ret = ath10k_core_search_bd(ar, boardname, data, len); + +- 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 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); + +- if (ret == -ENOENT) +- /* no match found, continue */ +- break; +- else if (ret) +- /* there was an error, bail out */ +- goto err; +- +- /* board data found */ +- goto out; +- } +- +- /* jump over the padding */ +- ie_len = ALIGN(ie_len, 4); +- +- len -= ie_len; +- data += ie_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; + } + ++ if (ret) ++ goto err; ++ + return 0; + + err: +@@ -1245,12 +1246,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); + +@@ -1276,17 +1277,26 @@ 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; + ret = ath10k_core_fetch_board_data_api_n(ar, boardname, ++ fallback_boardname, + ATH10K_BOARD_API2_FILE); + if (!ret) + goto success; |