This source file includes following definitions.
- i2400m_bm_cmd_prepare
- i2400m_zrealloc_2x
- i2400m_barker_db_add
- i2400m_barker_db_exit
- i2400m_barker_db_known_barkers
- i2400m_barker_db_init
- i2400m_is_boot_barker
- __i2400m_bm_ack_verify
- i2400m_bm_cmd
- i2400m_download_chunk
- i2400m_dnload_bcf
- i2400m_boot_is_signed
- i2400m_dnload_finalize
- i2400m_bootrom_init
- i2400m_read_mac_addr
- i2400m_dnload_init_nonsigned
- i2400m_dnload_init_signed
- i2400m_dnload_init
- i2400m_fw_hdr_check
- i2400m_fw_check
- i2400m_bcf_hdr_match
- i2400m_bcf_hdr_find
- i2400m_fw_dnload
- i2400m_fw_bootstrap
- i2400m_fw_destroy
- i2400m_fw_get
- i2400m_fw_put
- i2400m_dev_bootstrap
- i2400m_fw_cache
- i2400m_fw_uncache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 #include <linux/firmware.h>
157 #include <linux/sched.h>
158 #include <linux/slab.h>
159 #include <linux/usb.h>
160 #include <linux/export.h>
161 #include "i2400m.h"
162
163
164 #define D_SUBMODULE fw
165 #include "debug-levels.h"
166
167
168 static const __le32 i2400m_ACK_BARKER[4] = {
169 cpu_to_le32(I2400M_ACK_BARKER),
170 cpu_to_le32(I2400M_ACK_BARKER),
171 cpu_to_le32(I2400M_ACK_BARKER),
172 cpu_to_le32(I2400M_ACK_BARKER)
173 };
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *cmd)
189 {
190 if (i2400m_brh_get_use_checksum(cmd)) {
191 int i;
192 u32 checksum = 0;
193 const u32 *checksum_ptr = (void *) cmd->payload;
194 for (i = 0; i < cmd->data_size / 4; i++)
195 checksum += cpu_to_le32(*checksum_ptr++);
196 checksum += cmd->command + cmd->target_addr + cmd->data_size;
197 cmd->block_checksum = cpu_to_le32(checksum);
198 }
199 }
200 EXPORT_SYMBOL_GPL(i2400m_bm_cmd_prepare);
201
202
203
204
205
206
207
208
209
210
211 static struct i2400m_barker_db {
212 __le32 data[4];
213 } *i2400m_barker_db;
214 static size_t i2400m_barker_db_used, i2400m_barker_db_size;
215
216
217 static
218 int i2400m_zrealloc_2x(void **ptr, size_t *_count, size_t el_size,
219 gfp_t gfp_flags)
220 {
221 size_t old_count = *_count,
222 new_count = old_count ? 2 * old_count : 2,
223 old_size = el_size * old_count,
224 new_size = el_size * new_count;
225 void *nptr = krealloc(*ptr, new_size, gfp_flags);
226 if (nptr) {
227
228
229 if (old_size == 0)
230 memset(nptr, 0, new_size);
231 else
232 memset(nptr + old_size, 0, old_size);
233 *_count = new_count;
234 *ptr = nptr;
235 return 0;
236 } else
237 return -ENOMEM;
238 }
239
240
241
242
243
244
245
246
247 static
248 int i2400m_barker_db_add(u32 barker_id)
249 {
250 int result;
251
252 struct i2400m_barker_db *barker;
253 if (i2400m_barker_db_used >= i2400m_barker_db_size) {
254 result = i2400m_zrealloc_2x(
255 (void **) &i2400m_barker_db, &i2400m_barker_db_size,
256 sizeof(i2400m_barker_db[0]), GFP_KERNEL);
257 if (result < 0)
258 return result;
259 }
260 barker = i2400m_barker_db + i2400m_barker_db_used++;
261 barker->data[0] = le32_to_cpu(barker_id);
262 barker->data[1] = le32_to_cpu(barker_id);
263 barker->data[2] = le32_to_cpu(barker_id);
264 barker->data[3] = le32_to_cpu(barker_id);
265 return 0;
266 }
267
268
269 void i2400m_barker_db_exit(void)
270 {
271 kfree(i2400m_barker_db);
272 i2400m_barker_db = NULL;
273 i2400m_barker_db_size = 0;
274 i2400m_barker_db_used = 0;
275 }
276
277
278
279
280
281
282 static
283 int i2400m_barker_db_known_barkers(void)
284 {
285 int result;
286
287 result = i2400m_barker_db_add(I2400M_NBOOT_BARKER);
288 if (result < 0)
289 goto error_add;
290 result = i2400m_barker_db_add(I2400M_SBOOT_BARKER);
291 if (result < 0)
292 goto error_add;
293 result = i2400m_barker_db_add(I2400M_SBOOT_BARKER_6050);
294 if (result < 0)
295 goto error_add;
296 error_add:
297 return result;
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311
312 int i2400m_barker_db_init(const char *_options)
313 {
314 int result;
315 char *options = NULL, *options_orig, *token;
316
317 i2400m_barker_db = NULL;
318 i2400m_barker_db_size = 0;
319 i2400m_barker_db_used = 0;
320
321 result = i2400m_barker_db_known_barkers();
322 if (result < 0)
323 goto error_add;
324
325 if (_options != NULL) {
326 unsigned barker;
327
328 options_orig = kstrdup(_options, GFP_KERNEL);
329 if (options_orig == NULL) {
330 result = -ENOMEM;
331 goto error_parse;
332 }
333 options = options_orig;
334
335 while ((token = strsep(&options, ",")) != NULL) {
336 if (*token == '\0')
337 continue;
338 if (sscanf(token, "%x", &barker) != 1
339 || barker > 0xffffffff) {
340 printk(KERN_ERR "%s: can't recognize "
341 "i2400m.barkers value '%s' as "
342 "a 32-bit number\n",
343 __func__, token);
344 result = -EINVAL;
345 goto error_parse;
346 }
347 if (barker == 0) {
348
349 i2400m_barker_db_exit();
350 continue;
351 }
352 result = i2400m_barker_db_add(barker);
353 if (result < 0)
354 goto error_parse_add;
355 }
356 kfree(options_orig);
357 }
358 return 0;
359
360 error_parse_add:
361 error_parse:
362 kfree(options_orig);
363 error_add:
364 kfree(i2400m_barker_db);
365 return result;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 int i2400m_is_boot_barker(struct i2400m *i2400m,
387 const void *buf, size_t buf_size)
388 {
389 int result;
390 struct device *dev = i2400m_dev(i2400m);
391 struct i2400m_barker_db *barker;
392 int i;
393
394 result = -ENOENT;
395 if (buf_size != sizeof(i2400m_barker_db[i].data))
396 return result;
397
398
399
400 if (i2400m->barker &&
401 !memcmp(buf, i2400m->barker, sizeof(i2400m->barker->data)))
402 return 0;
403
404 for (i = 0; i < i2400m_barker_db_used; i++) {
405 barker = &i2400m_barker_db[i];
406 BUILD_BUG_ON(sizeof(barker->data) != 16);
407 if (memcmp(buf, barker->data, sizeof(barker->data)))
408 continue;
409
410 if (i2400m->barker == NULL) {
411 i2400m->barker = barker;
412 d_printf(1, dev, "boot barker set to #%u/%08x\n",
413 i, le32_to_cpu(barker->data[0]));
414 if (barker->data[0] == le32_to_cpu(I2400M_NBOOT_BARKER))
415 i2400m->sboot = 0;
416 else
417 i2400m->sboot = 1;
418 } else if (i2400m->barker != barker) {
419 dev_err(dev, "HW inconsistency: device "
420 "reports a different boot barker "
421 "than set (from %08x to %08x)\n",
422 le32_to_cpu(i2400m->barker->data[0]),
423 le32_to_cpu(barker->data[0]));
424 result = -EIO;
425 } else
426 d_printf(2, dev, "boot barker confirmed #%u/%08x\n",
427 i, le32_to_cpu(barker->data[0]));
428 result = 0;
429 break;
430 }
431 return result;
432 }
433 EXPORT_SYMBOL_GPL(i2400m_is_boot_barker);
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449 static
450 ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode,
451 struct i2400m_bootrom_header *ack,
452 size_t ack_size, int flags)
453 {
454 ssize_t result = -ENOMEM;
455 struct device *dev = i2400m_dev(i2400m);
456
457 d_fnstart(8, dev, "(i2400m %p opcode %d ack %p size %zu)\n",
458 i2400m, opcode, ack, ack_size);
459 if (ack_size < sizeof(*ack)) {
460 result = -EIO;
461 dev_err(dev, "boot-mode cmd %d: HW BUG? notification didn't "
462 "return enough data (%zu bytes vs %zu expected)\n",
463 opcode, ack_size, sizeof(*ack));
464 goto error_ack_short;
465 }
466 result = i2400m_is_boot_barker(i2400m, ack, ack_size);
467 if (result >= 0) {
468 result = -ERESTARTSYS;
469 d_printf(6, dev, "boot-mode cmd %d: HW boot barker\n", opcode);
470 goto error_reboot;
471 }
472 if (ack_size == sizeof(i2400m_ACK_BARKER)
473 && memcmp(ack, i2400m_ACK_BARKER, sizeof(*ack)) == 0) {
474 result = -EISCONN;
475 d_printf(3, dev, "boot-mode cmd %d: HW reboot ack barker\n",
476 opcode);
477 goto error_reboot_ack;
478 }
479 result = 0;
480 if (flags & I2400M_BM_CMD_RAW)
481 goto out_raw;
482 ack->data_size = le32_to_cpu(ack->data_size);
483 ack->target_addr = le32_to_cpu(ack->target_addr);
484 ack->block_checksum = le32_to_cpu(ack->block_checksum);
485 d_printf(5, dev, "boot-mode cmd %d: notification for opcode %u "
486 "response %u csum %u rr %u da %u\n",
487 opcode, i2400m_brh_get_opcode(ack),
488 i2400m_brh_get_response(ack),
489 i2400m_brh_get_use_checksum(ack),
490 i2400m_brh_get_response_required(ack),
491 i2400m_brh_get_direct_access(ack));
492 result = -EIO;
493 if (i2400m_brh_get_signature(ack) != 0xcbbc) {
494 dev_err(dev, "boot-mode cmd %d: HW BUG? wrong signature "
495 "0x%04x\n", opcode, i2400m_brh_get_signature(ack));
496 goto error_ack_signature;
497 }
498 if (opcode != -1 && opcode != i2400m_brh_get_opcode(ack)) {
499 dev_err(dev, "boot-mode cmd %d: HW BUG? "
500 "received response for opcode %u, expected %u\n",
501 opcode, i2400m_brh_get_opcode(ack), opcode);
502 goto error_ack_opcode;
503 }
504 if (i2400m_brh_get_response(ack) != 0) {
505 dev_err(dev, "boot-mode cmd %d: error; hw response %u\n",
506 opcode, i2400m_brh_get_response(ack));
507 goto error_ack_failed;
508 }
509 if (ack_size < ack->data_size + sizeof(*ack)) {
510 dev_err(dev, "boot-mode cmd %d: SW BUG "
511 "driver provided only %zu bytes for %zu bytes "
512 "of data\n", opcode, ack_size,
513 (size_t) le32_to_cpu(ack->data_size) + sizeof(*ack));
514 goto error_ack_short_buffer;
515 }
516 result = ack_size;
517
518
519
520 error_ack_short_buffer:
521 error_ack_failed:
522 error_ack_opcode:
523 error_ack_signature:
524 out_raw:
525 error_reboot_ack:
526 error_reboot:
527 error_ack_short:
528 d_fnend(8, dev, "(i2400m %p opcode %d ack %p size %zu) = %d\n",
529 i2400m, opcode, ack, ack_size, (int) result);
530 return result;
531 }
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579 static
580 ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
581 const struct i2400m_bootrom_header *cmd, size_t cmd_size,
582 struct i2400m_bootrom_header *ack, size_t ack_size,
583 int flags)
584 {
585 ssize_t result = -ENOMEM, rx_bytes;
586 struct device *dev = i2400m_dev(i2400m);
587 int opcode = cmd == NULL ? -1 : i2400m_brh_get_opcode(cmd);
588
589 d_fnstart(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu)\n",
590 i2400m, cmd, cmd_size, ack, ack_size);
591 BUG_ON(ack_size < sizeof(*ack));
592 BUG_ON(i2400m->boot_mode == 0);
593
594 if (cmd != NULL) {
595 result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags);
596 if (result < 0)
597 goto error_cmd_send;
598 if ((flags & I2400M_BM_CMD_RAW) == 0)
599 d_printf(5, dev,
600 "boot-mode cmd %d csum %u rr %u da %u: "
601 "addr 0x%04x size %u block csum 0x%04x\n",
602 opcode, i2400m_brh_get_use_checksum(cmd),
603 i2400m_brh_get_response_required(cmd),
604 i2400m_brh_get_direct_access(cmd),
605 cmd->target_addr, cmd->data_size,
606 cmd->block_checksum);
607 }
608 result = i2400m->bus_bm_wait_for_ack(i2400m, ack, ack_size);
609 if (result < 0) {
610 dev_err(dev, "boot-mode cmd %d: error waiting for an ack: %d\n",
611 opcode, (int) result);
612 goto error_wait_for_ack;
613 }
614 rx_bytes = result;
615
616
617 result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags);
618 if (result < 0)
619 goto error_bad_ack;
620
621
622
623 result = rx_bytes;
624 error_bad_ack:
625 error_wait_for_ack:
626 error_cmd_send:
627 d_fnend(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu) = %d\n",
628 i2400m, cmd, cmd_size, ack, ack_size, (int) result);
629 return result;
630 }
631
632
633
634
635
636
637
638
639
640
641
642
643 static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
644 size_t __chunk_len, unsigned long addr,
645 unsigned int direct, unsigned int do_csum)
646 {
647 int ret;
648 size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN);
649 struct device *dev = i2400m_dev(i2400m);
650 struct {
651 struct i2400m_bootrom_header cmd;
652 u8 cmd_payload[];
653 } __packed *buf;
654 struct i2400m_bootrom_header ack;
655
656 d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
657 "direct %u do_csum %u)\n", i2400m, chunk, __chunk_len,
658 addr, direct, do_csum);
659 buf = i2400m->bm_cmd_buf;
660 memcpy(buf->cmd_payload, chunk, __chunk_len);
661 memset(buf->cmd_payload + __chunk_len, 0xad, chunk_len - __chunk_len);
662
663 buf->cmd.command = i2400m_brh_command(I2400M_BRH_WRITE,
664 __chunk_len & 0x3 ? 0 : do_csum,
665 __chunk_len & 0xf ? 0 : direct);
666 buf->cmd.target_addr = cpu_to_le32(addr);
667 buf->cmd.data_size = cpu_to_le32(__chunk_len);
668 ret = i2400m_bm_cmd(i2400m, &buf->cmd, sizeof(buf->cmd) + chunk_len,
669 &ack, sizeof(ack), 0);
670 if (ret >= 0)
671 ret = 0;
672 d_fnend(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
673 "direct %u do_csum %u) = %d\n", i2400m, chunk, __chunk_len,
674 addr, direct, do_csum, ret);
675 return ret;
676 }
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697 static
698 ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
699 const struct i2400m_bcf_hdr *bcf, size_t bcf_len)
700 {
701 ssize_t ret;
702 struct device *dev = i2400m_dev(i2400m);
703 size_t offset,
704 data_size,
705 section_size,
706 section = 1;
707 const struct i2400m_bootrom_header *bh;
708 struct i2400m_bootrom_header ack;
709
710 d_fnstart(3, dev, "(i2400m %p bcf %p bcf_len %zu)\n",
711 i2400m, bcf, bcf_len);
712
713
714 offset = le32_to_cpu(bcf->header_len) * sizeof(u32);
715 while (1) {
716 bh = (void *) bcf + offset;
717 data_size = le32_to_cpu(bh->data_size);
718 section_size = ALIGN(sizeof(*bh) + data_size, 4);
719 d_printf(7, dev,
720 "downloading section #%zu (@%zu %zu B) to 0x%08x\n",
721 section, offset, sizeof(*bh) + data_size,
722 le32_to_cpu(bh->target_addr));
723
724
725
726
727
728
729 if (i2400m_brh_get_opcode(bh) == I2400M_BRH_SIGNED_JUMP ||
730 i2400m_brh_get_opcode(bh) == I2400M_BRH_JUMP) {
731 d_printf(5, dev, "jump found @%zu\n", offset);
732 break;
733 }
734 if (offset + section_size > bcf_len) {
735 dev_err(dev, "fw %s: bad section #%zu, "
736 "end (@%zu) beyond EOF (@%zu)\n",
737 i2400m->fw_name, section,
738 offset + section_size, bcf_len);
739 ret = -EINVAL;
740 goto error_section_beyond_eof;
741 }
742 __i2400m_msleep(20);
743 ret = i2400m_bm_cmd(i2400m, bh, section_size,
744 &ack, sizeof(ack), I2400M_BM_CMD_RAW);
745 if (ret < 0) {
746 dev_err(dev, "fw %s: section #%zu (@%zu %zu B) "
747 "failed %d\n", i2400m->fw_name, section,
748 offset, sizeof(*bh) + data_size, (int) ret);
749 goto error_send;
750 }
751 offset += section_size;
752 section++;
753 }
754 ret = offset;
755 error_section_beyond_eof:
756 error_send:
757 d_fnend(3, dev, "(i2400m %p bcf %p bcf_len %zu) = %d\n",
758 i2400m, bcf, bcf_len, (int) ret);
759 return ret;
760 }
761
762
763
764
765
766
767 static
768 unsigned i2400m_boot_is_signed(struct i2400m *i2400m)
769 {
770 return likely(i2400m->sboot);
771 }
772
773
774
775
776
777
778
779
780
781
782
783
784
785 static
786 int i2400m_dnload_finalize(struct i2400m *i2400m,
787 const struct i2400m_bcf_hdr *bcf_hdr,
788 const struct i2400m_bcf_hdr *bcf, size_t offset)
789 {
790 int ret = 0;
791 struct device *dev = i2400m_dev(i2400m);
792 struct i2400m_bootrom_header *cmd, ack;
793 struct {
794 struct i2400m_bootrom_header cmd;
795 u8 cmd_pl[0];
796 } __packed *cmd_buf;
797 size_t signature_block_offset, signature_block_size;
798
799 d_fnstart(3, dev, "offset %zu\n", offset);
800 cmd = (void *) bcf + offset;
801 if (i2400m_boot_is_signed(i2400m) == 0) {
802 struct i2400m_bootrom_header jump_ack;
803 d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n",
804 le32_to_cpu(cmd->target_addr));
805 cmd_buf = i2400m->bm_cmd_buf;
806 memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
807 cmd = &cmd_buf->cmd;
808
809 i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
810 cmd->data_size = 0;
811 ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
812 &jump_ack, sizeof(jump_ack), 0);
813 } else {
814 d_printf(1, dev, "secure boot, jumping to 0x%08x\n",
815 le32_to_cpu(cmd->target_addr));
816 cmd_buf = i2400m->bm_cmd_buf;
817 memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
818 signature_block_offset =
819 sizeof(*bcf_hdr)
820 + le32_to_cpu(bcf_hdr->key_size) * sizeof(u32)
821 + le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32);
822 signature_block_size =
823 le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32);
824 memcpy(cmd_buf->cmd_pl,
825 (void *) bcf_hdr + signature_block_offset,
826 signature_block_size);
827 ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd,
828 sizeof(cmd_buf->cmd) + signature_block_size,
829 &ack, sizeof(ack), I2400M_BM_CMD_RAW);
830 }
831 d_fnend(3, dev, "returning %d\n", ret);
832 return ret;
833 }
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880 int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
881 {
882 int result;
883 struct device *dev = i2400m_dev(i2400m);
884 struct i2400m_bootrom_header *cmd;
885 struct i2400m_bootrom_header ack;
886 int count = i2400m->bus_bm_retries;
887 int ack_timeout_cnt = 1;
888 unsigned i;
889
890 BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data));
891 BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER));
892
893 d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags);
894 result = -ENOMEM;
895 cmd = i2400m->bm_cmd_buf;
896 if (flags & I2400M_BRI_SOFT)
897 goto do_reboot_ack;
898 do_reboot:
899 ack_timeout_cnt = 1;
900 if (--count < 0)
901 goto error_timeout;
902 d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
903 count);
904 if ((flags & I2400M_BRI_NO_REBOOT) == 0)
905 i2400m_reset(i2400m, I2400M_RT_WARM);
906 result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
907 I2400M_BM_CMD_RAW);
908 flags &= ~I2400M_BRI_NO_REBOOT;
909 switch (result) {
910 case -ERESTARTSYS:
911
912
913
914
915
916 d_printf(4, dev, "device reboot: got reboot barker\n");
917 break;
918 case -EISCONN:
919 d_printf(4, dev, "device reboot: got ack barker - whatever\n");
920 goto do_reboot;
921 case -ETIMEDOUT:
922
923
924
925
926
927
928 if (i2400m->barker != NULL) {
929 dev_err(dev, "device boot: reboot barker timed out, "
930 "trying (set) %08x echo/ack\n",
931 le32_to_cpu(i2400m->barker->data[0]));
932 goto do_reboot_ack;
933 }
934 for (i = 0; i < i2400m_barker_db_used; i++) {
935 struct i2400m_barker_db *barker = &i2400m_barker_db[i];
936 memcpy(cmd, barker->data, sizeof(barker->data));
937 result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
938 &ack, sizeof(ack),
939 I2400M_BM_CMD_RAW);
940 if (result == -EISCONN) {
941 dev_warn(dev, "device boot: got ack barker "
942 "after sending echo/ack barker "
943 "#%d/%08x; rebooting j.i.c.\n",
944 i, le32_to_cpu(barker->data[0]));
945 flags &= ~I2400M_BRI_NO_REBOOT;
946 goto do_reboot;
947 }
948 }
949 dev_err(dev, "device boot: tried all the echo/acks, could "
950 "not get device to respond; giving up");
951 result = -ESHUTDOWN;
952 case -EPROTO:
953 case -ESHUTDOWN:
954 case -EINTR:
955 goto error_dev_gone;
956 default:
957 dev_err(dev, "device reboot: error %d while waiting "
958 "for reboot barker - rebooting\n", result);
959 d_dump(1, dev, &ack, result);
960 goto do_reboot;
961 }
962
963
964
965
966 do_reboot_ack:
967 d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count);
968 memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data));
969 result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
970 &ack, sizeof(ack), I2400M_BM_CMD_RAW);
971 switch (result) {
972 case -ERESTARTSYS:
973 d_printf(4, dev, "reboot ack: got reboot barker - retrying\n");
974 if (--count < 0)
975 goto error_timeout;
976 goto do_reboot_ack;
977 case -EISCONN:
978 d_printf(4, dev, "reboot ack: got ack barker - good\n");
979 break;
980 case -ETIMEDOUT:
981 if (ack_timeout_cnt-- < 0) {
982 d_printf(4, dev, "reboot ack timedout: retrying\n");
983 goto do_reboot_ack;
984 } else {
985 dev_err(dev, "reboot ack timedout too long: "
986 "trying reboot\n");
987 goto do_reboot;
988 }
989 break;
990 case -EPROTO:
991 case -ESHUTDOWN:
992 goto error_dev_gone;
993 default:
994 dev_err(dev, "device reboot ack: error %d while waiting for "
995 "reboot ack barker - rebooting\n", result);
996 goto do_reboot;
997 }
998 d_printf(2, dev, "device reboot ack: got ack barker - boot done\n");
999 result = 0;
1000 exit_timeout:
1001 error_dev_gone:
1002 d_fnend(4, dev, "(i2400m %p flags 0x%08x) = %d\n",
1003 i2400m, flags, result);
1004 return result;
1005
1006 error_timeout:
1007 dev_err(dev, "Timed out waiting for reboot ack\n");
1008 result = -ETIMEDOUT;
1009 goto exit_timeout;
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022 int i2400m_read_mac_addr(struct i2400m *i2400m)
1023 {
1024 int result;
1025 struct device *dev = i2400m_dev(i2400m);
1026 struct net_device *net_dev = i2400m->wimax_dev.net_dev;
1027 struct i2400m_bootrom_header *cmd;
1028 struct {
1029 struct i2400m_bootrom_header ack;
1030 u8 ack_pl[16];
1031 } __packed ack_buf;
1032
1033 d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
1034 cmd = i2400m->bm_cmd_buf;
1035 cmd->command = i2400m_brh_command(I2400M_BRH_READ, 0, 1);
1036 cmd->target_addr = cpu_to_le32(0x00203fe8);
1037 cmd->data_size = cpu_to_le32(6);
1038 result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
1039 &ack_buf.ack, sizeof(ack_buf), 0);
1040 if (result < 0) {
1041 dev_err(dev, "BM: read mac addr failed: %d\n", result);
1042 goto error_read_mac;
1043 }
1044 d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl);
1045 if (i2400m->bus_bm_mac_addr_impaired == 1) {
1046 ack_buf.ack_pl[0] = 0x00;
1047 ack_buf.ack_pl[1] = 0x16;
1048 ack_buf.ack_pl[2] = 0xd3;
1049 get_random_bytes(&ack_buf.ack_pl[3], 3);
1050 dev_err(dev, "BM is MAC addr impaired, faking MAC addr to "
1051 "mac addr is %pM\n", ack_buf.ack_pl);
1052 result = 0;
1053 }
1054 net_dev->addr_len = ETH_ALEN;
1055 memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN);
1056 error_read_mac:
1057 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result);
1058 return result;
1059 }
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 static
1070 int i2400m_dnload_init_nonsigned(struct i2400m *i2400m)
1071 {
1072 unsigned i = 0;
1073 int ret = 0;
1074 struct device *dev = i2400m_dev(i2400m);
1075 d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
1076 if (i2400m->bus_bm_pokes_table) {
1077 while (i2400m->bus_bm_pokes_table[i].address) {
1078 ret = i2400m_download_chunk(
1079 i2400m,
1080 &i2400m->bus_bm_pokes_table[i].data,
1081 sizeof(i2400m->bus_bm_pokes_table[i].data),
1082 i2400m->bus_bm_pokes_table[i].address, 1, 1);
1083 if (ret < 0)
1084 break;
1085 i++;
1086 }
1087 }
1088 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
1089 return ret;
1090 }
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 static
1108 int i2400m_dnload_init_signed(struct i2400m *i2400m,
1109 const struct i2400m_bcf_hdr *bcf_hdr)
1110 {
1111 int ret;
1112 struct device *dev = i2400m_dev(i2400m);
1113 struct {
1114 struct i2400m_bootrom_header cmd;
1115 struct i2400m_bcf_hdr cmd_pl;
1116 } __packed *cmd_buf;
1117 struct i2400m_bootrom_header ack;
1118
1119 d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr);
1120 cmd_buf = i2400m->bm_cmd_buf;
1121 cmd_buf->cmd.command =
1122 i2400m_brh_command(I2400M_BRH_HASH_PAYLOAD_ONLY, 0, 0);
1123 cmd_buf->cmd.target_addr = 0;
1124 cmd_buf->cmd.data_size = cpu_to_le32(sizeof(cmd_buf->cmd_pl));
1125 memcpy(&cmd_buf->cmd_pl, bcf_hdr, sizeof(*bcf_hdr));
1126 ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, sizeof(*cmd_buf),
1127 &ack, sizeof(ack), 0);
1128 if (ret >= 0)
1129 ret = 0;
1130 d_fnend(5, dev, "(i2400m %p bcf_hdr %p) = %d\n", i2400m, bcf_hdr, ret);
1131 return ret;
1132 }
1133
1134
1135
1136
1137
1138
1139
1140
1141 static
1142 int i2400m_dnload_init(struct i2400m *i2400m,
1143 const struct i2400m_bcf_hdr *bcf_hdr)
1144 {
1145 int result;
1146 struct device *dev = i2400m_dev(i2400m);
1147
1148 if (i2400m_boot_is_signed(i2400m)) {
1149 d_printf(1, dev, "signed boot\n");
1150 result = i2400m_dnload_init_signed(i2400m, bcf_hdr);
1151 if (result == -ERESTARTSYS)
1152 return result;
1153 if (result < 0)
1154 dev_err(dev, "firmware %s: signed boot download "
1155 "initialization failed: %d\n",
1156 i2400m->fw_name, result);
1157 } else {
1158
1159 d_printf(1, dev, "non-signed boot\n");
1160 result = i2400m_dnload_init_nonsigned(i2400m);
1161 if (result == -ERESTARTSYS)
1162 return result;
1163 if (result < 0)
1164 dev_err(dev, "firmware %s: non-signed download "
1165 "initialization failed: %d\n",
1166 i2400m->fw_name, result);
1167 }
1168 return result;
1169 }
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183 static
1184 int i2400m_fw_hdr_check(struct i2400m *i2400m,
1185 const struct i2400m_bcf_hdr *bcf_hdr,
1186 size_t index, size_t offset)
1187 {
1188 struct device *dev = i2400m_dev(i2400m);
1189
1190 unsigned module_type, header_len, major_version, minor_version,
1191 module_id, module_vendor, date, size;
1192
1193 module_type = le32_to_cpu(bcf_hdr->module_type);
1194 header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len);
1195 major_version = (le32_to_cpu(bcf_hdr->header_version) & 0xffff0000)
1196 >> 16;
1197 minor_version = le32_to_cpu(bcf_hdr->header_version) & 0x0000ffff;
1198 module_id = le32_to_cpu(bcf_hdr->module_id);
1199 module_vendor = le32_to_cpu(bcf_hdr->module_vendor);
1200 date = le32_to_cpu(bcf_hdr->date);
1201 size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
1202
1203 d_printf(1, dev, "firmware %s #%zd@%08zx: BCF header "
1204 "type:vendor:id 0x%x:%x:%x v%u.%u (%u/%u B) built %08x\n",
1205 i2400m->fw_name, index, offset,
1206 module_type, module_vendor, module_id,
1207 major_version, minor_version, header_len, size, date);
1208
1209
1210 if (major_version != 1) {
1211 dev_err(dev, "firmware %s #%zd@%08zx: major header version "
1212 "v%u.%u not supported\n",
1213 i2400m->fw_name, index, offset,
1214 major_version, minor_version);
1215 return -EBADF;
1216 }
1217
1218 if (module_type != 6) {
1219 dev_err(dev, "firmware %s #%zd@%08zx: unexpected module "
1220 "type 0x%x; aborting\n",
1221 i2400m->fw_name, index, offset,
1222 module_type);
1223 return -EBADF;
1224 }
1225
1226 if (module_vendor != 0x8086) {
1227 dev_err(dev, "firmware %s #%zd@%08zx: unexpected module "
1228 "vendor 0x%x; aborting\n",
1229 i2400m->fw_name, index, offset, module_vendor);
1230 return -EBADF;
1231 }
1232
1233 if (date < 0x20080300)
1234 dev_warn(dev, "firmware %s #%zd@%08zx: build date %08x "
1235 "too old; unsupported\n",
1236 i2400m->fw_name, index, offset, date);
1237 return 0;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252 static
1253 int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size)
1254 {
1255 int result;
1256 struct device *dev = i2400m_dev(i2400m);
1257 size_t headers = 0;
1258 const struct i2400m_bcf_hdr *bcf_hdr;
1259 const void *itr, *next, *top;
1260 size_t slots = 0, used_slots = 0;
1261
1262 for (itr = bcf, top = itr + bcf_size;
1263 itr < top;
1264 headers++, itr = next) {
1265 size_t leftover, offset, header_len, size;
1266
1267 leftover = top - itr;
1268 offset = itr - bcf;
1269 if (leftover <= sizeof(*bcf_hdr)) {
1270 dev_err(dev, "firmware %s: %zu B left at @%zx, "
1271 "not enough for BCF header\n",
1272 i2400m->fw_name, leftover, offset);
1273 break;
1274 }
1275 bcf_hdr = itr;
1276
1277
1278 header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len);
1279 size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
1280 if (headers == 0)
1281 next = itr + size;
1282 else
1283 next = itr + header_len;
1284
1285 result = i2400m_fw_hdr_check(i2400m, bcf_hdr, headers, offset);
1286 if (result < 0)
1287 continue;
1288 if (used_slots + 1 >= slots) {
1289
1290
1291
1292 result = i2400m_zrealloc_2x(
1293 (void **) &i2400m->fw_hdrs, &slots,
1294 sizeof(i2400m->fw_hdrs[0]),
1295 GFP_KERNEL);
1296 if (result < 0)
1297 goto error_zrealloc;
1298 }
1299 i2400m->fw_hdrs[used_slots] = bcf_hdr;
1300 used_slots++;
1301 }
1302 if (headers == 0) {
1303 dev_err(dev, "firmware %s: no usable headers found\n",
1304 i2400m->fw_name);
1305 result = -EBADF;
1306 } else
1307 result = 0;
1308 error_zrealloc:
1309 return result;
1310 }
1311
1312
1313
1314
1315
1316
1317
1318
1319 static
1320 unsigned i2400m_bcf_hdr_match(struct i2400m *i2400m,
1321 const struct i2400m_bcf_hdr *bcf_hdr)
1322 {
1323 u32 barker = le32_to_cpu(i2400m->barker->data[0])
1324 & 0x7fffffff;
1325 u32 module_id = le32_to_cpu(bcf_hdr->module_id)
1326 & 0x7fffffff;
1327
1328
1329 if (barker == I2400M_SBOOT_BARKER && module_id == 0)
1330 return 1;
1331 if (module_id == barker)
1332 return 1;
1333 return 0;
1334 }
1335
1336 static
1337 const struct i2400m_bcf_hdr *i2400m_bcf_hdr_find(struct i2400m *i2400m)
1338 {
1339 struct device *dev = i2400m_dev(i2400m);
1340 const struct i2400m_bcf_hdr **bcf_itr, *bcf_hdr;
1341 unsigned i = 0;
1342 u32 barker = le32_to_cpu(i2400m->barker->data[0]);
1343
1344 d_printf(2, dev, "finding BCF header for barker %08x\n", barker);
1345 if (barker == I2400M_NBOOT_BARKER) {
1346 bcf_hdr = i2400m->fw_hdrs[0];
1347 d_printf(1, dev, "using BCF header #%u/%08x for non-signed "
1348 "barker\n", 0, le32_to_cpu(bcf_hdr->module_id));
1349 return bcf_hdr;
1350 }
1351 for (bcf_itr = i2400m->fw_hdrs; *bcf_itr != NULL; bcf_itr++, i++) {
1352 bcf_hdr = *bcf_itr;
1353 if (i2400m_bcf_hdr_match(i2400m, bcf_hdr)) {
1354 d_printf(1, dev, "hit on BCF hdr #%u/%08x\n",
1355 i, le32_to_cpu(bcf_hdr->module_id));
1356 return bcf_hdr;
1357 } else
1358 d_printf(1, dev, "miss on BCF hdr #%u/%08x\n",
1359 i, le32_to_cpu(bcf_hdr->module_id));
1360 }
1361 dev_err(dev, "cannot find a matching BCF header for barker %08x\n",
1362 barker);
1363 return NULL;
1364 }
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381 static
1382 int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
1383 size_t fw_size, enum i2400m_bri flags)
1384 {
1385 int ret = 0;
1386 struct device *dev = i2400m_dev(i2400m);
1387 int count = i2400m->bus_bm_retries;
1388 const struct i2400m_bcf_hdr *bcf_hdr;
1389 size_t bcf_size;
1390
1391 d_fnstart(5, dev, "(i2400m %p bcf %p fw size %zu)\n",
1392 i2400m, bcf, fw_size);
1393 i2400m->boot_mode = 1;
1394 wmb();
1395 hw_reboot:
1396 if (count-- == 0) {
1397 ret = -ERESTARTSYS;
1398 dev_err(dev, "device rebooted too many times, aborting\n");
1399 goto error_too_many_reboots;
1400 }
1401 if (flags & I2400M_BRI_MAC_REINIT) {
1402 ret = i2400m_bootrom_init(i2400m, flags);
1403 if (ret < 0) {
1404 dev_err(dev, "bootrom init failed: %d\n", ret);
1405 goto error_bootrom_init;
1406 }
1407 }
1408 flags |= I2400M_BRI_MAC_REINIT;
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419 ret = -EBADF;
1420 bcf_hdr = i2400m_bcf_hdr_find(i2400m);
1421 if (bcf_hdr == NULL)
1422 goto error_bcf_hdr_find;
1423
1424 ret = i2400m_dnload_init(i2400m, bcf_hdr);
1425 if (ret == -ERESTARTSYS)
1426 goto error_dev_rebooted;
1427 if (ret < 0)
1428 goto error_dnload_init;
1429
1430
1431
1432
1433
1434
1435 bcf_size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
1436 ret = i2400m_dnload_bcf(i2400m, bcf, bcf_size);
1437 if (ret == -ERESTARTSYS)
1438 goto error_dev_rebooted;
1439 if (ret < 0) {
1440 dev_err(dev, "fw %s: download failed: %d\n",
1441 i2400m->fw_name, ret);
1442 goto error_dnload_bcf;
1443 }
1444
1445 ret = i2400m_dnload_finalize(i2400m, bcf_hdr, bcf, ret);
1446 if (ret == -ERESTARTSYS)
1447 goto error_dev_rebooted;
1448 if (ret < 0) {
1449 dev_err(dev, "fw %s: "
1450 "download finalization failed: %d\n",
1451 i2400m->fw_name, ret);
1452 goto error_dnload_finalize;
1453 }
1454
1455 d_printf(2, dev, "fw %s successfully uploaded\n",
1456 i2400m->fw_name);
1457 i2400m->boot_mode = 0;
1458 wmb();
1459 error_dnload_finalize:
1460 error_dnload_bcf:
1461 error_dnload_init:
1462 error_bcf_hdr_find:
1463 error_bootrom_init:
1464 error_too_many_reboots:
1465 d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n",
1466 i2400m, bcf, fw_size, ret);
1467 return ret;
1468
1469 error_dev_rebooted:
1470 dev_err(dev, "device rebooted, %d tries left\n", count);
1471
1472 flags |= I2400M_BRI_SOFT;
1473 goto hw_reboot;
1474 }
1475
1476 static
1477 int i2400m_fw_bootstrap(struct i2400m *i2400m, const struct firmware *fw,
1478 enum i2400m_bri flags)
1479 {
1480 int ret;
1481 struct device *dev = i2400m_dev(i2400m);
1482 const struct i2400m_bcf_hdr *bcf;
1483
1484 d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
1485 bcf = (void *) fw->data;
1486 ret = i2400m_fw_check(i2400m, bcf, fw->size);
1487 if (ret >= 0)
1488 ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags);
1489 if (ret < 0)
1490 dev_err(dev, "%s: cannot use: %d, skipping\n",
1491 i2400m->fw_name, ret);
1492 kfree(i2400m->fw_hdrs);
1493 i2400m->fw_hdrs = NULL;
1494 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
1495 return ret;
1496 }
1497
1498
1499
1500 struct i2400m_fw {
1501 struct kref kref;
1502 const struct firmware *fw;
1503 };
1504
1505
1506 static
1507 void i2400m_fw_destroy(struct kref *kref)
1508 {
1509 struct i2400m_fw *i2400m_fw =
1510 container_of(kref, struct i2400m_fw, kref);
1511 release_firmware(i2400m_fw->fw);
1512 kfree(i2400m_fw);
1513 }
1514
1515
1516 static
1517 struct i2400m_fw *i2400m_fw_get(struct i2400m_fw *i2400m_fw)
1518 {
1519 if (i2400m_fw != NULL && i2400m_fw != (void *) ~0)
1520 kref_get(&i2400m_fw->kref);
1521 return i2400m_fw;
1522 }
1523
1524
1525 static
1526 void i2400m_fw_put(struct i2400m_fw *i2400m_fw)
1527 {
1528 kref_put(&i2400m_fw->kref, i2400m_fw_destroy);
1529 }
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547 int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags)
1548 {
1549 int ret, itr;
1550 struct device *dev = i2400m_dev(i2400m);
1551 struct i2400m_fw *i2400m_fw;
1552 const struct firmware *fw;
1553 const char *fw_name;
1554
1555 d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
1556
1557 ret = -ENODEV;
1558 spin_lock(&i2400m->rx_lock);
1559 i2400m_fw = i2400m_fw_get(i2400m->fw_cached);
1560 spin_unlock(&i2400m->rx_lock);
1561 if (i2400m_fw == (void *) ~0) {
1562 dev_err(dev, "can't load firmware now!");
1563 goto out;
1564 } else if (i2400m_fw != NULL) {
1565 dev_info(dev, "firmware %s: loading from cache\n",
1566 i2400m->fw_name);
1567 ret = i2400m_fw_bootstrap(i2400m, i2400m_fw->fw, flags);
1568 i2400m_fw_put(i2400m_fw);
1569 goto out;
1570 }
1571
1572
1573 for (itr = 0, ret = -ENOENT; ; itr++) {
1574 fw_name = i2400m->bus_fw_names[itr];
1575 if (fw_name == NULL) {
1576 dev_err(dev, "Could not find a usable firmware image\n");
1577 break;
1578 }
1579 d_printf(1, dev, "trying firmware %s (%d)\n", fw_name, itr);
1580 ret = request_firmware(&fw, fw_name, dev);
1581 if (ret < 0) {
1582 dev_err(dev, "fw %s: cannot load file: %d\n",
1583 fw_name, ret);
1584 continue;
1585 }
1586 i2400m->fw_name = fw_name;
1587 ret = i2400m_fw_bootstrap(i2400m, fw, flags);
1588 release_firmware(fw);
1589 if (ret >= 0)
1590 break;
1591 i2400m->fw_name = NULL;
1592 }
1593 out:
1594 d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
1595 return ret;
1596 }
1597 EXPORT_SYMBOL_GPL(i2400m_dev_bootstrap);
1598
1599
1600 void i2400m_fw_cache(struct i2400m *i2400m)
1601 {
1602 int result;
1603 struct i2400m_fw *i2400m_fw;
1604 struct device *dev = i2400m_dev(i2400m);
1605
1606
1607 spin_lock(&i2400m->rx_lock);
1608 i2400m_fw = i2400m->fw_cached;
1609 spin_unlock(&i2400m->rx_lock);
1610 if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) {
1611 i2400m_fw_put(i2400m_fw);
1612 WARN(1, "%s:%u: still cached fw still present?\n",
1613 __func__, __LINE__);
1614 }
1615
1616 if (i2400m->fw_name == NULL) {
1617 dev_err(dev, "firmware n/a: can't cache\n");
1618 i2400m_fw = (void *) ~0;
1619 goto out;
1620 }
1621
1622 i2400m_fw = kzalloc(sizeof(*i2400m_fw), GFP_ATOMIC);
1623 if (i2400m_fw == NULL)
1624 goto out;
1625 kref_init(&i2400m_fw->kref);
1626 result = request_firmware(&i2400m_fw->fw, i2400m->fw_name, dev);
1627 if (result < 0) {
1628 dev_err(dev, "firmware %s: failed to cache: %d\n",
1629 i2400m->fw_name, result);
1630 kfree(i2400m_fw);
1631 i2400m_fw = (void *) ~0;
1632 } else
1633 dev_info(dev, "firmware %s: cached\n", i2400m->fw_name);
1634 out:
1635 spin_lock(&i2400m->rx_lock);
1636 i2400m->fw_cached = i2400m_fw;
1637 spin_unlock(&i2400m->rx_lock);
1638 }
1639
1640
1641 void i2400m_fw_uncache(struct i2400m *i2400m)
1642 {
1643 struct i2400m_fw *i2400m_fw;
1644
1645 spin_lock(&i2400m->rx_lock);
1646 i2400m_fw = i2400m->fw_cached;
1647 i2400m->fw_cached = NULL;
1648 spin_unlock(&i2400m->rx_lock);
1649
1650 if (i2400m_fw != NULL && i2400m_fw != (void *) ~0)
1651 i2400m_fw_put(i2400m_fw);
1652 }
1653