123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- From: Thomas Hebb <[email protected]>
- 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 <[email protected]>
- ---
- 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
- @@ -1132,14 +1132,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,
- @@ -1177,69 +1224,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:
- @@ -1248,12 +1249,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);
-
- @@ -1279,17 +1280,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;
|