diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-03-05 14:24:50 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-03-06 15:16:16 -0500 |
commit | 15854ef94f54ae8fa8b95eb66a2cfa5dcff481e9 (patch) | |
tree | 8cc0e5e8088750722dbcbc33087bca5af1234a36 | |
parent | 702e0630ee50c5f72e84da59daf5b23729140b62 (diff) |
iwlwifi: move firmware request into drv
Firmware request is a base driver flow,
it isn't related to any specific mode.
Move the code related to it into the
base driver file iwl-drv.c.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 625 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-ucode.c | 622 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-wifi.h | 5 |
3 files changed, 625 insertions, 627 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 590f57662754..343f41eb4e4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -61,12 +61,637 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/completion.h> | 63 | #include <linux/completion.h> |
64 | #include <linux/dma-mapping.h> | ||
65 | #include <linux/firmware.h> | ||
66 | #include <linux/module.h> | ||
64 | 67 | ||
65 | #include "iwl-drv.h" | 68 | #include "iwl-drv.h" |
66 | #include "iwl-trans.h" | 69 | #include "iwl-trans.h" |
67 | #include "iwl-wifi.h" | 70 | #include "iwl-wifi.h" |
71 | #include "iwl-shared.h" | ||
68 | #include "iwl-op-mode.h" | 72 | #include "iwl-op-mode.h" |
69 | 73 | ||
74 | static void iwl_free_fw_desc(struct iwl_nic *nic, struct fw_desc *desc) | ||
75 | { | ||
76 | if (desc->v_addr) | ||
77 | dma_free_coherent(trans(nic)->dev, desc->len, | ||
78 | desc->v_addr, desc->p_addr); | ||
79 | desc->v_addr = NULL; | ||
80 | desc->len = 0; | ||
81 | } | ||
82 | |||
83 | static void iwl_free_fw_img(struct iwl_nic *nic, struct fw_img *img) | ||
84 | { | ||
85 | iwl_free_fw_desc(nic, &img->code); | ||
86 | iwl_free_fw_desc(nic, &img->data); | ||
87 | } | ||
88 | |||
89 | static void iwl_dealloc_ucode(struct iwl_nic *nic) | ||
90 | { | ||
91 | iwl_free_fw_img(nic, &nic->fw.ucode_rt); | ||
92 | iwl_free_fw_img(nic, &nic->fw.ucode_init); | ||
93 | iwl_free_fw_img(nic, &nic->fw.ucode_wowlan); | ||
94 | } | ||
95 | |||
96 | static int iwl_alloc_fw_desc(struct iwl_nic *nic, struct fw_desc *desc, | ||
97 | const void *data, size_t len) | ||
98 | { | ||
99 | if (!len) { | ||
100 | desc->v_addr = NULL; | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | desc->v_addr = dma_alloc_coherent(trans(nic)->dev, len, | ||
105 | &desc->p_addr, GFP_KERNEL); | ||
106 | if (!desc->v_addr) | ||
107 | return -ENOMEM; | ||
108 | |||
109 | desc->len = len; | ||
110 | memcpy(desc->v_addr, data, len); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | ||
115 | |||
116 | #define UCODE_EXPERIMENTAL_INDEX 100 | ||
117 | #define UCODE_EXPERIMENTAL_TAG "exp" | ||
118 | |||
119 | static int iwl_request_firmware(struct iwl_nic *nic, bool first) | ||
120 | { | ||
121 | const struct iwl_cfg *cfg = cfg(nic); | ||
122 | const char *name_pre = cfg->fw_name_pre; | ||
123 | char tag[8]; | ||
124 | |||
125 | if (first) { | ||
126 | #ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE | ||
127 | nic->fw_index = UCODE_EXPERIMENTAL_INDEX; | ||
128 | strcpy(tag, UCODE_EXPERIMENTAL_TAG); | ||
129 | } else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) { | ||
130 | #endif | ||
131 | nic->fw_index = cfg->ucode_api_max; | ||
132 | sprintf(tag, "%d", nic->fw_index); | ||
133 | } else { | ||
134 | nic->fw_index--; | ||
135 | sprintf(tag, "%d", nic->fw_index); | ||
136 | } | ||
137 | |||
138 | if (nic->fw_index < cfg->ucode_api_min) { | ||
139 | IWL_ERR(nic, "no suitable firmware found!\n"); | ||
140 | return -ENOENT; | ||
141 | } | ||
142 | |||
143 | sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); | ||
144 | |||
145 | IWL_DEBUG_INFO(nic, "attempting to load firmware %s'%s'\n", | ||
146 | (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) | ||
147 | ? "EXPERIMENTAL " : "", | ||
148 | nic->firmware_name); | ||
149 | |||
150 | return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name, | ||
151 | trans(nic)->dev, | ||
152 | GFP_KERNEL, nic, iwl_ucode_callback); | ||
153 | } | ||
154 | |||
155 | struct iwlagn_firmware_pieces { | ||
156 | const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; | ||
157 | size_t inst_size, data_size, init_size, init_data_size, | ||
158 | wowlan_inst_size, wowlan_data_size; | ||
159 | |||
160 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | ||
161 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | ||
162 | }; | ||
163 | |||
164 | static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic, | ||
165 | const struct firmware *ucode_raw, | ||
166 | struct iwlagn_firmware_pieces *pieces) | ||
167 | { | ||
168 | struct iwl_ucode_header *ucode = (void *)ucode_raw->data; | ||
169 | u32 api_ver, hdr_size, build; | ||
170 | char buildstr[25]; | ||
171 | const u8 *src; | ||
172 | |||
173 | nic->fw.ucode_ver = le32_to_cpu(ucode->ver); | ||
174 | api_ver = IWL_UCODE_API(nic->fw.ucode_ver); | ||
175 | |||
176 | switch (api_ver) { | ||
177 | default: | ||
178 | hdr_size = 28; | ||
179 | if (ucode_raw->size < hdr_size) { | ||
180 | IWL_ERR(nic, "File size too small!\n"); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | build = le32_to_cpu(ucode->u.v2.build); | ||
184 | pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); | ||
185 | pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); | ||
186 | pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); | ||
187 | pieces->init_data_size = | ||
188 | le32_to_cpu(ucode->u.v2.init_data_size); | ||
189 | src = ucode->u.v2.data; | ||
190 | break; | ||
191 | case 0: | ||
192 | case 1: | ||
193 | case 2: | ||
194 | hdr_size = 24; | ||
195 | if (ucode_raw->size < hdr_size) { | ||
196 | IWL_ERR(nic, "File size too small!\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | build = 0; | ||
200 | pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); | ||
201 | pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); | ||
202 | pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); | ||
203 | pieces->init_data_size = | ||
204 | le32_to_cpu(ucode->u.v1.init_data_size); | ||
205 | src = ucode->u.v1.data; | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | if (build) | ||
210 | sprintf(buildstr, " build %u%s", build, | ||
211 | (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) | ||
212 | ? " (EXP)" : ""); | ||
213 | else | ||
214 | buildstr[0] = '\0'; | ||
215 | |||
216 | snprintf(nic->fw.fw_version, | ||
217 | sizeof(nic->fw.fw_version), | ||
218 | "%u.%u.%u.%u%s", | ||
219 | IWL_UCODE_MAJOR(nic->fw.ucode_ver), | ||
220 | IWL_UCODE_MINOR(nic->fw.ucode_ver), | ||
221 | IWL_UCODE_API(nic->fw.ucode_ver), | ||
222 | IWL_UCODE_SERIAL(nic->fw.ucode_ver), | ||
223 | buildstr); | ||
224 | |||
225 | /* Verify size of file vs. image size info in file's header */ | ||
226 | if (ucode_raw->size != hdr_size + pieces->inst_size + | ||
227 | pieces->data_size + pieces->init_size + | ||
228 | pieces->init_data_size) { | ||
229 | |||
230 | IWL_ERR(nic, | ||
231 | "uCode file size %d does not match expected size\n", | ||
232 | (int)ucode_raw->size); | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | pieces->inst = src; | ||
237 | src += pieces->inst_size; | ||
238 | pieces->data = src; | ||
239 | src += pieces->data_size; | ||
240 | pieces->init = src; | ||
241 | src += pieces->init_size; | ||
242 | pieces->init_data = src; | ||
243 | src += pieces->init_data_size; | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int iwl_parse_tlv_firmware(struct iwl_nic *nic, | ||
249 | const struct firmware *ucode_raw, | ||
250 | struct iwlagn_firmware_pieces *pieces, | ||
251 | struct iwl_ucode_capabilities *capa) | ||
252 | { | ||
253 | struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; | ||
254 | struct iwl_ucode_tlv *tlv; | ||
255 | size_t len = ucode_raw->size; | ||
256 | const u8 *data; | ||
257 | int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; | ||
258 | int tmp; | ||
259 | u64 alternatives; | ||
260 | u32 tlv_len; | ||
261 | enum iwl_ucode_tlv_type tlv_type; | ||
262 | const u8 *tlv_data; | ||
263 | char buildstr[25]; | ||
264 | u32 build; | ||
265 | |||
266 | if (len < sizeof(*ucode)) { | ||
267 | IWL_ERR(nic, "uCode has invalid length: %zd\n", len); | ||
268 | return -EINVAL; | ||
269 | } | ||
270 | |||
271 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { | ||
272 | IWL_ERR(nic, "invalid uCode magic: 0X%x\n", | ||
273 | le32_to_cpu(ucode->magic)); | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Check which alternatives are present, and "downgrade" | ||
279 | * when the chosen alternative is not present, warning | ||
280 | * the user when that happens. Some files may not have | ||
281 | * any alternatives, so don't warn in that case. | ||
282 | */ | ||
283 | alternatives = le64_to_cpu(ucode->alternatives); | ||
284 | tmp = wanted_alternative; | ||
285 | if (wanted_alternative > 63) | ||
286 | wanted_alternative = 63; | ||
287 | while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) | ||
288 | wanted_alternative--; | ||
289 | if (wanted_alternative && wanted_alternative != tmp) | ||
290 | IWL_WARN(nic, | ||
291 | "uCode alternative %d not available, choosing %d\n", | ||
292 | tmp, wanted_alternative); | ||
293 | |||
294 | nic->fw.ucode_ver = le32_to_cpu(ucode->ver); | ||
295 | build = le32_to_cpu(ucode->build); | ||
296 | |||
297 | if (build) | ||
298 | sprintf(buildstr, " build %u%s", build, | ||
299 | (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) | ||
300 | ? " (EXP)" : ""); | ||
301 | else | ||
302 | buildstr[0] = '\0'; | ||
303 | |||
304 | snprintf(nic->fw.fw_version, | ||
305 | sizeof(nic->fw.fw_version), | ||
306 | "%u.%u.%u.%u%s", | ||
307 | IWL_UCODE_MAJOR(nic->fw.ucode_ver), | ||
308 | IWL_UCODE_MINOR(nic->fw.ucode_ver), | ||
309 | IWL_UCODE_API(nic->fw.ucode_ver), | ||
310 | IWL_UCODE_SERIAL(nic->fw.ucode_ver), | ||
311 | buildstr); | ||
312 | |||
313 | data = ucode->data; | ||
314 | |||
315 | len -= sizeof(*ucode); | ||
316 | |||
317 | while (len >= sizeof(*tlv)) { | ||
318 | u16 tlv_alt; | ||
319 | |||
320 | len -= sizeof(*tlv); | ||
321 | tlv = (void *)data; | ||
322 | |||
323 | tlv_len = le32_to_cpu(tlv->length); | ||
324 | tlv_type = le16_to_cpu(tlv->type); | ||
325 | tlv_alt = le16_to_cpu(tlv->alternative); | ||
326 | tlv_data = tlv->data; | ||
327 | |||
328 | if (len < tlv_len) { | ||
329 | IWL_ERR(nic, "invalid TLV len: %zd/%u\n", | ||
330 | len, tlv_len); | ||
331 | return -EINVAL; | ||
332 | } | ||
333 | len -= ALIGN(tlv_len, 4); | ||
334 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); | ||
335 | |||
336 | /* | ||
337 | * Alternative 0 is always valid. | ||
338 | * | ||
339 | * Skip alternative TLVs that are not selected. | ||
340 | */ | ||
341 | if (tlv_alt != 0 && tlv_alt != wanted_alternative) | ||
342 | continue; | ||
343 | |||
344 | switch (tlv_type) { | ||
345 | case IWL_UCODE_TLV_INST: | ||
346 | pieces->inst = tlv_data; | ||
347 | pieces->inst_size = tlv_len; | ||
348 | break; | ||
349 | case IWL_UCODE_TLV_DATA: | ||
350 | pieces->data = tlv_data; | ||
351 | pieces->data_size = tlv_len; | ||
352 | break; | ||
353 | case IWL_UCODE_TLV_INIT: | ||
354 | pieces->init = tlv_data; | ||
355 | pieces->init_size = tlv_len; | ||
356 | break; | ||
357 | case IWL_UCODE_TLV_INIT_DATA: | ||
358 | pieces->init_data = tlv_data; | ||
359 | pieces->init_data_size = tlv_len; | ||
360 | break; | ||
361 | case IWL_UCODE_TLV_BOOT: | ||
362 | IWL_ERR(nic, "Found unexpected BOOT ucode\n"); | ||
363 | break; | ||
364 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | ||
365 | if (tlv_len != sizeof(u32)) | ||
366 | goto invalid_tlv_len; | ||
367 | capa->max_probe_length = | ||
368 | le32_to_cpup((__le32 *)tlv_data); | ||
369 | break; | ||
370 | case IWL_UCODE_TLV_PAN: | ||
371 | if (tlv_len) | ||
372 | goto invalid_tlv_len; | ||
373 | capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; | ||
374 | break; | ||
375 | case IWL_UCODE_TLV_FLAGS: | ||
376 | /* must be at least one u32 */ | ||
377 | if (tlv_len < sizeof(u32)) | ||
378 | goto invalid_tlv_len; | ||
379 | /* and a proper number of u32s */ | ||
380 | if (tlv_len % sizeof(u32)) | ||
381 | goto invalid_tlv_len; | ||
382 | /* | ||
383 | * This driver only reads the first u32 as | ||
384 | * right now no more features are defined, | ||
385 | * if that changes then either the driver | ||
386 | * will not work with the new firmware, or | ||
387 | * it'll not take advantage of new features. | ||
388 | */ | ||
389 | capa->flags = le32_to_cpup((__le32 *)tlv_data); | ||
390 | break; | ||
391 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | ||
392 | if (tlv_len != sizeof(u32)) | ||
393 | goto invalid_tlv_len; | ||
394 | pieces->init_evtlog_ptr = | ||
395 | le32_to_cpup((__le32 *)tlv_data); | ||
396 | break; | ||
397 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: | ||
398 | if (tlv_len != sizeof(u32)) | ||
399 | goto invalid_tlv_len; | ||
400 | pieces->init_evtlog_size = | ||
401 | le32_to_cpup((__le32 *)tlv_data); | ||
402 | break; | ||
403 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: | ||
404 | if (tlv_len != sizeof(u32)) | ||
405 | goto invalid_tlv_len; | ||
406 | pieces->init_errlog_ptr = | ||
407 | le32_to_cpup((__le32 *)tlv_data); | ||
408 | break; | ||
409 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: | ||
410 | if (tlv_len != sizeof(u32)) | ||
411 | goto invalid_tlv_len; | ||
412 | pieces->inst_evtlog_ptr = | ||
413 | le32_to_cpup((__le32 *)tlv_data); | ||
414 | break; | ||
415 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: | ||
416 | if (tlv_len != sizeof(u32)) | ||
417 | goto invalid_tlv_len; | ||
418 | pieces->inst_evtlog_size = | ||
419 | le32_to_cpup((__le32 *)tlv_data); | ||
420 | break; | ||
421 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: | ||
422 | if (tlv_len != sizeof(u32)) | ||
423 | goto invalid_tlv_len; | ||
424 | pieces->inst_errlog_ptr = | ||
425 | le32_to_cpup((__le32 *)tlv_data); | ||
426 | break; | ||
427 | case IWL_UCODE_TLV_ENHANCE_SENS_TBL: | ||
428 | if (tlv_len) | ||
429 | goto invalid_tlv_len; | ||
430 | nic->fw.enhance_sensitivity_table = true; | ||
431 | break; | ||
432 | case IWL_UCODE_TLV_WOWLAN_INST: | ||
433 | pieces->wowlan_inst = tlv_data; | ||
434 | pieces->wowlan_inst_size = tlv_len; | ||
435 | break; | ||
436 | case IWL_UCODE_TLV_WOWLAN_DATA: | ||
437 | pieces->wowlan_data = tlv_data; | ||
438 | pieces->wowlan_data_size = tlv_len; | ||
439 | break; | ||
440 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: | ||
441 | if (tlv_len != sizeof(u32)) | ||
442 | goto invalid_tlv_len; | ||
443 | capa->standard_phy_calibration_size = | ||
444 | le32_to_cpup((__le32 *)tlv_data); | ||
445 | break; | ||
446 | default: | ||
447 | IWL_DEBUG_INFO(nic, "unknown TLV: %d\n", tlv_type); | ||
448 | break; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | if (len) { | ||
453 | IWL_ERR(nic, "invalid TLV after parsing: %zd\n", len); | ||
454 | iwl_print_hex_dump(nic, IWL_DL_FW, (u8 *)data, len); | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | |||
458 | return 0; | ||
459 | |||
460 | invalid_tlv_len: | ||
461 | IWL_ERR(nic, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); | ||
462 | iwl_print_hex_dump(nic, IWL_DL_FW, tlv_data, tlv_len); | ||
463 | |||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * iwl_ucode_callback - callback when firmware was loaded | ||
469 | * | ||
470 | * If loaded successfully, copies the firmware into buffers | ||
471 | * for the card to fetch (via DMA). | ||
472 | */ | ||
473 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | ||
474 | { | ||
475 | struct iwl_nic *nic = context; | ||
476 | const struct iwl_cfg *cfg = cfg(nic); | ||
477 | struct iwl_fw *fw = &nic->fw; | ||
478 | struct iwl_ucode_header *ucode; | ||
479 | int err; | ||
480 | struct iwlagn_firmware_pieces pieces; | ||
481 | const unsigned int api_max = cfg->ucode_api_max; | ||
482 | unsigned int api_ok = cfg->ucode_api_ok; | ||
483 | const unsigned int api_min = cfg->ucode_api_min; | ||
484 | u32 api_ver; | ||
485 | |||
486 | fw->ucode_capa.max_probe_length = 200; | ||
487 | fw->ucode_capa.standard_phy_calibration_size = | ||
488 | IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; | ||
489 | |||
490 | if (!api_ok) | ||
491 | api_ok = api_max; | ||
492 | |||
493 | memset(&pieces, 0, sizeof(pieces)); | ||
494 | |||
495 | if (!ucode_raw) { | ||
496 | if (nic->fw_index <= api_ok) | ||
497 | IWL_ERR(nic, | ||
498 | "request for firmware file '%s' failed.\n", | ||
499 | nic->firmware_name); | ||
500 | goto try_again; | ||
501 | } | ||
502 | |||
503 | IWL_DEBUG_INFO(nic, "Loaded firmware file '%s' (%zd bytes).\n", | ||
504 | nic->firmware_name, ucode_raw->size); | ||
505 | |||
506 | /* Make sure that we got at least the API version number */ | ||
507 | if (ucode_raw->size < 4) { | ||
508 | IWL_ERR(nic, "File size way too small!\n"); | ||
509 | goto try_again; | ||
510 | } | ||
511 | |||
512 | /* Data from ucode file: header followed by uCode images */ | ||
513 | ucode = (struct iwl_ucode_header *)ucode_raw->data; | ||
514 | |||
515 | if (ucode->ver) | ||
516 | err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces); | ||
517 | else | ||
518 | err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces, | ||
519 | &fw->ucode_capa); | ||
520 | |||
521 | if (err) | ||
522 | goto try_again; | ||
523 | |||
524 | api_ver = IWL_UCODE_API(nic->fw.ucode_ver); | ||
525 | |||
526 | /* | ||
527 | * api_ver should match the api version forming part of the | ||
528 | * firmware filename ... but we don't check for that and only rely | ||
529 | * on the API version read from firmware header from here on forward | ||
530 | */ | ||
531 | /* no api version check required for experimental uCode */ | ||
532 | if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) { | ||
533 | if (api_ver < api_min || api_ver > api_max) { | ||
534 | IWL_ERR(nic, | ||
535 | "Driver unable to support your firmware API. " | ||
536 | "Driver supports v%u, firmware is v%u.\n", | ||
537 | api_max, api_ver); | ||
538 | goto try_again; | ||
539 | } | ||
540 | |||
541 | if (api_ver < api_ok) { | ||
542 | if (api_ok != api_max) | ||
543 | IWL_ERR(nic, "Firmware has old API version, " | ||
544 | "expected v%u through v%u, got v%u.\n", | ||
545 | api_ok, api_max, api_ver); | ||
546 | else | ||
547 | IWL_ERR(nic, "Firmware has old API version, " | ||
548 | "expected v%u, got v%u.\n", | ||
549 | api_max, api_ver); | ||
550 | IWL_ERR(nic, "New firmware can be obtained from " | ||
551 | "http://www.intellinuxwireless.org/.\n"); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | IWL_INFO(nic, "loaded firmware version %s", nic->fw.fw_version); | ||
556 | |||
557 | /* | ||
558 | * For any of the failures below (before allocating pci memory) | ||
559 | * we will try to load a version with a smaller API -- maybe the | ||
560 | * user just got a corrupted version of the latest API. | ||
561 | */ | ||
562 | |||
563 | IWL_DEBUG_INFO(nic, "f/w package hdr ucode version raw = 0x%x\n", | ||
564 | nic->fw.ucode_ver); | ||
565 | IWL_DEBUG_INFO(nic, "f/w package hdr runtime inst size = %Zd\n", | ||
566 | pieces.inst_size); | ||
567 | IWL_DEBUG_INFO(nic, "f/w package hdr runtime data size = %Zd\n", | ||
568 | pieces.data_size); | ||
569 | IWL_DEBUG_INFO(nic, "f/w package hdr init inst size = %Zd\n", | ||
570 | pieces.init_size); | ||
571 | IWL_DEBUG_INFO(nic, "f/w package hdr init data size = %Zd\n", | ||
572 | pieces.init_data_size); | ||
573 | |||
574 | /* Verify that uCode images will fit in card's SRAM */ | ||
575 | if (pieces.inst_size > cfg->max_inst_size) { | ||
576 | IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n", | ||
577 | pieces.inst_size); | ||
578 | goto try_again; | ||
579 | } | ||
580 | |||
581 | if (pieces.data_size > cfg->max_data_size) { | ||
582 | IWL_ERR(nic, "uCode data len %Zd too large to fit in\n", | ||
583 | pieces.data_size); | ||
584 | goto try_again; | ||
585 | } | ||
586 | |||
587 | if (pieces.init_size > cfg->max_inst_size) { | ||
588 | IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n", | ||
589 | pieces.init_size); | ||
590 | goto try_again; | ||
591 | } | ||
592 | |||
593 | if (pieces.init_data_size > cfg->max_data_size) { | ||
594 | IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n", | ||
595 | pieces.init_data_size); | ||
596 | goto try_again; | ||
597 | } | ||
598 | |||
599 | /* Allocate ucode buffers for card's bus-master loading ... */ | ||
600 | |||
601 | /* Runtime instructions and 2 copies of data: | ||
602 | * 1) unmodified from disk | ||
603 | * 2) backup cache for save/restore during power-downs */ | ||
604 | if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.code, | ||
605 | pieces.inst, pieces.inst_size)) | ||
606 | goto err_pci_alloc; | ||
607 | if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.data, | ||
608 | pieces.data, pieces.data_size)) | ||
609 | goto err_pci_alloc; | ||
610 | |||
611 | /* Initialization instructions and data */ | ||
612 | if (pieces.init_size && pieces.init_data_size) { | ||
613 | if (iwl_alloc_fw_desc(nic, | ||
614 | &nic->fw.ucode_init.code, | ||
615 | pieces.init, pieces.init_size)) | ||
616 | goto err_pci_alloc; | ||
617 | if (iwl_alloc_fw_desc(nic, | ||
618 | &nic->fw.ucode_init.data, | ||
619 | pieces.init_data, pieces.init_data_size)) | ||
620 | goto err_pci_alloc; | ||
621 | } | ||
622 | |||
623 | /* WoWLAN instructions and data */ | ||
624 | if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { | ||
625 | if (iwl_alloc_fw_desc(nic, | ||
626 | &nic->fw.ucode_wowlan.code, | ||
627 | pieces.wowlan_inst, | ||
628 | pieces.wowlan_inst_size)) | ||
629 | goto err_pci_alloc; | ||
630 | if (iwl_alloc_fw_desc(nic, | ||
631 | &nic->fw.ucode_wowlan.data, | ||
632 | pieces.wowlan_data, | ||
633 | pieces.wowlan_data_size)) | ||
634 | goto err_pci_alloc; | ||
635 | } | ||
636 | |||
637 | /* Now that we can no longer fail, copy information */ | ||
638 | |||
639 | /* | ||
640 | * The (size - 16) / 12 formula is based on the information recorded | ||
641 | * for each event, which is of mode 1 (including timestamp) for all | ||
642 | * new microcodes that include this information. | ||
643 | */ | ||
644 | nic->init_evtlog_ptr = pieces.init_evtlog_ptr; | ||
645 | if (pieces.init_evtlog_size) | ||
646 | nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; | ||
647 | else | ||
648 | nic->init_evtlog_size = | ||
649 | cfg->base_params->max_event_log_size; | ||
650 | nic->init_errlog_ptr = pieces.init_errlog_ptr; | ||
651 | nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | ||
652 | if (pieces.inst_evtlog_size) | ||
653 | nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; | ||
654 | else | ||
655 | nic->inst_evtlog_size = | ||
656 | cfg->base_params->max_event_log_size; | ||
657 | nic->inst_errlog_ptr = pieces.inst_errlog_ptr; | ||
658 | |||
659 | /* | ||
660 | * figure out the offset of chain noise reset and gain commands | ||
661 | * base on the size of standard phy calibration commands table size | ||
662 | */ | ||
663 | if (fw->ucode_capa.standard_phy_calibration_size > | ||
664 | IWL_MAX_PHY_CALIBRATE_TBL_SIZE) | ||
665 | fw->ucode_capa.standard_phy_calibration_size = | ||
666 | IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; | ||
667 | |||
668 | /* We have our copies now, allow OS release its copies */ | ||
669 | release_firmware(ucode_raw); | ||
670 | complete(&nic->request_firmware_complete); | ||
671 | |||
672 | nic->op_mode = iwl_dvm_ops.start(nic->shrd->trans); | ||
673 | |||
674 | if (!nic->op_mode) | ||
675 | goto out_unbind; | ||
676 | |||
677 | return; | ||
678 | |||
679 | try_again: | ||
680 | /* try next, if any */ | ||
681 | release_firmware(ucode_raw); | ||
682 | if (iwl_request_firmware(nic, false)) | ||
683 | goto out_unbind; | ||
684 | return; | ||
685 | |||
686 | err_pci_alloc: | ||
687 | IWL_ERR(nic, "failed to allocate pci memory\n"); | ||
688 | iwl_dealloc_ucode(nic); | ||
689 | release_firmware(ucode_raw); | ||
690 | out_unbind: | ||
691 | complete(&nic->request_firmware_complete); | ||
692 | device_release_driver(trans(nic)->dev); | ||
693 | } | ||
694 | |||
70 | int iwl_drv_start(struct iwl_shared *shrd, | 695 | int iwl_drv_start(struct iwl_shared *shrd, |
71 | struct iwl_trans *trans, const struct iwl_cfg *cfg) | 696 | struct iwl_trans *trans, const struct iwl_cfg *cfg) |
72 | { | 697 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c index 12e79d04374f..64a9c5ce5f89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c | |||
@@ -28,11 +28,8 @@ | |||
28 | *****************************************************************************/ | 28 | *****************************************************************************/ |
29 | 29 | ||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | ||
32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
33 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
34 | #include <linux/dma-mapping.h> | ||
35 | #include <linux/firmware.h> | ||
36 | 33 | ||
37 | #include "iwl-ucode.h" | 34 | #include "iwl-ucode.h" |
38 | #include "iwl-wifi.h" | 35 | #include "iwl-wifi.h" |
@@ -83,46 +80,6 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { | |||
83 | * | 80 | * |
84 | ******************************************************************************/ | 81 | ******************************************************************************/ |
85 | 82 | ||
86 | static void iwl_free_fw_desc(struct iwl_nic *nic, struct fw_desc *desc) | ||
87 | { | ||
88 | if (desc->v_addr) | ||
89 | dma_free_coherent(trans(nic)->dev, desc->len, | ||
90 | desc->v_addr, desc->p_addr); | ||
91 | desc->v_addr = NULL; | ||
92 | desc->len = 0; | ||
93 | } | ||
94 | |||
95 | static void iwl_free_fw_img(struct iwl_nic *nic, struct fw_img *img) | ||
96 | { | ||
97 | iwl_free_fw_desc(nic, &img->code); | ||
98 | iwl_free_fw_desc(nic, &img->data); | ||
99 | } | ||
100 | |||
101 | void iwl_dealloc_ucode(struct iwl_nic *nic) | ||
102 | { | ||
103 | iwl_free_fw_img(nic, &nic->fw.ucode_rt); | ||
104 | iwl_free_fw_img(nic, &nic->fw.ucode_init); | ||
105 | iwl_free_fw_img(nic, &nic->fw.ucode_wowlan); | ||
106 | } | ||
107 | |||
108 | static int iwl_alloc_fw_desc(struct iwl_nic *nic, struct fw_desc *desc, | ||
109 | const void *data, size_t len) | ||
110 | { | ||
111 | if (!len) { | ||
112 | desc->v_addr = NULL; | ||
113 | return -EINVAL; | ||
114 | } | ||
115 | |||
116 | desc->v_addr = dma_alloc_coherent(trans(nic)->dev, len, | ||
117 | &desc->p_addr, GFP_KERNEL); | ||
118 | if (!desc->v_addr) | ||
119 | return -ENOMEM; | ||
120 | |||
121 | desc->len = len; | ||
122 | memcpy(desc->v_addr, data, len); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static inline struct fw_img *iwl_get_ucode_image(struct iwl_nic *nic, | 83 | static inline struct fw_img *iwl_get_ucode_image(struct iwl_nic *nic, |
127 | enum iwl_ucode_type ucode_type) | 84 | enum iwl_ucode_type ucode_type) |
128 | { | 85 | { |
@@ -685,582 +642,3 @@ int iwl_run_init_ucode(struct iwl_trans *trans) | |||
685 | iwl_trans_stop_device(trans); | 642 | iwl_trans_stop_device(trans); |
686 | return ret; | 643 | return ret; |
687 | } | 644 | } |
688 | |||
689 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | ||
690 | |||
691 | #define UCODE_EXPERIMENTAL_TAG "exp" | ||
692 | |||
693 | int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first) | ||
694 | { | ||
695 | const struct iwl_cfg *cfg = cfg(nic); | ||
696 | const char *name_pre = cfg->fw_name_pre; | ||
697 | char tag[8]; | ||
698 | |||
699 | if (first) { | ||
700 | #ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE | ||
701 | nic->fw_index = UCODE_EXPERIMENTAL_INDEX; | ||
702 | strcpy(tag, UCODE_EXPERIMENTAL_TAG); | ||
703 | } else if (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) { | ||
704 | #endif | ||
705 | nic->fw_index = cfg->ucode_api_max; | ||
706 | sprintf(tag, "%d", nic->fw_index); | ||
707 | } else { | ||
708 | nic->fw_index--; | ||
709 | sprintf(tag, "%d", nic->fw_index); | ||
710 | } | ||
711 | |||
712 | if (nic->fw_index < cfg->ucode_api_min) { | ||
713 | IWL_ERR(nic, "no suitable firmware found!\n"); | ||
714 | return -ENOENT; | ||
715 | } | ||
716 | |||
717 | sprintf(nic->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); | ||
718 | |||
719 | IWL_DEBUG_INFO(nic, "attempting to load firmware %s'%s'\n", | ||
720 | (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) | ||
721 | ? "EXPERIMENTAL " : "", | ||
722 | nic->firmware_name); | ||
723 | |||
724 | return request_firmware_nowait(THIS_MODULE, 1, nic->firmware_name, | ||
725 | trans(nic)->dev, | ||
726 | GFP_KERNEL, nic, iwl_ucode_callback); | ||
727 | } | ||
728 | |||
729 | struct iwlagn_firmware_pieces { | ||
730 | const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; | ||
731 | size_t inst_size, data_size, init_size, init_data_size, | ||
732 | wowlan_inst_size, wowlan_data_size; | ||
733 | |||
734 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | ||
735 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | ||
736 | }; | ||
737 | |||
738 | static int iwl_parse_v1_v2_firmware(struct iwl_nic *nic, | ||
739 | const struct firmware *ucode_raw, | ||
740 | struct iwlagn_firmware_pieces *pieces) | ||
741 | { | ||
742 | struct iwl_ucode_header *ucode = (void *)ucode_raw->data; | ||
743 | u32 api_ver, hdr_size, build; | ||
744 | char buildstr[25]; | ||
745 | const u8 *src; | ||
746 | |||
747 | nic->fw.ucode_ver = le32_to_cpu(ucode->ver); | ||
748 | api_ver = IWL_UCODE_API(nic->fw.ucode_ver); | ||
749 | |||
750 | switch (api_ver) { | ||
751 | default: | ||
752 | hdr_size = 28; | ||
753 | if (ucode_raw->size < hdr_size) { | ||
754 | IWL_ERR(nic, "File size too small!\n"); | ||
755 | return -EINVAL; | ||
756 | } | ||
757 | build = le32_to_cpu(ucode->u.v2.build); | ||
758 | pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); | ||
759 | pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); | ||
760 | pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); | ||
761 | pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); | ||
762 | src = ucode->u.v2.data; | ||
763 | break; | ||
764 | case 0: | ||
765 | case 1: | ||
766 | case 2: | ||
767 | hdr_size = 24; | ||
768 | if (ucode_raw->size < hdr_size) { | ||
769 | IWL_ERR(nic, "File size too small!\n"); | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | build = 0; | ||
773 | pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); | ||
774 | pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); | ||
775 | pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); | ||
776 | pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); | ||
777 | src = ucode->u.v1.data; | ||
778 | break; | ||
779 | } | ||
780 | |||
781 | if (build) | ||
782 | sprintf(buildstr, " build %u%s", build, | ||
783 | (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) | ||
784 | ? " (EXP)" : ""); | ||
785 | else | ||
786 | buildstr[0] = '\0'; | ||
787 | |||
788 | snprintf(nic->fw.fw_version, | ||
789 | sizeof(nic->fw.fw_version), | ||
790 | "%u.%u.%u.%u%s", | ||
791 | IWL_UCODE_MAJOR(nic->fw.ucode_ver), | ||
792 | IWL_UCODE_MINOR(nic->fw.ucode_ver), | ||
793 | IWL_UCODE_API(nic->fw.ucode_ver), | ||
794 | IWL_UCODE_SERIAL(nic->fw.ucode_ver), | ||
795 | buildstr); | ||
796 | |||
797 | /* Verify size of file vs. image size info in file's header */ | ||
798 | if (ucode_raw->size != hdr_size + pieces->inst_size + | ||
799 | pieces->data_size + pieces->init_size + | ||
800 | pieces->init_data_size) { | ||
801 | |||
802 | IWL_ERR(nic, | ||
803 | "uCode file size %d does not match expected size\n", | ||
804 | (int)ucode_raw->size); | ||
805 | return -EINVAL; | ||
806 | } | ||
807 | |||
808 | pieces->inst = src; | ||
809 | src += pieces->inst_size; | ||
810 | pieces->data = src; | ||
811 | src += pieces->data_size; | ||
812 | pieces->init = src; | ||
813 | src += pieces->init_size; | ||
814 | pieces->init_data = src; | ||
815 | src += pieces->init_data_size; | ||
816 | |||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int iwl_parse_tlv_firmware(struct iwl_nic *nic, | ||
821 | const struct firmware *ucode_raw, | ||
822 | struct iwlagn_firmware_pieces *pieces, | ||
823 | struct iwl_ucode_capabilities *capa) | ||
824 | { | ||
825 | struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; | ||
826 | struct iwl_ucode_tlv *tlv; | ||
827 | size_t len = ucode_raw->size; | ||
828 | const u8 *data; | ||
829 | int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; | ||
830 | int tmp; | ||
831 | u64 alternatives; | ||
832 | u32 tlv_len; | ||
833 | enum iwl_ucode_tlv_type tlv_type; | ||
834 | const u8 *tlv_data; | ||
835 | char buildstr[25]; | ||
836 | u32 build; | ||
837 | |||
838 | if (len < sizeof(*ucode)) { | ||
839 | IWL_ERR(nic, "uCode has invalid length: %zd\n", len); | ||
840 | return -EINVAL; | ||
841 | } | ||
842 | |||
843 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { | ||
844 | IWL_ERR(nic, "invalid uCode magic: 0X%x\n", | ||
845 | le32_to_cpu(ucode->magic)); | ||
846 | return -EINVAL; | ||
847 | } | ||
848 | |||
849 | /* | ||
850 | * Check which alternatives are present, and "downgrade" | ||
851 | * when the chosen alternative is not present, warning | ||
852 | * the user when that happens. Some files may not have | ||
853 | * any alternatives, so don't warn in that case. | ||
854 | */ | ||
855 | alternatives = le64_to_cpu(ucode->alternatives); | ||
856 | tmp = wanted_alternative; | ||
857 | if (wanted_alternative > 63) | ||
858 | wanted_alternative = 63; | ||
859 | while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) | ||
860 | wanted_alternative--; | ||
861 | if (wanted_alternative && wanted_alternative != tmp) | ||
862 | IWL_WARN(nic, | ||
863 | "uCode alternative %d not available, choosing %d\n", | ||
864 | tmp, wanted_alternative); | ||
865 | |||
866 | nic->fw.ucode_ver = le32_to_cpu(ucode->ver); | ||
867 | build = le32_to_cpu(ucode->build); | ||
868 | |||
869 | if (build) | ||
870 | sprintf(buildstr, " build %u%s", build, | ||
871 | (nic->fw_index == UCODE_EXPERIMENTAL_INDEX) | ||
872 | ? " (EXP)" : ""); | ||
873 | else | ||
874 | buildstr[0] = '\0'; | ||
875 | |||
876 | snprintf(nic->fw.fw_version, | ||
877 | sizeof(nic->fw.fw_version), | ||
878 | "%u.%u.%u.%u%s", | ||
879 | IWL_UCODE_MAJOR(nic->fw.ucode_ver), | ||
880 | IWL_UCODE_MINOR(nic->fw.ucode_ver), | ||
881 | IWL_UCODE_API(nic->fw.ucode_ver), | ||
882 | IWL_UCODE_SERIAL(nic->fw.ucode_ver), | ||
883 | buildstr); | ||
884 | |||
885 | data = ucode->data; | ||
886 | |||
887 | len -= sizeof(*ucode); | ||
888 | |||
889 | while (len >= sizeof(*tlv)) { | ||
890 | u16 tlv_alt; | ||
891 | |||
892 | len -= sizeof(*tlv); | ||
893 | tlv = (void *)data; | ||
894 | |||
895 | tlv_len = le32_to_cpu(tlv->length); | ||
896 | tlv_type = le16_to_cpu(tlv->type); | ||
897 | tlv_alt = le16_to_cpu(tlv->alternative); | ||
898 | tlv_data = tlv->data; | ||
899 | |||
900 | if (len < tlv_len) { | ||
901 | IWL_ERR(nic, "invalid TLV len: %zd/%u\n", | ||
902 | len, tlv_len); | ||
903 | return -EINVAL; | ||
904 | } | ||
905 | len -= ALIGN(tlv_len, 4); | ||
906 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); | ||
907 | |||
908 | /* | ||
909 | * Alternative 0 is always valid. | ||
910 | * | ||
911 | * Skip alternative TLVs that are not selected. | ||
912 | */ | ||
913 | if (tlv_alt != 0 && tlv_alt != wanted_alternative) | ||
914 | continue; | ||
915 | |||
916 | switch (tlv_type) { | ||
917 | case IWL_UCODE_TLV_INST: | ||
918 | pieces->inst = tlv_data; | ||
919 | pieces->inst_size = tlv_len; | ||
920 | break; | ||
921 | case IWL_UCODE_TLV_DATA: | ||
922 | pieces->data = tlv_data; | ||
923 | pieces->data_size = tlv_len; | ||
924 | break; | ||
925 | case IWL_UCODE_TLV_INIT: | ||
926 | pieces->init = tlv_data; | ||
927 | pieces->init_size = tlv_len; | ||
928 | break; | ||
929 | case IWL_UCODE_TLV_INIT_DATA: | ||
930 | pieces->init_data = tlv_data; | ||
931 | pieces->init_data_size = tlv_len; | ||
932 | break; | ||
933 | case IWL_UCODE_TLV_BOOT: | ||
934 | IWL_ERR(nic, "Found unexpected BOOT ucode\n"); | ||
935 | break; | ||
936 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | ||
937 | if (tlv_len != sizeof(u32)) | ||
938 | goto invalid_tlv_len; | ||
939 | capa->max_probe_length = | ||
940 | le32_to_cpup((__le32 *)tlv_data); | ||
941 | break; | ||
942 | case IWL_UCODE_TLV_PAN: | ||
943 | if (tlv_len) | ||
944 | goto invalid_tlv_len; | ||
945 | capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; | ||
946 | break; | ||
947 | case IWL_UCODE_TLV_FLAGS: | ||
948 | /* must be at least one u32 */ | ||
949 | if (tlv_len < sizeof(u32)) | ||
950 | goto invalid_tlv_len; | ||
951 | /* and a proper number of u32s */ | ||
952 | if (tlv_len % sizeof(u32)) | ||
953 | goto invalid_tlv_len; | ||
954 | /* | ||
955 | * This driver only reads the first u32 as | ||
956 | * right now no more features are defined, | ||
957 | * if that changes then either the driver | ||
958 | * will not work with the new firmware, or | ||
959 | * it'll not take advantage of new features. | ||
960 | */ | ||
961 | capa->flags = le32_to_cpup((__le32 *)tlv_data); | ||
962 | break; | ||
963 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | ||
964 | if (tlv_len != sizeof(u32)) | ||
965 | goto invalid_tlv_len; | ||
966 | pieces->init_evtlog_ptr = | ||
967 | le32_to_cpup((__le32 *)tlv_data); | ||
968 | break; | ||
969 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: | ||
970 | if (tlv_len != sizeof(u32)) | ||
971 | goto invalid_tlv_len; | ||
972 | pieces->init_evtlog_size = | ||
973 | le32_to_cpup((__le32 *)tlv_data); | ||
974 | break; | ||
975 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: | ||
976 | if (tlv_len != sizeof(u32)) | ||
977 | goto invalid_tlv_len; | ||
978 | pieces->init_errlog_ptr = | ||
979 | le32_to_cpup((__le32 *)tlv_data); | ||
980 | break; | ||
981 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: | ||
982 | if (tlv_len != sizeof(u32)) | ||
983 | goto invalid_tlv_len; | ||
984 | pieces->inst_evtlog_ptr = | ||
985 | le32_to_cpup((__le32 *)tlv_data); | ||
986 | break; | ||
987 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: | ||
988 | if (tlv_len != sizeof(u32)) | ||
989 | goto invalid_tlv_len; | ||
990 | pieces->inst_evtlog_size = | ||
991 | le32_to_cpup((__le32 *)tlv_data); | ||
992 | break; | ||
993 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: | ||
994 | if (tlv_len != sizeof(u32)) | ||
995 | goto invalid_tlv_len; | ||
996 | pieces->inst_errlog_ptr = | ||
997 | le32_to_cpup((__le32 *)tlv_data); | ||
998 | break; | ||
999 | case IWL_UCODE_TLV_ENHANCE_SENS_TBL: | ||
1000 | if (tlv_len) | ||
1001 | goto invalid_tlv_len; | ||
1002 | nic->fw.enhance_sensitivity_table = true; | ||
1003 | break; | ||
1004 | case IWL_UCODE_TLV_WOWLAN_INST: | ||
1005 | pieces->wowlan_inst = tlv_data; | ||
1006 | pieces->wowlan_inst_size = tlv_len; | ||
1007 | break; | ||
1008 | case IWL_UCODE_TLV_WOWLAN_DATA: | ||
1009 | pieces->wowlan_data = tlv_data; | ||
1010 | pieces->wowlan_data_size = tlv_len; | ||
1011 | break; | ||
1012 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: | ||
1013 | if (tlv_len != sizeof(u32)) | ||
1014 | goto invalid_tlv_len; | ||
1015 | capa->standard_phy_calibration_size = | ||
1016 | le32_to_cpup((__le32 *)tlv_data); | ||
1017 | break; | ||
1018 | default: | ||
1019 | IWL_DEBUG_INFO(nic, "unknown TLV: %d\n", tlv_type); | ||
1020 | break; | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | if (len) { | ||
1025 | IWL_ERR(nic, "invalid TLV after parsing: %zd\n", len); | ||
1026 | iwl_print_hex_dump(nic, IWL_DL_FW, (u8 *)data, len); | ||
1027 | return -EINVAL; | ||
1028 | } | ||
1029 | |||
1030 | return 0; | ||
1031 | |||
1032 | invalid_tlv_len: | ||
1033 | IWL_ERR(nic, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); | ||
1034 | iwl_print_hex_dump(nic, IWL_DL_FW, tlv_data, tlv_len); | ||
1035 | |||
1036 | return -EINVAL; | ||
1037 | } | ||
1038 | |||
1039 | /** | ||
1040 | * iwl_ucode_callback - callback when firmware was loaded | ||
1041 | * | ||
1042 | * If loaded successfully, copies the firmware into buffers | ||
1043 | * for the card to fetch (via DMA). | ||
1044 | */ | ||
1045 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | ||
1046 | { | ||
1047 | struct iwl_nic *nic = context; | ||
1048 | const struct iwl_cfg *cfg = cfg(nic); | ||
1049 | struct iwl_fw *fw = &nic->fw; | ||
1050 | struct iwl_ucode_header *ucode; | ||
1051 | int err; | ||
1052 | struct iwlagn_firmware_pieces pieces; | ||
1053 | const unsigned int api_max = cfg->ucode_api_max; | ||
1054 | unsigned int api_ok = cfg->ucode_api_ok; | ||
1055 | const unsigned int api_min = cfg->ucode_api_min; | ||
1056 | u32 api_ver; | ||
1057 | |||
1058 | fw->ucode_capa.max_probe_length = 200; | ||
1059 | fw->ucode_capa.standard_phy_calibration_size = | ||
1060 | IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; | ||
1061 | |||
1062 | if (!api_ok) | ||
1063 | api_ok = api_max; | ||
1064 | |||
1065 | memset(&pieces, 0, sizeof(pieces)); | ||
1066 | |||
1067 | if (!ucode_raw) { | ||
1068 | if (nic->fw_index <= api_ok) | ||
1069 | IWL_ERR(nic, | ||
1070 | "request for firmware file '%s' failed.\n", | ||
1071 | nic->firmware_name); | ||
1072 | goto try_again; | ||
1073 | } | ||
1074 | |||
1075 | IWL_DEBUG_INFO(nic, "Loaded firmware file '%s' (%zd bytes).\n", | ||
1076 | nic->firmware_name, ucode_raw->size); | ||
1077 | |||
1078 | /* Make sure that we got at least the API version number */ | ||
1079 | if (ucode_raw->size < 4) { | ||
1080 | IWL_ERR(nic, "File size way too small!\n"); | ||
1081 | goto try_again; | ||
1082 | } | ||
1083 | |||
1084 | /* Data from ucode file: header followed by uCode images */ | ||
1085 | ucode = (struct iwl_ucode_header *)ucode_raw->data; | ||
1086 | |||
1087 | if (ucode->ver) | ||
1088 | err = iwl_parse_v1_v2_firmware(nic, ucode_raw, &pieces); | ||
1089 | else | ||
1090 | err = iwl_parse_tlv_firmware(nic, ucode_raw, &pieces, | ||
1091 | &fw->ucode_capa); | ||
1092 | |||
1093 | if (err) | ||
1094 | goto try_again; | ||
1095 | |||
1096 | api_ver = IWL_UCODE_API(nic->fw.ucode_ver); | ||
1097 | |||
1098 | /* | ||
1099 | * api_ver should match the api version forming part of the | ||
1100 | * firmware filename ... but we don't check for that and only rely | ||
1101 | * on the API version read from firmware header from here on forward | ||
1102 | */ | ||
1103 | /* no api version check required for experimental uCode */ | ||
1104 | if (nic->fw_index != UCODE_EXPERIMENTAL_INDEX) { | ||
1105 | if (api_ver < api_min || api_ver > api_max) { | ||
1106 | IWL_ERR(nic, | ||
1107 | "Driver unable to support your firmware API. " | ||
1108 | "Driver supports v%u, firmware is v%u.\n", | ||
1109 | api_max, api_ver); | ||
1110 | goto try_again; | ||
1111 | } | ||
1112 | |||
1113 | if (api_ver < api_ok) { | ||
1114 | if (api_ok != api_max) | ||
1115 | IWL_ERR(nic, "Firmware has old API version, " | ||
1116 | "expected v%u through v%u, got v%u.\n", | ||
1117 | api_ok, api_max, api_ver); | ||
1118 | else | ||
1119 | IWL_ERR(nic, "Firmware has old API version, " | ||
1120 | "expected v%u, got v%u.\n", | ||
1121 | api_max, api_ver); | ||
1122 | IWL_ERR(nic, "New firmware can be obtained from " | ||
1123 | "http://www.intellinuxwireless.org/.\n"); | ||
1124 | } | ||
1125 | } | ||
1126 | |||
1127 | IWL_INFO(nic, "loaded firmware version %s", nic->fw.fw_version); | ||
1128 | |||
1129 | /* | ||
1130 | * For any of the failures below (before allocating pci memory) | ||
1131 | * we will try to load a version with a smaller API -- maybe the | ||
1132 | * user just got a corrupted version of the latest API. | ||
1133 | */ | ||
1134 | |||
1135 | IWL_DEBUG_INFO(nic, "f/w package hdr ucode version raw = 0x%x\n", | ||
1136 | nic->fw.ucode_ver); | ||
1137 | IWL_DEBUG_INFO(nic, "f/w package hdr runtime inst size = %Zd\n", | ||
1138 | pieces.inst_size); | ||
1139 | IWL_DEBUG_INFO(nic, "f/w package hdr runtime data size = %Zd\n", | ||
1140 | pieces.data_size); | ||
1141 | IWL_DEBUG_INFO(nic, "f/w package hdr init inst size = %Zd\n", | ||
1142 | pieces.init_size); | ||
1143 | IWL_DEBUG_INFO(nic, "f/w package hdr init data size = %Zd\n", | ||
1144 | pieces.init_data_size); | ||
1145 | |||
1146 | /* Verify that uCode images will fit in card's SRAM */ | ||
1147 | if (pieces.inst_size > cfg->max_inst_size) { | ||
1148 | IWL_ERR(nic, "uCode instr len %Zd too large to fit in\n", | ||
1149 | pieces.inst_size); | ||
1150 | goto try_again; | ||
1151 | } | ||
1152 | |||
1153 | if (pieces.data_size > cfg->max_data_size) { | ||
1154 | IWL_ERR(nic, "uCode data len %Zd too large to fit in\n", | ||
1155 | pieces.data_size); | ||
1156 | goto try_again; | ||
1157 | } | ||
1158 | |||
1159 | if (pieces.init_size > cfg->max_inst_size) { | ||
1160 | IWL_ERR(nic, "uCode init instr len %Zd too large to fit in\n", | ||
1161 | pieces.init_size); | ||
1162 | goto try_again; | ||
1163 | } | ||
1164 | |||
1165 | if (pieces.init_data_size > cfg->max_data_size) { | ||
1166 | IWL_ERR(nic, "uCode init data len %Zd too large to fit in\n", | ||
1167 | pieces.init_data_size); | ||
1168 | goto try_again; | ||
1169 | } | ||
1170 | |||
1171 | /* Allocate ucode buffers for card's bus-master loading ... */ | ||
1172 | |||
1173 | /* Runtime instructions and 2 copies of data: | ||
1174 | * 1) unmodified from disk | ||
1175 | * 2) backup cache for save/restore during power-downs */ | ||
1176 | if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.code, | ||
1177 | pieces.inst, pieces.inst_size)) | ||
1178 | goto err_pci_alloc; | ||
1179 | if (iwl_alloc_fw_desc(nic, &nic->fw.ucode_rt.data, | ||
1180 | pieces.data, pieces.data_size)) | ||
1181 | goto err_pci_alloc; | ||
1182 | |||
1183 | /* Initialization instructions and data */ | ||
1184 | if (pieces.init_size && pieces.init_data_size) { | ||
1185 | if (iwl_alloc_fw_desc(nic, | ||
1186 | &nic->fw.ucode_init.code, | ||
1187 | pieces.init, pieces.init_size)) | ||
1188 | goto err_pci_alloc; | ||
1189 | if (iwl_alloc_fw_desc(nic, | ||
1190 | &nic->fw.ucode_init.data, | ||
1191 | pieces.init_data, pieces.init_data_size)) | ||
1192 | goto err_pci_alloc; | ||
1193 | } | ||
1194 | |||
1195 | /* WoWLAN instructions and data */ | ||
1196 | if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { | ||
1197 | if (iwl_alloc_fw_desc(nic, | ||
1198 | &nic->fw.ucode_wowlan.code, | ||
1199 | pieces.wowlan_inst, | ||
1200 | pieces.wowlan_inst_size)) | ||
1201 | goto err_pci_alloc; | ||
1202 | if (iwl_alloc_fw_desc(nic, | ||
1203 | &nic->fw.ucode_wowlan.data, | ||
1204 | pieces.wowlan_data, | ||
1205 | pieces.wowlan_data_size)) | ||
1206 | goto err_pci_alloc; | ||
1207 | } | ||
1208 | |||
1209 | /* Now that we can no longer fail, copy information */ | ||
1210 | |||
1211 | /* | ||
1212 | * The (size - 16) / 12 formula is based on the information recorded | ||
1213 | * for each event, which is of mode 1 (including timestamp) for all | ||
1214 | * new microcodes that include this information. | ||
1215 | */ | ||
1216 | nic->init_evtlog_ptr = pieces.init_evtlog_ptr; | ||
1217 | if (pieces.init_evtlog_size) | ||
1218 | nic->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; | ||
1219 | else | ||
1220 | nic->init_evtlog_size = | ||
1221 | cfg->base_params->max_event_log_size; | ||
1222 | nic->init_errlog_ptr = pieces.init_errlog_ptr; | ||
1223 | nic->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | ||
1224 | if (pieces.inst_evtlog_size) | ||
1225 | nic->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; | ||
1226 | else | ||
1227 | nic->inst_evtlog_size = | ||
1228 | cfg->base_params->max_event_log_size; | ||
1229 | nic->inst_errlog_ptr = pieces.inst_errlog_ptr; | ||
1230 | |||
1231 | /* | ||
1232 | * figure out the offset of chain noise reset and gain commands | ||
1233 | * base on the size of standard phy calibration commands table size | ||
1234 | */ | ||
1235 | if (fw->ucode_capa.standard_phy_calibration_size > | ||
1236 | IWL_MAX_PHY_CALIBRATE_TBL_SIZE) | ||
1237 | fw->ucode_capa.standard_phy_calibration_size = | ||
1238 | IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; | ||
1239 | |||
1240 | /* We have our copies now, allow OS release its copies */ | ||
1241 | release_firmware(ucode_raw); | ||
1242 | complete(&nic->request_firmware_complete); | ||
1243 | |||
1244 | nic->op_mode = iwl_dvm_ops.start(nic->shrd->trans); | ||
1245 | |||
1246 | if (!nic->op_mode) | ||
1247 | goto out_unbind; | ||
1248 | |||
1249 | return; | ||
1250 | |||
1251 | try_again: | ||
1252 | /* try next, if any */ | ||
1253 | release_firmware(ucode_raw); | ||
1254 | if (iwl_request_firmware(nic, false)) | ||
1255 | goto out_unbind; | ||
1256 | return; | ||
1257 | |||
1258 | err_pci_alloc: | ||
1259 | IWL_ERR(nic, "failed to allocate pci memory\n"); | ||
1260 | iwl_dealloc_ucode(nic); | ||
1261 | release_firmware(ucode_raw); | ||
1262 | out_unbind: | ||
1263 | complete(&nic->request_firmware_complete); | ||
1264 | device_release_driver(trans(nic)->dev); | ||
1265 | } | ||
1266 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-wifi.h b/drivers/net/wireless/iwlwifi/iwl-wifi.h index d5cba07a24c8..d157931e1e95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-wifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-wifi.h | |||
@@ -66,8 +66,6 @@ | |||
66 | #include "iwl-shared.h" | 66 | #include "iwl-shared.h" |
67 | #include "iwl-ucode.h" | 67 | #include "iwl-ucode.h" |
68 | 68 | ||
69 | #define UCODE_EXPERIMENTAL_INDEX 100 | ||
70 | |||
71 | /** | 69 | /** |
72 | * struct iwl_nic - nic common data | 70 | * struct iwl_nic - nic common data |
73 | * @fw: the iwl_fw structure | 71 | * @fw: the iwl_fw structure |
@@ -99,9 +97,6 @@ struct iwl_nic { | |||
99 | }; | 97 | }; |
100 | 98 | ||
101 | 99 | ||
102 | int __must_check iwl_request_firmware(struct iwl_nic *nic, bool first); | ||
103 | void iwl_dealloc_ucode(struct iwl_nic *nic); | ||
104 | |||
105 | int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); | 100 | int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type); |
106 | void iwl_send_prio_tbl(struct iwl_trans *trans); | 101 | void iwl_send_prio_tbl(struct iwl_trans *trans); |
107 | int iwl_init_alive_start(struct iwl_trans *trans); | 102 | int iwl_init_alive_start(struct iwl_trans *trans); |