OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From: Thomas Hebb <tommyhebb@gmail.com> |
2 | Date: Fri, 13 Apr 2018 17:40:26 +0300 |
||
3 | Subject: [PATCH] ath10k: search all IEs for variant before falling back |
||
4 | |||
5 | commit f2593cb1b291 ("ath10k: Search SMBIOS for OEM board file |
||
6 | extension") added a feature to ath10k that allows Board Data File |
||
7 | (BDF) conflicts between multiple devices that use the same device IDs |
||
8 | but have different calibration requirements to be resolved by allowing |
||
9 | a "variant" string to be stored in SMBIOS [and later device tree, added |
||
10 | by commit d06f26c5c8a4 ("ath10k: search DT for qcom,ath10k-calibration- |
||
11 | variant")] that gets appended to the ID stored in board-2.bin. |
||
12 | |||
13 | This original patch had a regression, however. Namely that devices with |
||
14 | a variant present in SMBIOS that didn't need custom BDFs could no longer |
||
15 | find the default BDF, which has no variant appended. The patch was |
||
16 | reverted and re-applied with a fix for this issue in commit 1657b8f84ed9 |
||
17 | ("search SMBIOS for OEM board file extension"). |
||
18 | |||
19 | But the fix to fall back to a default BDF introduced another issue: the |
||
20 | driver currently parses IEs in board-2.bin one by one, and for each one |
||
21 | it first checks to see if it matches the ID with the variant appended. |
||
22 | If it doesn't, it checks to see if it matches the "fallback" ID with no |
||
23 | variant. If a matching BDF is found at any point during this search, the |
||
24 | search is terminated and that BDF is used. The issue is that it's very |
||
25 | possible (and is currently the case for board-2.bin files present in the |
||
26 | ath10k-firmware repository) for the default BDF to occur in an earlier |
||
27 | IE than the variant-specific BDF. In this case, the current code will |
||
28 | happily choose the default BDF even though a better-matching BDF is |
||
29 | present later in the file. |
||
30 | |||
31 | This patch fixes the issue by first searching the entire file for the ID |
||
32 | with variant, and searching for the fallback ID only if that search |
||
33 | fails. It also includes some code cleanup in the area, as |
||
34 | ath10k_core_fetch_board_data_api_n() no longer does its own string |
||
35 | mangling to remove the variant from an ID, instead leaving that job to a |
||
36 | new flag passed to ath10k_core_create_board_name(). |
||
37 | |||
38 | I've tested this patch on a QCA4019 and verified that the driver behaves |
||
39 | correctly for 1) both fallback and variant BDFs present, 2) only fallback |
||
40 | BDF present, and 3) no matching BDFs present. |
||
41 | |||
42 | Fixes: 1657b8f84ed9 ("ath10k: search SMBIOS for OEM board file extension") |
||
43 | Signed-off-by: Thomas Hebb <tommyhebb@gmail.com> |
||
44 | Signed-off-by: Kalle Valo <kvalo@codeaurora.org> |
||
45 | |||
46 | Origin: backport, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c8489668065a283d3027e86e877b103a87f99d22 |
||
47 | --- |
||
48 | ath10k-4.13/core.c | 134 ++++++++++++++++++--------------- |
||
49 | 1 file changed, 72 insertions(+), 62 deletions(-) |
||
50 | |||
51 | --- a/ath10k-4.13/core.c |
||
52 | +++ b/ath10k-4.13/core.c |
||
3 | office | 53 | @@ -1419,14 +1419,61 @@ out: |
1 | office | 54 | return ret; |
55 | } |
||
56 | |||
57 | +static int ath10k_core_search_bd(struct ath10k *ar, |
||
58 | + const char *boardname, |
||
59 | + const u8 *data, |
||
60 | + size_t len) |
||
61 | +{ |
||
62 | + size_t ie_len; |
||
63 | + struct ath10k_fw_ie *hdr; |
||
64 | + int ret = -ENOENT, ie_id; |
||
65 | + |
||
66 | + while (len > sizeof(struct ath10k_fw_ie)) { |
||
67 | + hdr = (struct ath10k_fw_ie *)data; |
||
68 | + ie_id = le32_to_cpu(hdr->id); |
||
69 | + ie_len = le32_to_cpu(hdr->len); |
||
70 | + |
||
71 | + len -= sizeof(*hdr); |
||
72 | + data = hdr->data; |
||
73 | + |
||
74 | + if (len < ALIGN(ie_len, 4)) { |
||
75 | + ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", |
||
76 | + ie_id, ie_len, len); |
||
77 | + return -EINVAL; |
||
78 | + } |
||
79 | + |
||
80 | + switch (ie_id) { |
||
81 | + case ATH10K_BD_IE_BOARD: |
||
82 | + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, |
||
83 | + boardname); |
||
84 | + if (ret == -ENOENT) |
||
85 | + /* no match found, continue */ |
||
86 | + break; |
||
87 | + |
||
88 | + /* either found or error, so stop searching */ |
||
89 | + goto out; |
||
90 | + } |
||
91 | + |
||
92 | + /* jump over the padding */ |
||
93 | + ie_len = ALIGN(ie_len, 4); |
||
94 | + |
||
95 | + len -= ie_len; |
||
96 | + data += ie_len; |
||
97 | + } |
||
98 | + |
||
99 | +out: |
||
100 | + /* return result of parse_bd_ie_board() or -ENOENT */ |
||
101 | + return ret; |
||
102 | +} |
||
103 | + |
||
104 | static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, |
||
105 | const char *boardname, |
||
106 | + const char *fallback_boardname, |
||
107 | const char *filename) |
||
108 | { |
||
109 | - size_t len, magic_len, ie_len; |
||
110 | - struct ath10k_fw_ie *hdr; |
||
111 | + size_t len, magic_len; |
||
112 | const u8 *data; |
||
113 | - int ret, ie_id; |
||
114 | + int ret; |
||
115 | |||
116 | ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, |
||
117 | ar->hw_params.fw.dir, |
||
3 | office | 118 | @@ -1464,73 +1511,28 @@ static int ath10k_core_fetch_board_data_ |
1 | office | 119 | data += magic_len; |
120 | len -= magic_len; |
||
121 | |||
122 | - while (len > sizeof(struct ath10k_fw_ie)) { |
||
123 | - hdr = (struct ath10k_fw_ie *)data; |
||
124 | - ie_id = le32_to_cpu(hdr->id); |
||
125 | - ie_len = le32_to_cpu(hdr->len); |
||
126 | - |
||
127 | - len -= sizeof(*hdr); |
||
128 | - data = hdr->data; |
||
129 | - |
||
130 | - if (len < ALIGN(ie_len, 4)) { |
||
131 | - ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", |
||
132 | - ie_id, ie_len, len); |
||
133 | - ret = -EINVAL; |
||
134 | - goto err; |
||
135 | - } |
||
136 | - |
||
137 | - switch (ie_id) { |
||
138 | - case ATH10K_BD_IE_BOARD: |
||
139 | - ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, |
||
140 | - boardname); |
||
141 | - if (ret == -ENOENT && ar->id.bdf_ext[0] != '\0') { |
||
142 | - /* try default bdf if variant was not found */ |
||
143 | - char *s, *v = ",variant="; |
||
144 | - char boardname2[100]; |
||
145 | - |
||
146 | - strlcpy(boardname2, boardname, |
||
147 | - sizeof(boardname2)); |
||
148 | - |
||
149 | - s = strstr(boardname2, v); |
||
150 | - if (s) |
||
151 | - *s = '\0'; /* strip ",variant=%s" */ |
||
152 | - |
||
153 | - ret = ath10k_core_parse_bd_ie_board(ar, data, |
||
154 | - ie_len, |
||
155 | - boardname2); |
||
156 | - } |
||
157 | - |
||
158 | - if (ret == -ENOENT) |
||
159 | - /* no match found, continue */ |
||
160 | - break; |
||
161 | - else if (ret) |
||
162 | - /* there was an error, bail out */ |
||
163 | - goto err; |
||
164 | - |
||
165 | - /* board data found */ |
||
166 | - goto out; |
||
167 | - } |
||
168 | + /* attempt to find boardname in the IE list */ |
||
169 | + ret = ath10k_core_search_bd(ar, boardname, data, len); |
||
170 | |||
171 | - /* jump over the padding */ |
||
172 | - ie_len = ALIGN(ie_len, 4); |
||
173 | - |
||
174 | - len -= ie_len; |
||
175 | - data += ie_len; |
||
176 | - } |
||
177 | + /* if we didn't find it and have a fallback name, try that */ |
||
178 | + if (ret == -ENOENT && fallback_boardname) |
||
179 | + ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); |
||
180 | |||
181 | out: |
||
182 | - if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) { |
||
183 | + if (ret == -ENOENT) { |
||
184 | ath10k_err(ar, |
||
185 | "failed to fetch board data for %s from %s/%s\n", |
||
186 | boardname, ar->hw_params.fw.dir, filename); |
||
187 | ret = -ENODATA; |
||
188 | - goto err; |
||
189 | } |
||
190 | |||
191 | /* Save firmware board name so we can display it later. */ |
||
192 | strlcpy(ar->normal_mode_fw.fw_file.fw_board_name, filename, |
||
193 | sizeof(ar->normal_mode_fw.fw_file.fw_board_name)); |
||
194 | |||
195 | + if (ret) |
||
196 | + goto err; |
||
197 | + |
||
198 | return 0; |
||
199 | |||
200 | err: |
||
3 | office | 201 | @@ -1539,12 +1541,12 @@ err: |
1 | office | 202 | } |
203 | |||
204 | static int ath10k_core_create_board_name(struct ath10k *ar, char *name, |
||
205 | - size_t name_len) |
||
206 | + size_t name_len, bool with_variant) |
||
207 | { |
||
208 | /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ |
||
209 | char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; |
||
210 | |||
211 | - if (ar->id.bdf_ext[0] != '\0') |
||
212 | + if (with_variant && ar->id.bdf_ext[0] != '\0') |
||
213 | scnprintf(variant, sizeof(variant), ",variant=%s", |
||
214 | ar->id.bdf_ext); |
||
215 | |||
3 | office | 216 | @@ -1570,21 +1572,31 @@ out: |
1 | office | 217 | |
218 | static int ath10k_core_fetch_board_file(struct ath10k *ar) |
||
219 | { |
||
220 | - char boardname[100]; |
||
221 | + char boardname[100], fallback_boardname[100]; |
||
222 | int ret; |
||
223 | |||
224 | - ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname)); |
||
225 | + ret = ath10k_core_create_board_name(ar, boardname, |
||
226 | + sizeof(boardname), true); |
||
227 | if (ret) { |
||
228 | ath10k_err(ar, "failed to create board name: %d", ret); |
||
229 | return ret; |
||
230 | } |
||
231 | |||
232 | + ret = ath10k_core_create_board_name(ar, fallback_boardname, |
||
233 | + sizeof(boardname), false); |
||
234 | + if (ret) { |
||
235 | + ath10k_err(ar, "failed to create fallback board name: %d", ret); |
||
236 | + return ret; |
||
237 | + } |
||
238 | + |
||
239 | ar->bd_api = 2; |
||
240 | if (ar->fwcfg.bname[0]) |
||
241 | ret = ath10k_core_fetch_board_data_api_n(ar, boardname, |
||
242 | + fallback_boardname, |
||
243 | ar->fwcfg.bname); |
||
244 | else |
||
245 | ret = ath10k_core_fetch_board_data_api_n(ar, boardname, |
||
246 | + fallback_boardname, |
||
247 | ATH10K_BOARD_API2_FILE); |
||
248 | if (!ret) |
||
249 | goto success; |