]>
Commit | Line | Data |
---|---|---|
5c58edc6 EG |
1 | /****************************************************************************** |
2 | * | |
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | * redistributing this file, you may do so under either license. | |
5 | * | |
6 | * GPL LICENSE SUMMARY | |
7 | * | |
8 | * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of version 2 of the GNU General Public License as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | |
22 | * USA | |
23 | * | |
24 | * The full GNU General Public License is included in this distribution | |
25 | * in the file called LICENSE.GPL. | |
26 | * | |
27 | * Contact Information: | |
28 | * Intel Linux Wireless <ilw@linux.intel.com> | |
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
30 | * | |
31 | * BSD LICENSE | |
32 | * | |
33 | * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. | |
34 | * All rights reserved. | |
35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | |
39 | * | |
40 | * * Redistributions of source code must retain the above copyright | |
41 | * notice, this list of conditions and the following disclaimer. | |
42 | * * Redistributions in binary form must reproduce the above copyright | |
43 | * notice, this list of conditions and the following disclaimer in | |
44 | * the documentation and/or other materials provided with the | |
45 | * distribution. | |
46 | * * Neither the name Intel Corporation nor the names of its | |
47 | * contributors may be used to endorse or promote products derived | |
48 | * from this software without specific prior written permission. | |
49 | * | |
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
61 | * | |
62 | *****************************************************************************/ | |
63 | #include <linux/completion.h> | |
15854ef9 JB |
64 | #include <linux/dma-mapping.h> |
65 | #include <linux/firmware.h> | |
66 | #include <linux/module.h> | |
5c58edc6 EG |
67 | |
68 | #include "iwl-drv.h" | |
69 | #include "iwl-trans.h" | |
15854ef9 | 70 | #include "iwl-shared.h" |
d0f76d68 | 71 | #include "iwl-op-mode.h" |
5c58edc6 | 72 | |
0692fe41 JB |
73 | /* private includes */ |
74 | #include "iwl-ucode.h" | |
75 | ||
965974a6 JB |
76 | /** |
77 | * struct iwl_drv - drv common data | |
78 | * @fw: the iwl_fw structure | |
79 | * @shrd: pointer to common shared structure | |
80 | * @op_mode: the running op_mode | |
81 | * @fw_index: firmware revision to try loading | |
82 | * @firmware_name: composite filename of ucode file to load | |
83 | * @request_firmware_complete: the firmware has been obtained from user space | |
84 | */ | |
85 | struct iwl_drv { | |
86 | struct iwl_fw fw; | |
87 | ||
88 | struct iwl_shared *shrd; | |
89 | struct iwl_op_mode *op_mode; | |
90 | ||
91 | int fw_index; /* firmware we're trying to load */ | |
92 | char firmware_name[25]; /* name of firmware file to load */ | |
93 | ||
94 | struct completion request_firmware_complete; | |
95 | }; | |
96 | ||
97 | ||
98 | ||
99 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) | |
15854ef9 JB |
100 | { |
101 | if (desc->v_addr) | |
965974a6 | 102 | dma_free_coherent(trans(drv)->dev, desc->len, |
15854ef9 JB |
103 | desc->v_addr, desc->p_addr); |
104 | desc->v_addr = NULL; | |
105 | desc->len = 0; | |
106 | } | |
107 | ||
965974a6 | 108 | static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img) |
15854ef9 | 109 | { |
965974a6 JB |
110 | iwl_free_fw_desc(drv, &img->code); |
111 | iwl_free_fw_desc(drv, &img->data); | |
15854ef9 JB |
112 | } |
113 | ||
965974a6 | 114 | static void iwl_dealloc_ucode(struct iwl_drv *drv) |
15854ef9 | 115 | { |
965974a6 JB |
116 | iwl_free_fw_img(drv, &drv->fw.ucode_rt); |
117 | iwl_free_fw_img(drv, &drv->fw.ucode_init); | |
118 | iwl_free_fw_img(drv, &drv->fw.ucode_wowlan); | |
15854ef9 JB |
119 | } |
120 | ||
965974a6 | 121 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, |
15854ef9 JB |
122 | const void *data, size_t len) |
123 | { | |
124 | if (!len) { | |
125 | desc->v_addr = NULL; | |
126 | return -EINVAL; | |
127 | } | |
128 | ||
965974a6 | 129 | desc->v_addr = dma_alloc_coherent(trans(drv)->dev, len, |
15854ef9 JB |
130 | &desc->p_addr, GFP_KERNEL); |
131 | if (!desc->v_addr) | |
132 | return -ENOMEM; | |
133 | ||
134 | desc->len = len; | |
135 | memcpy(desc->v_addr, data, len); | |
136 | return 0; | |
137 | } | |
138 | ||
139 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | |
140 | ||
141 | #define UCODE_EXPERIMENTAL_INDEX 100 | |
142 | #define UCODE_EXPERIMENTAL_TAG "exp" | |
143 | ||
965974a6 | 144 | static int iwl_request_firmware(struct iwl_drv *drv, bool first) |
15854ef9 | 145 | { |
965974a6 | 146 | const struct iwl_cfg *cfg = cfg(drv); |
15854ef9 JB |
147 | const char *name_pre = cfg->fw_name_pre; |
148 | char tag[8]; | |
149 | ||
150 | if (first) { | |
151 | #ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE | |
965974a6 | 152 | drv->fw_index = UCODE_EXPERIMENTAL_INDEX; |
15854ef9 | 153 | strcpy(tag, UCODE_EXPERIMENTAL_TAG); |
965974a6 | 154 | } else if (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) { |
15854ef9 | 155 | #endif |
965974a6 JB |
156 | drv->fw_index = cfg->ucode_api_max; |
157 | sprintf(tag, "%d", drv->fw_index); | |
15854ef9 | 158 | } else { |
965974a6 JB |
159 | drv->fw_index--; |
160 | sprintf(tag, "%d", drv->fw_index); | |
15854ef9 JB |
161 | } |
162 | ||
965974a6 JB |
163 | if (drv->fw_index < cfg->ucode_api_min) { |
164 | IWL_ERR(drv, "no suitable firmware found!\n"); | |
15854ef9 JB |
165 | return -ENOENT; |
166 | } | |
167 | ||
965974a6 | 168 | sprintf(drv->firmware_name, "%s%s%s", name_pre, tag, ".ucode"); |
15854ef9 | 169 | |
965974a6 JB |
170 | IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n", |
171 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) | |
15854ef9 | 172 | ? "EXPERIMENTAL " : "", |
965974a6 | 173 | drv->firmware_name); |
15854ef9 | 174 | |
965974a6 JB |
175 | return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, |
176 | trans(drv)->dev, | |
177 | GFP_KERNEL, drv, iwl_ucode_callback); | |
15854ef9 JB |
178 | } |
179 | ||
180 | struct iwlagn_firmware_pieces { | |
181 | const void *inst, *data, *init, *init_data, *wowlan_inst, *wowlan_data; | |
182 | size_t inst_size, data_size, init_size, init_data_size, | |
183 | wowlan_inst_size, wowlan_data_size; | |
184 | ||
185 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | |
186 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | |
187 | }; | |
188 | ||
965974a6 | 189 | static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, |
15854ef9 JB |
190 | const struct firmware *ucode_raw, |
191 | struct iwlagn_firmware_pieces *pieces) | |
192 | { | |
193 | struct iwl_ucode_header *ucode = (void *)ucode_raw->data; | |
194 | u32 api_ver, hdr_size, build; | |
195 | char buildstr[25]; | |
196 | const u8 *src; | |
197 | ||
965974a6 JB |
198 | drv->fw.ucode_ver = le32_to_cpu(ucode->ver); |
199 | api_ver = IWL_UCODE_API(drv->fw.ucode_ver); | |
15854ef9 JB |
200 | |
201 | switch (api_ver) { | |
202 | default: | |
203 | hdr_size = 28; | |
204 | if (ucode_raw->size < hdr_size) { | |
965974a6 | 205 | IWL_ERR(drv, "File size too small!\n"); |
15854ef9 JB |
206 | return -EINVAL; |
207 | } | |
208 | build = le32_to_cpu(ucode->u.v2.build); | |
209 | pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); | |
210 | pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); | |
211 | pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); | |
212 | pieces->init_data_size = | |
213 | le32_to_cpu(ucode->u.v2.init_data_size); | |
214 | src = ucode->u.v2.data; | |
215 | break; | |
216 | case 0: | |
217 | case 1: | |
218 | case 2: | |
219 | hdr_size = 24; | |
220 | if (ucode_raw->size < hdr_size) { | |
965974a6 | 221 | IWL_ERR(drv, "File size too small!\n"); |
15854ef9 JB |
222 | return -EINVAL; |
223 | } | |
224 | build = 0; | |
225 | pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size); | |
226 | pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); | |
227 | pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); | |
228 | pieces->init_data_size = | |
229 | le32_to_cpu(ucode->u.v1.init_data_size); | |
230 | src = ucode->u.v1.data; | |
231 | break; | |
232 | } | |
233 | ||
234 | if (build) | |
235 | sprintf(buildstr, " build %u%s", build, | |
965974a6 | 236 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) |
15854ef9 JB |
237 | ? " (EXP)" : ""); |
238 | else | |
239 | buildstr[0] = '\0'; | |
240 | ||
965974a6 JB |
241 | snprintf(drv->fw.fw_version, |
242 | sizeof(drv->fw.fw_version), | |
15854ef9 | 243 | "%u.%u.%u.%u%s", |
965974a6 JB |
244 | IWL_UCODE_MAJOR(drv->fw.ucode_ver), |
245 | IWL_UCODE_MINOR(drv->fw.ucode_ver), | |
246 | IWL_UCODE_API(drv->fw.ucode_ver), | |
247 | IWL_UCODE_SERIAL(drv->fw.ucode_ver), | |
15854ef9 JB |
248 | buildstr); |
249 | ||
250 | /* Verify size of file vs. image size info in file's header */ | |
251 | if (ucode_raw->size != hdr_size + pieces->inst_size + | |
252 | pieces->data_size + pieces->init_size + | |
253 | pieces->init_data_size) { | |
254 | ||
965974a6 | 255 | IWL_ERR(drv, |
15854ef9 JB |
256 | "uCode file size %d does not match expected size\n", |
257 | (int)ucode_raw->size); | |
258 | return -EINVAL; | |
259 | } | |
260 | ||
261 | pieces->inst = src; | |
262 | src += pieces->inst_size; | |
263 | pieces->data = src; | |
264 | src += pieces->data_size; | |
265 | pieces->init = src; | |
266 | src += pieces->init_size; | |
267 | pieces->init_data = src; | |
268 | src += pieces->init_data_size; | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
965974a6 | 273 | static int iwl_parse_tlv_firmware(struct iwl_drv *drv, |
15854ef9 JB |
274 | const struct firmware *ucode_raw, |
275 | struct iwlagn_firmware_pieces *pieces, | |
276 | struct iwl_ucode_capabilities *capa) | |
277 | { | |
278 | struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; | |
279 | struct iwl_ucode_tlv *tlv; | |
280 | size_t len = ucode_raw->size; | |
281 | const u8 *data; | |
282 | int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; | |
283 | int tmp; | |
284 | u64 alternatives; | |
285 | u32 tlv_len; | |
286 | enum iwl_ucode_tlv_type tlv_type; | |
287 | const u8 *tlv_data; | |
288 | char buildstr[25]; | |
289 | u32 build; | |
290 | ||
291 | if (len < sizeof(*ucode)) { | |
965974a6 | 292 | IWL_ERR(drv, "uCode has invalid length: %zd\n", len); |
15854ef9 JB |
293 | return -EINVAL; |
294 | } | |
295 | ||
296 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { | |
965974a6 | 297 | IWL_ERR(drv, "invalid uCode magic: 0X%x\n", |
15854ef9 JB |
298 | le32_to_cpu(ucode->magic)); |
299 | return -EINVAL; | |
300 | } | |
301 | ||
302 | /* | |
303 | * Check which alternatives are present, and "downgrade" | |
304 | * when the chosen alternative is not present, warning | |
305 | * the user when that happens. Some files may not have | |
306 | * any alternatives, so don't warn in that case. | |
307 | */ | |
308 | alternatives = le64_to_cpu(ucode->alternatives); | |
309 | tmp = wanted_alternative; | |
310 | if (wanted_alternative > 63) | |
311 | wanted_alternative = 63; | |
312 | while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) | |
313 | wanted_alternative--; | |
314 | if (wanted_alternative && wanted_alternative != tmp) | |
965974a6 | 315 | IWL_WARN(drv, |
15854ef9 JB |
316 | "uCode alternative %d not available, choosing %d\n", |
317 | tmp, wanted_alternative); | |
318 | ||
965974a6 | 319 | drv->fw.ucode_ver = le32_to_cpu(ucode->ver); |
15854ef9 JB |
320 | build = le32_to_cpu(ucode->build); |
321 | ||
322 | if (build) | |
323 | sprintf(buildstr, " build %u%s", build, | |
965974a6 | 324 | (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) |
15854ef9 JB |
325 | ? " (EXP)" : ""); |
326 | else | |
327 | buildstr[0] = '\0'; | |
328 | ||
965974a6 JB |
329 | snprintf(drv->fw.fw_version, |
330 | sizeof(drv->fw.fw_version), | |
15854ef9 | 331 | "%u.%u.%u.%u%s", |
965974a6 JB |
332 | IWL_UCODE_MAJOR(drv->fw.ucode_ver), |
333 | IWL_UCODE_MINOR(drv->fw.ucode_ver), | |
334 | IWL_UCODE_API(drv->fw.ucode_ver), | |
335 | IWL_UCODE_SERIAL(drv->fw.ucode_ver), | |
15854ef9 JB |
336 | buildstr); |
337 | ||
338 | data = ucode->data; | |
339 | ||
340 | len -= sizeof(*ucode); | |
341 | ||
342 | while (len >= sizeof(*tlv)) { | |
343 | u16 tlv_alt; | |
344 | ||
345 | len -= sizeof(*tlv); | |
346 | tlv = (void *)data; | |
347 | ||
348 | tlv_len = le32_to_cpu(tlv->length); | |
349 | tlv_type = le16_to_cpu(tlv->type); | |
350 | tlv_alt = le16_to_cpu(tlv->alternative); | |
351 | tlv_data = tlv->data; | |
352 | ||
353 | if (len < tlv_len) { | |
965974a6 | 354 | IWL_ERR(drv, "invalid TLV len: %zd/%u\n", |
15854ef9 JB |
355 | len, tlv_len); |
356 | return -EINVAL; | |
357 | } | |
358 | len -= ALIGN(tlv_len, 4); | |
359 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); | |
360 | ||
361 | /* | |
362 | * Alternative 0 is always valid. | |
363 | * | |
364 | * Skip alternative TLVs that are not selected. | |
365 | */ | |
366 | if (tlv_alt != 0 && tlv_alt != wanted_alternative) | |
367 | continue; | |
368 | ||
369 | switch (tlv_type) { | |
370 | case IWL_UCODE_TLV_INST: | |
371 | pieces->inst = tlv_data; | |
372 | pieces->inst_size = tlv_len; | |
373 | break; | |
374 | case IWL_UCODE_TLV_DATA: | |
375 | pieces->data = tlv_data; | |
376 | pieces->data_size = tlv_len; | |
377 | break; | |
378 | case IWL_UCODE_TLV_INIT: | |
379 | pieces->init = tlv_data; | |
380 | pieces->init_size = tlv_len; | |
381 | break; | |
382 | case IWL_UCODE_TLV_INIT_DATA: | |
383 | pieces->init_data = tlv_data; | |
384 | pieces->init_data_size = tlv_len; | |
385 | break; | |
386 | case IWL_UCODE_TLV_BOOT: | |
965974a6 | 387 | IWL_ERR(drv, "Found unexpected BOOT ucode\n"); |
15854ef9 JB |
388 | break; |
389 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | |
390 | if (tlv_len != sizeof(u32)) | |
391 | goto invalid_tlv_len; | |
392 | capa->max_probe_length = | |
393 | le32_to_cpup((__le32 *)tlv_data); | |
394 | break; | |
395 | case IWL_UCODE_TLV_PAN: | |
396 | if (tlv_len) | |
397 | goto invalid_tlv_len; | |
398 | capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; | |
399 | break; | |
400 | case IWL_UCODE_TLV_FLAGS: | |
401 | /* must be at least one u32 */ | |
402 | if (tlv_len < sizeof(u32)) | |
403 | goto invalid_tlv_len; | |
404 | /* and a proper number of u32s */ | |
405 | if (tlv_len % sizeof(u32)) | |
406 | goto invalid_tlv_len; | |
407 | /* | |
408 | * This driver only reads the first u32 as | |
409 | * right now no more features are defined, | |
410 | * if that changes then either the driver | |
411 | * will not work with the new firmware, or | |
412 | * it'll not take advantage of new features. | |
413 | */ | |
414 | capa->flags = le32_to_cpup((__le32 *)tlv_data); | |
415 | break; | |
416 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | |
417 | if (tlv_len != sizeof(u32)) | |
418 | goto invalid_tlv_len; | |
419 | pieces->init_evtlog_ptr = | |
420 | le32_to_cpup((__le32 *)tlv_data); | |
421 | break; | |
422 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: | |
423 | if (tlv_len != sizeof(u32)) | |
424 | goto invalid_tlv_len; | |
425 | pieces->init_evtlog_size = | |
426 | le32_to_cpup((__le32 *)tlv_data); | |
427 | break; | |
428 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: | |
429 | if (tlv_len != sizeof(u32)) | |
430 | goto invalid_tlv_len; | |
431 | pieces->init_errlog_ptr = | |
432 | le32_to_cpup((__le32 *)tlv_data); | |
433 | break; | |
434 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: | |
435 | if (tlv_len != sizeof(u32)) | |
436 | goto invalid_tlv_len; | |
437 | pieces->inst_evtlog_ptr = | |
438 | le32_to_cpup((__le32 *)tlv_data); | |
439 | break; | |
440 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: | |
441 | if (tlv_len != sizeof(u32)) | |
442 | goto invalid_tlv_len; | |
443 | pieces->inst_evtlog_size = | |
444 | le32_to_cpup((__le32 *)tlv_data); | |
445 | break; | |
446 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: | |
447 | if (tlv_len != sizeof(u32)) | |
448 | goto invalid_tlv_len; | |
449 | pieces->inst_errlog_ptr = | |
450 | le32_to_cpup((__le32 *)tlv_data); | |
451 | break; | |
452 | case IWL_UCODE_TLV_ENHANCE_SENS_TBL: | |
453 | if (tlv_len) | |
454 | goto invalid_tlv_len; | |
965974a6 | 455 | drv->fw.enhance_sensitivity_table = true; |
15854ef9 JB |
456 | break; |
457 | case IWL_UCODE_TLV_WOWLAN_INST: | |
458 | pieces->wowlan_inst = tlv_data; | |
459 | pieces->wowlan_inst_size = tlv_len; | |
460 | break; | |
461 | case IWL_UCODE_TLV_WOWLAN_DATA: | |
462 | pieces->wowlan_data = tlv_data; | |
463 | pieces->wowlan_data_size = tlv_len; | |
464 | break; | |
465 | case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE: | |
466 | if (tlv_len != sizeof(u32)) | |
467 | goto invalid_tlv_len; | |
468 | capa->standard_phy_calibration_size = | |
469 | le32_to_cpup((__le32 *)tlv_data); | |
470 | break; | |
471 | default: | |
965974a6 | 472 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
15854ef9 JB |
473 | break; |
474 | } | |
475 | } | |
476 | ||
477 | if (len) { | |
965974a6 JB |
478 | IWL_ERR(drv, "invalid TLV after parsing: %zd\n", len); |
479 | iwl_print_hex_dump(drv, IWL_DL_FW, (u8 *)data, len); | |
15854ef9 JB |
480 | return -EINVAL; |
481 | } | |
482 | ||
483 | return 0; | |
484 | ||
485 | invalid_tlv_len: | |
965974a6 JB |
486 | IWL_ERR(drv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len); |
487 | iwl_print_hex_dump(drv, IWL_DL_FW, tlv_data, tlv_len); | |
15854ef9 JB |
488 | |
489 | return -EINVAL; | |
490 | } | |
491 | ||
492 | /** | |
493 | * iwl_ucode_callback - callback when firmware was loaded | |
494 | * | |
495 | * If loaded successfully, copies the firmware into buffers | |
496 | * for the card to fetch (via DMA). | |
497 | */ | |
498 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |
499 | { | |
965974a6 JB |
500 | struct iwl_drv *drv = context; |
501 | const struct iwl_cfg *cfg = cfg(drv); | |
502 | struct iwl_fw *fw = &drv->fw; | |
15854ef9 JB |
503 | struct iwl_ucode_header *ucode; |
504 | int err; | |
505 | struct iwlagn_firmware_pieces pieces; | |
506 | const unsigned int api_max = cfg->ucode_api_max; | |
507 | unsigned int api_ok = cfg->ucode_api_ok; | |
508 | const unsigned int api_min = cfg->ucode_api_min; | |
509 | u32 api_ver; | |
510 | ||
511 | fw->ucode_capa.max_probe_length = 200; | |
512 | fw->ucode_capa.standard_phy_calibration_size = | |
513 | IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; | |
514 | ||
515 | if (!api_ok) | |
516 | api_ok = api_max; | |
517 | ||
518 | memset(&pieces, 0, sizeof(pieces)); | |
519 | ||
520 | if (!ucode_raw) { | |
965974a6 JB |
521 | if (drv->fw_index <= api_ok) |
522 | IWL_ERR(drv, | |
15854ef9 | 523 | "request for firmware file '%s' failed.\n", |
965974a6 | 524 | drv->firmware_name); |
15854ef9 JB |
525 | goto try_again; |
526 | } | |
527 | ||
965974a6 JB |
528 | IWL_DEBUG_INFO(drv, "Loaded firmware file '%s' (%zd bytes).\n", |
529 | drv->firmware_name, ucode_raw->size); | |
15854ef9 JB |
530 | |
531 | /* Make sure that we got at least the API version number */ | |
532 | if (ucode_raw->size < 4) { | |
965974a6 | 533 | IWL_ERR(drv, "File size way too small!\n"); |
15854ef9 JB |
534 | goto try_again; |
535 | } | |
536 | ||
537 | /* Data from ucode file: header followed by uCode images */ | |
538 | ucode = (struct iwl_ucode_header *)ucode_raw->data; | |
539 | ||
540 | if (ucode->ver) | |
965974a6 | 541 | err = iwl_parse_v1_v2_firmware(drv, ucode_raw, &pieces); |
15854ef9 | 542 | else |
965974a6 | 543 | err = iwl_parse_tlv_firmware(drv, ucode_raw, &pieces, |
15854ef9 JB |
544 | &fw->ucode_capa); |
545 | ||
546 | if (err) | |
547 | goto try_again; | |
548 | ||
965974a6 | 549 | api_ver = IWL_UCODE_API(drv->fw.ucode_ver); |
15854ef9 JB |
550 | |
551 | /* | |
552 | * api_ver should match the api version forming part of the | |
553 | * firmware filename ... but we don't check for that and only rely | |
554 | * on the API version read from firmware header from here on forward | |
555 | */ | |
556 | /* no api version check required for experimental uCode */ | |
965974a6 | 557 | if (drv->fw_index != UCODE_EXPERIMENTAL_INDEX) { |
15854ef9 | 558 | if (api_ver < api_min || api_ver > api_max) { |
965974a6 | 559 | IWL_ERR(drv, |
15854ef9 JB |
560 | "Driver unable to support your firmware API. " |
561 | "Driver supports v%u, firmware is v%u.\n", | |
562 | api_max, api_ver); | |
563 | goto try_again; | |
564 | } | |
565 | ||
566 | if (api_ver < api_ok) { | |
567 | if (api_ok != api_max) | |
965974a6 | 568 | IWL_ERR(drv, "Firmware has old API version, " |
15854ef9 JB |
569 | "expected v%u through v%u, got v%u.\n", |
570 | api_ok, api_max, api_ver); | |
571 | else | |
965974a6 | 572 | IWL_ERR(drv, "Firmware has old API version, " |
15854ef9 JB |
573 | "expected v%u, got v%u.\n", |
574 | api_max, api_ver); | |
965974a6 | 575 | IWL_ERR(drv, "New firmware can be obtained from " |
15854ef9 JB |
576 | "http://www.intellinuxwireless.org/.\n"); |
577 | } | |
578 | } | |
579 | ||
965974a6 | 580 | IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version); |
15854ef9 JB |
581 | |
582 | /* | |
583 | * For any of the failures below (before allocating pci memory) | |
584 | * we will try to load a version with a smaller API -- maybe the | |
585 | * user just got a corrupted version of the latest API. | |
586 | */ | |
587 | ||
965974a6 JB |
588 | IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n", |
589 | drv->fw.ucode_ver); | |
590 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n", | |
15854ef9 | 591 | pieces.inst_size); |
965974a6 | 592 | IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n", |
15854ef9 | 593 | pieces.data_size); |
965974a6 | 594 | IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n", |
15854ef9 | 595 | pieces.init_size); |
965974a6 | 596 | IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n", |
15854ef9 JB |
597 | pieces.init_data_size); |
598 | ||
599 | /* Verify that uCode images will fit in card's SRAM */ | |
600 | if (pieces.inst_size > cfg->max_inst_size) { | |
965974a6 | 601 | IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", |
15854ef9 JB |
602 | pieces.inst_size); |
603 | goto try_again; | |
604 | } | |
605 | ||
606 | if (pieces.data_size > cfg->max_data_size) { | |
965974a6 | 607 | IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", |
15854ef9 JB |
608 | pieces.data_size); |
609 | goto try_again; | |
610 | } | |
611 | ||
612 | if (pieces.init_size > cfg->max_inst_size) { | |
965974a6 | 613 | IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", |
15854ef9 JB |
614 | pieces.init_size); |
615 | goto try_again; | |
616 | } | |
617 | ||
618 | if (pieces.init_data_size > cfg->max_data_size) { | |
965974a6 | 619 | IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", |
15854ef9 JB |
620 | pieces.init_data_size); |
621 | goto try_again; | |
622 | } | |
623 | ||
624 | /* Allocate ucode buffers for card's bus-master loading ... */ | |
625 | ||
626 | /* Runtime instructions and 2 copies of data: | |
627 | * 1) unmodified from disk | |
628 | * 2) backup cache for save/restore during power-downs */ | |
965974a6 | 629 | if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.code, |
15854ef9 JB |
630 | pieces.inst, pieces.inst_size)) |
631 | goto err_pci_alloc; | |
965974a6 | 632 | if (iwl_alloc_fw_desc(drv, &drv->fw.ucode_rt.data, |
15854ef9 JB |
633 | pieces.data, pieces.data_size)) |
634 | goto err_pci_alloc; | |
635 | ||
636 | /* Initialization instructions and data */ | |
637 | if (pieces.init_size && pieces.init_data_size) { | |
965974a6 JB |
638 | if (iwl_alloc_fw_desc(drv, |
639 | &drv->fw.ucode_init.code, | |
15854ef9 JB |
640 | pieces.init, pieces.init_size)) |
641 | goto err_pci_alloc; | |
965974a6 JB |
642 | if (iwl_alloc_fw_desc(drv, |
643 | &drv->fw.ucode_init.data, | |
15854ef9 JB |
644 | pieces.init_data, pieces.init_data_size)) |
645 | goto err_pci_alloc; | |
646 | } | |
647 | ||
648 | /* WoWLAN instructions and data */ | |
649 | if (pieces.wowlan_inst_size && pieces.wowlan_data_size) { | |
965974a6 JB |
650 | if (iwl_alloc_fw_desc(drv, |
651 | &drv->fw.ucode_wowlan.code, | |
15854ef9 JB |
652 | pieces.wowlan_inst, |
653 | pieces.wowlan_inst_size)) | |
654 | goto err_pci_alloc; | |
965974a6 JB |
655 | if (iwl_alloc_fw_desc(drv, |
656 | &drv->fw.ucode_wowlan.data, | |
15854ef9 JB |
657 | pieces.wowlan_data, |
658 | pieces.wowlan_data_size)) | |
659 | goto err_pci_alloc; | |
660 | } | |
661 | ||
662 | /* Now that we can no longer fail, copy information */ | |
663 | ||
664 | /* | |
665 | * The (size - 16) / 12 formula is based on the information recorded | |
666 | * for each event, which is of mode 1 (including timestamp) for all | |
667 | * new microcodes that include this information. | |
668 | */ | |
0692fe41 | 669 | fw->init_evtlog_ptr = pieces.init_evtlog_ptr; |
15854ef9 | 670 | if (pieces.init_evtlog_size) |
0692fe41 | 671 | fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; |
15854ef9 | 672 | else |
0692fe41 | 673 | fw->init_evtlog_size = |
15854ef9 | 674 | cfg->base_params->max_event_log_size; |
0692fe41 JB |
675 | fw->init_errlog_ptr = pieces.init_errlog_ptr; |
676 | fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | |
15854ef9 | 677 | if (pieces.inst_evtlog_size) |
0692fe41 | 678 | fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; |
15854ef9 | 679 | else |
0692fe41 | 680 | fw->inst_evtlog_size = |
15854ef9 | 681 | cfg->base_params->max_event_log_size; |
0692fe41 | 682 | fw->inst_errlog_ptr = pieces.inst_errlog_ptr; |
15854ef9 JB |
683 | |
684 | /* | |
685 | * figure out the offset of chain noise reset and gain commands | |
686 | * base on the size of standard phy calibration commands table size | |
687 | */ | |
688 | if (fw->ucode_capa.standard_phy_calibration_size > | |
689 | IWL_MAX_PHY_CALIBRATE_TBL_SIZE) | |
690 | fw->ucode_capa.standard_phy_calibration_size = | |
691 | IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE; | |
692 | ||
693 | /* We have our copies now, allow OS release its copies */ | |
694 | release_firmware(ucode_raw); | |
965974a6 | 695 | complete(&drv->request_firmware_complete); |
15854ef9 | 696 | |
965974a6 | 697 | drv->op_mode = iwl_dvm_ops.start(drv->shrd->trans, &drv->fw); |
15854ef9 | 698 | |
965974a6 | 699 | if (!drv->op_mode) |
15854ef9 JB |
700 | goto out_unbind; |
701 | ||
702 | return; | |
703 | ||
704 | try_again: | |
705 | /* try next, if any */ | |
706 | release_firmware(ucode_raw); | |
965974a6 | 707 | if (iwl_request_firmware(drv, false)) |
15854ef9 JB |
708 | goto out_unbind; |
709 | return; | |
710 | ||
711 | err_pci_alloc: | |
965974a6 JB |
712 | IWL_ERR(drv, "failed to allocate pci memory\n"); |
713 | iwl_dealloc_ucode(drv); | |
15854ef9 JB |
714 | release_firmware(ucode_raw); |
715 | out_unbind: | |
965974a6 JB |
716 | complete(&drv->request_firmware_complete); |
717 | device_release_driver(trans(drv)->dev); | |
15854ef9 JB |
718 | } |
719 | ||
5c58edc6 | 720 | int iwl_drv_start(struct iwl_shared *shrd, |
706c4ff6 | 721 | struct iwl_trans *trans, const struct iwl_cfg *cfg) |
5c58edc6 | 722 | { |
965974a6 | 723 | struct iwl_drv *drv; |
5c58edc6 EG |
724 | int ret; |
725 | ||
726 | shrd->cfg = cfg; | |
727 | ||
965974a6 JB |
728 | drv = kzalloc(sizeof(*drv), GFP_KERNEL); |
729 | if (!drv) { | |
730 | dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_drv"); | |
5c58edc6 EG |
731 | return -ENOMEM; |
732 | } | |
965974a6 JB |
733 | drv->shrd = shrd; |
734 | shrd->drv = drv; | |
5c58edc6 | 735 | |
965974a6 | 736 | init_completion(&drv->request_firmware_complete); |
5c58edc6 | 737 | |
965974a6 | 738 | ret = iwl_request_firmware(drv, true); |
5c58edc6 EG |
739 | |
740 | if (ret) { | |
741 | dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw"); | |
965974a6 JB |
742 | kfree(drv); |
743 | shrd->drv = NULL; | |
5c58edc6 EG |
744 | } |
745 | ||
746 | return ret; | |
747 | } | |
748 | ||
07590f08 EG |
749 | void iwl_drv_stop(struct iwl_shared *shrd) |
750 | { | |
965974a6 | 751 | struct iwl_drv *drv = shrd->drv; |
0692fe41 | 752 | |
965974a6 | 753 | wait_for_completion(&drv->request_firmware_complete); |
2e7eb117 | 754 | |
d0f76d68 | 755 | /* op_mode can be NULL if its start failed */ |
965974a6 JB |
756 | if (drv->op_mode) |
757 | iwl_op_mode_stop(drv->op_mode); | |
07590f08 | 758 | |
965974a6 | 759 | iwl_dealloc_ucode(drv); |
7db5b989 | 760 | |
965974a6 JB |
761 | kfree(drv); |
762 | shrd->drv = NULL; | |
07590f08 | 763 | } |