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#include <linux/ihex.h>
52#include <linux/slab.h>
53
54
55
56
57#define PRISM2_USB_FWFILE "prism2_ru.fw"
58MODULE_FIRMWARE(PRISM2_USB_FWFILE);
59
60#define S3DATA_MAX 5000
61#define S3PLUG_MAX 200
62#define S3CRC_MAX 200
63#define S3INFO_MAX 50
64
65#define S3ADDR_PLUG (0xff000000UL)
66#define S3ADDR_CRC (0xff100000UL)
67#define S3ADDR_INFO (0xff200000UL)
68#define S3ADDR_START (0xff400000UL)
69
70#define CHUNKS_MAX 100
71
72#define WRITESIZE_MAX 4096
73
74
75
76
77struct s3datarec {
78 u32 len;
79 u32 addr;
80 u8 checksum;
81 u8 *data;
82};
83
84struct s3plugrec {
85 u32 itemcode;
86 u32 addr;
87 u32 len;
88};
89
90struct s3crcrec {
91 u32 addr;
92 u32 len;
93 unsigned int dowrite;
94};
95
96struct s3inforec {
97 u16 len;
98 u16 type;
99 union {
100 struct hfa384x_compident version;
101 struct hfa384x_caplevel compat;
102 u16 buildseq;
103 struct hfa384x_compident platform;
104 } info;
105};
106
107struct pda {
108 u8 buf[HFA384x_PDA_LEN_MAX];
109 struct hfa384x_pdrec *rec[HFA384x_PDA_RECS_MAX];
110 unsigned int nrec;
111};
112
113struct imgchunk {
114 u32 addr;
115 u32 len;
116 u16 crc;
117 u8 *data;
118};
119
120
121
122
123
124
125
126
127static unsigned int ns3data;
128static struct s3datarec *s3data;
129
130
131static unsigned int ns3plug;
132static struct s3plugrec s3plug[S3PLUG_MAX];
133
134
135static unsigned int ns3crc;
136static struct s3crcrec s3crc[S3CRC_MAX];
137
138
139static unsigned int ns3info;
140static struct s3inforec s3info[S3INFO_MAX];
141
142
143static u32 startaddr;
144
145
146static unsigned int nfchunks;
147static struct imgchunk fchunk[CHUNKS_MAX];
148
149
150
151
152
153
154
155static struct pda pda;
156static struct hfa384x_compident nicid;
157static struct hfa384x_caplevel rfid;
158static struct hfa384x_caplevel macid;
159static struct hfa384x_caplevel priid;
160
161
162
163
164static int prism2_fwapply(const struct ihex_binrec *rfptr,
165 struct wlandevice *wlandev);
166
167static int read_fwfile(const struct ihex_binrec *rfptr);
168
169static int mkimage(struct imgchunk *clist, unsigned int *ccnt);
170
171static int read_cardpda(struct pda *pda, struct wlandevice *wlandev);
172
173static int mkpdrlist(struct pda *pda);
174
175static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
176 struct s3plugrec *s3plug, unsigned int ns3plug,
177 struct pda *pda);
178
179static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
180 struct s3crcrec *s3crc, unsigned int ns3crc);
181
182static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
183 unsigned int nfchunks);
184
185static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks);
186
187static void free_srecs(void);
188
189static int validate_identity(void);
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208static int prism2_fwtry(struct usb_device *udev, struct wlandevice *wlandev)
209{
210 const struct firmware *fw_entry = NULL;
211
212 netdev_info(wlandev->netdev, "prism2_usb: Checking for firmware %s\n",
213 PRISM2_USB_FWFILE);
214 if (request_ihex_firmware(&fw_entry,
215 PRISM2_USB_FWFILE, &udev->dev) != 0) {
216 netdev_info(wlandev->netdev,
217 "prism2_usb: Firmware not available, but not essential\n");
218 netdev_info(wlandev->netdev,
219 "prism2_usb: can continue to use card anyway.\n");
220 return 1;
221 }
222
223 netdev_info(wlandev->netdev,
224 "prism2_usb: %s will be processed, size %zu\n",
225 PRISM2_USB_FWFILE, fw_entry->size);
226 prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
227
228 release_firmware(fw_entry);
229 return 0;
230}
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246static int prism2_fwapply(const struct ihex_binrec *rfptr,
247 struct wlandevice *wlandev)
248{
249 signed int result = 0;
250 struct p80211msg_dot11req_mibget getmsg;
251 struct p80211itemd *item;
252 u32 *data;
253
254
255 ns3data = 0;
256 s3data = kcalloc(S3DATA_MAX, sizeof(*s3data), GFP_KERNEL);
257 if (!s3data) {
258 result = -ENOMEM;
259 goto out;
260 }
261
262 ns3plug = 0;
263 memset(s3plug, 0, sizeof(s3plug));
264 ns3crc = 0;
265 memset(s3crc, 0, sizeof(s3crc));
266 ns3info = 0;
267 memset(s3info, 0, sizeof(s3info));
268 startaddr = 0;
269
270 nfchunks = 0;
271 memset(fchunk, 0, sizeof(fchunk));
272 memset(&nicid, 0, sizeof(nicid));
273 memset(&rfid, 0, sizeof(rfid));
274 memset(&macid, 0, sizeof(macid));
275 memset(&priid, 0, sizeof(priid));
276
277
278 memset(&pda, 0, sizeof(pda));
279 pda.rec[0] = (struct hfa384x_pdrec *)pda.buf;
280 pda.rec[0]->len = cpu_to_le16(2);
281 pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
282 pda.nrec = 1;
283
284
285
286 prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
287
288
289 if (read_cardpda(&pda, wlandev)) {
290 netdev_err(wlandev->netdev, "load_cardpda failed, exiting.\n");
291 result = 1;
292 goto out;
293 }
294
295
296 memset(&getmsg, 0, sizeof(getmsg));
297 getmsg.msgcode = DIDMSG_DOT11REQ_MIBGET;
298 getmsg.msglen = sizeof(getmsg);
299 strscpy(getmsg.devname, wlandev->name, sizeof(getmsg.devname));
300
301 getmsg.mibattribute.did = DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE;
302 getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
303 getmsg.resultcode.did = DIDMSG_DOT11REQ_MIBGET_RESULTCODE;
304 getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
305
306 item = (struct p80211itemd *)getmsg.mibattribute.data;
307 item->did = DIDMIB_P2_NIC_PRISUPRANGE;
308 item->status = P80211ENUM_msgitem_status_no_value;
309
310 data = (u32 *)item->data;
311
312
313 prism2mgmt_mibset_mibget(wlandev, &getmsg);
314 if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
315 netdev_err(wlandev->netdev, "Couldn't fetch PRI-SUP info\n");
316
317
318 priid.role = *data++;
319 priid.id = *data++;
320 priid.variant = *data++;
321 priid.bottom = *data++;
322 priid.top = *data++;
323
324
325 result = read_fwfile(rfptr);
326 if (result) {
327 netdev_err(wlandev->netdev,
328 "Failed to read the data exiting.\n");
329 goto out;
330 }
331
332 result = validate_identity();
333 if (result) {
334 netdev_err(wlandev->netdev, "Incompatible firmware image.\n");
335 goto out;
336 }
337
338 if (startaddr == 0x00000000) {
339 netdev_err(wlandev->netdev,
340 "Can't RAM download a Flash image!\n");
341 result = 1;
342 goto out;
343 }
344
345
346 result = mkimage(fchunk, &nfchunks);
347 if (result) {
348 netdev_err(wlandev->netdev, "Failed to make image chunk.\n");
349 goto free_chunks;
350 }
351
352
353 result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
354 if (result) {
355 netdev_err(wlandev->netdev, "Failed to plug data.\n");
356 goto free_chunks;
357 }
358
359
360 result = crcimage(fchunk, nfchunks, s3crc, ns3crc);
361 if (result) {
362 netdev_err(wlandev->netdev, "Failed to insert all CRCs\n");
363 goto free_chunks;
364 }
365
366
367 result = writeimage(wlandev, fchunk, nfchunks);
368 if (result) {
369 netdev_err(wlandev->netdev, "Failed to ramwrite image data.\n");
370 goto free_chunks;
371 }
372
373 netdev_info(wlandev->netdev, "prism2_usb: firmware loading finished.\n");
374
375free_chunks:
376
377 free_chunks(fchunk, &nfchunks);
378 free_srecs();
379
380out:
381 return result;
382}
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
403 struct s3crcrec *s3crc, unsigned int ns3crc)
404{
405 int result = 0;
406 int i;
407 int c;
408 u32 crcstart;
409 u32 cstart = 0;
410 u32 cend;
411 u8 *dest;
412 u32 chunkoff;
413
414 for (i = 0; i < ns3crc; i++) {
415 if (!s3crc[i].dowrite)
416 continue;
417 crcstart = s3crc[i].addr;
418
419 for (c = 0; c < nfchunks; c++) {
420 cstart = fchunk[c].addr;
421 cend = fchunk[c].addr + fchunk[c].len;
422
423
424
425
426
427
428
429
430 if (crcstart - 2 >= cstart && crcstart < cend)
431 break;
432 }
433 if (c >= nfchunks) {
434 pr_err("Failed to find chunk for crcrec[%d], addr=0x%06x len=%d , aborting crc.\n",
435 i, s3crc[i].addr, s3crc[i].len);
436 return 1;
437 }
438
439
440 pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
441 chunkoff = crcstart - cstart - 2;
442 dest = fchunk[c].data + chunkoff;
443 *dest = 0xde;
444 *(dest + 1) = 0xc0;
445 }
446 return result;
447}
448
449
450
451
452
453
454
455
456
457
458
459
460
461static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
462{
463 int i;
464
465 for (i = 0; i < *nfchunks; i++)
466 kfree(fchunk[i].data);
467
468 *nfchunks = 0;
469 memset(fchunk, 0, sizeof(*fchunk));
470}
471
472
473
474
475
476
477
478
479
480
481
482
483
484static void free_srecs(void)
485{
486 ns3data = 0;
487 kfree(s3data);
488 ns3plug = 0;
489 memset(s3plug, 0, sizeof(s3plug));
490 ns3crc = 0;
491 memset(s3crc, 0, sizeof(s3crc));
492 ns3info = 0;
493 memset(s3info, 0, sizeof(s3info));
494 startaddr = 0;
495}
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512static int mkimage(struct imgchunk *clist, unsigned int *ccnt)
513{
514 int result = 0;
515 int i;
516 int j;
517 int currchunk = 0;
518 u32 nextaddr = 0;
519 u32 s3start;
520 u32 s3end;
521 u32 cstart = 0;
522 u32 cend;
523 u32 coffset;
524
525
526 *ccnt = 0;
527
528
529 for (i = 0; i < ns3data; i++) {
530 if (s3data[i].addr == nextaddr) {
531
532 clist[currchunk].len += s3data[i].len;
533 nextaddr += s3data[i].len;
534 } else {
535
536 (*ccnt)++;
537 currchunk = *ccnt - 1;
538 clist[currchunk].addr = s3data[i].addr;
539 clist[currchunk].len = s3data[i].len;
540 nextaddr = s3data[i].addr + s3data[i].len;
541
542
543 for (j = 0; j < ns3crc; j++) {
544 if (s3crc[j].dowrite &&
545 s3crc[j].addr == clist[currchunk].addr) {
546 clist[currchunk].addr -= 2;
547 clist[currchunk].len += 2;
548 }
549 }
550 }
551 }
552
553
554
555
556
557 for (i = 0; i < *ccnt; i++) {
558 clist[i].data = kzalloc(clist[i].len, GFP_KERNEL);
559 if (!clist[i].data)
560 return 1;
561
562 pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
563 i, clist[i].addr, clist[i].len);
564 }
565
566
567 for (i = 0; i < ns3data; i++) {
568 s3start = s3data[i].addr;
569 s3end = s3start + s3data[i].len - 1;
570 for (j = 0; j < *ccnt; j++) {
571 cstart = clist[j].addr;
572 cend = cstart + clist[j].len - 1;
573 if (s3start >= cstart && s3end <= cend)
574 break;
575 }
576 if (((unsigned int)j) >= (*ccnt)) {
577 pr_err("s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
578 s3start, s3data[i].len);
579 return 1;
580 }
581 coffset = s3start - cstart;
582 memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
583 }
584
585 return result;
586}
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603static int mkpdrlist(struct pda *pda)
604{
605 __le16 *pda16 = (__le16 *)pda->buf;
606 int curroff;
607
608 pda->nrec = 0;
609 curroff = 0;
610 while (curroff < (HFA384x_PDA_LEN_MAX / 2 - 1) &&
611 le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
612 pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
613
614 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
615 HFA384x_PDR_NICID) {
616 memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
617 sizeof(nicid));
618 le16_to_cpus(&nicid.id);
619 le16_to_cpus(&nicid.variant);
620 le16_to_cpus(&nicid.major);
621 le16_to_cpus(&nicid.minor);
622 }
623 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
624 HFA384x_PDR_MFISUPRANGE) {
625 memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
626 sizeof(rfid));
627 le16_to_cpus(&rfid.id);
628 le16_to_cpus(&rfid.variant);
629 le16_to_cpus(&rfid.bottom);
630 le16_to_cpus(&rfid.top);
631 }
632 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
633 HFA384x_PDR_CFISUPRANGE) {
634 memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
635 sizeof(macid));
636 le16_to_cpus(&macid.id);
637 le16_to_cpus(&macid.variant);
638 le16_to_cpus(&macid.bottom);
639 le16_to_cpus(&macid.top);
640 }
641
642 (pda->nrec)++;
643 curroff += le16_to_cpu(pda16[curroff]) + 1;
644 }
645 if (curroff >= (HFA384x_PDA_LEN_MAX / 2 - 1)) {
646 pr_err("no end record found or invalid lengths in PDR data, exiting. %x %d\n",
647 curroff, pda->nrec);
648 return 1;
649 }
650 pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
651 (pda->nrec)++;
652 return 0;
653}
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
674 struct s3plugrec *s3plug, unsigned int ns3plug,
675 struct pda *pda)
676{
677 int result = 0;
678 int i;
679 int j;
680 int c;
681 u32 pstart;
682 u32 pend;
683 u32 cstart = 0;
684 u32 cend;
685 u32 chunkoff;
686 u8 *dest;
687
688
689 for (i = 0; i < ns3plug; i++) {
690 pstart = s3plug[i].addr;
691 pend = s3plug[i].addr + s3plug[i].len;
692
693 if (s3plug[i].itemcode != 0xffffffffUL) {
694 for (j = 0; j < pda->nrec; j++) {
695 if (s3plug[i].itemcode ==
696 le16_to_cpu(pda->rec[j]->code))
697 break;
698 }
699 } else {
700 j = -1;
701 }
702 if (j >= pda->nrec && j != -1) {
703 pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n",
704 s3plug[i].itemcode);
705 continue;
706
707
708
709
710
711
712
713
714 }
715
716
717 if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
718 pr_err("error: Plug vs. PDR len mismatch for plugrec 0x%04x, abort plugging.\n",
719 s3plug[i].itemcode);
720 result = 1;
721 continue;
722 }
723
724
725
726
727
728 for (c = 0; c < nfchunks; c++) {
729 cstart = fchunk[c].addr;
730 cend = fchunk[c].addr + fchunk[c].len;
731 if (pstart >= cstart && pend <= cend)
732 break;
733 }
734 if (c >= nfchunks) {
735 pr_err("error: Failed to find image chunk for plugrec 0x%04x.\n",
736 s3plug[i].itemcode);
737 result = 1;
738 continue;
739 }
740
741
742 chunkoff = pstart - cstart;
743 dest = fchunk[c].data + chunkoff;
744 pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, cnum=%d coff=0x%06x\n",
745 s3plug[i].itemcode, pstart, s3plug[i].len,
746 c, chunkoff);
747
748 if (j == -1) {
749 memset(dest, 0, s3plug[i].len);
750 strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
751 } else {
752 memcpy(dest, &pda->rec[j]->data, s3plug[i].len);
753 }
754 }
755 return result;
756}
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777static int read_cardpda(struct pda *pda, struct wlandevice *wlandev)
778{
779 int result = 0;
780 struct p80211msg_p2req_readpda *msg;
781
782 msg = kzalloc(sizeof(*msg), GFP_KERNEL);
783 if (!msg)
784 return -ENOMEM;
785
786
787 msg->msgcode = DIDMSG_P2REQ_READPDA;
788 msg->msglen = sizeof(msg);
789 strscpy(msg->devname, wlandev->name, sizeof(msg->devname));
790 msg->pda.did = DIDMSG_P2REQ_READPDA_PDA;
791 msg->pda.len = HFA384x_PDA_LEN_MAX;
792 msg->pda.status = P80211ENUM_msgitem_status_no_value;
793 msg->resultcode.did = DIDMSG_P2REQ_READPDA_RESULTCODE;
794 msg->resultcode.len = sizeof(u32);
795 msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
796
797 if (prism2mgmt_readpda(wlandev, msg) != 0) {
798
799 result = -1;
800 } else if (msg->resultcode.data == P80211ENUM_resultcode_success) {
801 memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX);
802 result = mkpdrlist(pda);
803 } else {
804
805 result = -1;
806 }
807
808 kfree(msg);
809 return result;
810}
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
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
873static int read_fwfile(const struct ihex_binrec *record)
874{
875 int i;
876 int rcnt = 0;
877 u16 *tmpinfo;
878 u16 *ptr16;
879 u32 *ptr32, len, addr;
880
881 pr_debug("Reading fw file ...\n");
882
883 while (record) {
884 rcnt++;
885
886 len = be16_to_cpu(record->len);
887 addr = be32_to_cpu(record->addr);
888
889
890 ptr32 = (u32 *)record->data;
891 ptr16 = (u16 *)record->data;
892
893
894 switch (addr) {
895 case S3ADDR_START:
896 startaddr = *ptr32;
897 pr_debug(" S7 start addr, record=%d addr=0x%08x\n",
898 rcnt,
899 startaddr);
900 break;
901 case S3ADDR_PLUG:
902 s3plug[ns3plug].itemcode = *ptr32;
903 s3plug[ns3plug].addr = *(ptr32 + 1);
904 s3plug[ns3plug].len = *(ptr32 + 2);
905
906 pr_debug(" S3 plugrec, record=%d itemcode=0x%08x addr=0x%08x len=%d\n",
907 rcnt,
908 s3plug[ns3plug].itemcode,
909 s3plug[ns3plug].addr,
910 s3plug[ns3plug].len);
911
912 ns3plug++;
913 if (ns3plug == S3PLUG_MAX) {
914 pr_err("S3 plugrec limit reached - aborting\n");
915 return 1;
916 }
917 break;
918 case S3ADDR_CRC:
919 s3crc[ns3crc].addr = *ptr32;
920 s3crc[ns3crc].len = *(ptr32 + 1);
921 s3crc[ns3crc].dowrite = *(ptr32 + 2);
922
923 pr_debug(" S3 crcrec, record=%d addr=0x%08x len=%d write=0x%08x\n",
924 rcnt,
925 s3crc[ns3crc].addr,
926 s3crc[ns3crc].len,
927 s3crc[ns3crc].dowrite);
928 ns3crc++;
929 if (ns3crc == S3CRC_MAX) {
930 pr_err("S3 crcrec limit reached - aborting\n");
931 return 1;
932 }
933 break;
934 case S3ADDR_INFO:
935 s3info[ns3info].len = *ptr16;
936 s3info[ns3info].type = *(ptr16 + 1);
937
938 pr_debug(" S3 inforec, record=%d len=0x%04x type=0x%04x\n",
939 rcnt,
940 s3info[ns3info].len,
941 s3info[ns3info].type);
942 if (((s3info[ns3info].len - 1) * sizeof(u16)) >
943 sizeof(s3info[ns3info].info)) {
944 pr_err("S3 inforec length too long - aborting\n");
945 return 1;
946 }
947
948 tmpinfo = (u16 *)&s3info[ns3info].info.version;
949 pr_debug(" info=");
950 for (i = 0; i < s3info[ns3info].len - 1; i++) {
951 tmpinfo[i] = *(ptr16 + 2 + i);
952 pr_debug("%04x ", tmpinfo[i]);
953 }
954 pr_debug("\n");
955
956 ns3info++;
957 if (ns3info == S3INFO_MAX) {
958 pr_err("S3 inforec limit reached - aborting\n");
959 return 1;
960 }
961 break;
962 default:
963 s3data[ns3data].addr = addr;
964 s3data[ns3data].len = len;
965 s3data[ns3data].data = (uint8_t *)record->data;
966 ns3data++;
967 if (ns3data == S3DATA_MAX) {
968 pr_err("S3 datarec limit reached - aborting\n");
969 return 1;
970 }
971 break;
972 }
973 record = ihex_next_binrec(record);
974 }
975 return 0;
976}
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
995 unsigned int nfchunks)
996{
997 int result = 0;
998 struct p80211msg_p2req_ramdl_state *rstmsg;
999 struct p80211msg_p2req_ramdl_write *rwrmsg;
1000 u32 resultcode;
1001 int i;
1002 int j;
1003 unsigned int nwrites;
1004 u32 curroff;
1005 u32 currlen;
1006 u32 currdaddr;
1007
1008 rstmsg = kzalloc(sizeof(*rstmsg), GFP_KERNEL);
1009 rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL);
1010 if (!rstmsg || !rwrmsg) {
1011 kfree(rstmsg);
1012 kfree(rwrmsg);
1013 netdev_err(wlandev->netdev,
1014 "%s: no memory for firmware download, aborting download\n",
1015 __func__);
1016 return -ENOMEM;
1017 }
1018
1019
1020 strscpy(rstmsg->devname, wlandev->name, sizeof(rstmsg->devname));
1021 rstmsg->msgcode = DIDMSG_P2REQ_RAMDL_STATE;
1022 rstmsg->msglen = sizeof(*rstmsg);
1023 rstmsg->enable.did = DIDMSG_P2REQ_RAMDL_STATE_ENABLE;
1024 rstmsg->exeaddr.did = DIDMSG_P2REQ_RAMDL_STATE_EXEADDR;
1025 rstmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE;
1026 rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
1027 rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
1028 rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1029 rstmsg->enable.len = sizeof(u32);
1030 rstmsg->exeaddr.len = sizeof(u32);
1031 rstmsg->resultcode.len = sizeof(u32);
1032
1033 strscpy(rwrmsg->devname, wlandev->name, sizeof(rwrmsg->devname));
1034 rwrmsg->msgcode = DIDMSG_P2REQ_RAMDL_WRITE;
1035 rwrmsg->msglen = sizeof(*rwrmsg);
1036 rwrmsg->addr.did = DIDMSG_P2REQ_RAMDL_WRITE_ADDR;
1037 rwrmsg->len.did = DIDMSG_P2REQ_RAMDL_WRITE_LEN;
1038 rwrmsg->data.did = DIDMSG_P2REQ_RAMDL_WRITE_DATA;
1039 rwrmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE;
1040 rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
1041 rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
1042 rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
1043 rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1044 rwrmsg->addr.len = sizeof(u32);
1045 rwrmsg->len.len = sizeof(u32);
1046 rwrmsg->data.len = WRITESIZE_MAX;
1047 rwrmsg->resultcode.len = sizeof(u32);
1048
1049
1050 pr_debug("Sending dl_state(enable) message.\n");
1051 rstmsg->enable.data = P80211ENUM_truth_true;
1052 rstmsg->exeaddr.data = startaddr;
1053
1054 result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1055 if (result) {
1056 netdev_err(wlandev->netdev,
1057 "%s state enable failed w/ result=%d, aborting download\n",
1058 __func__, result);
1059 goto free_result;
1060 }
1061 resultcode = rstmsg->resultcode.data;
1062 if (resultcode != P80211ENUM_resultcode_success) {
1063 netdev_err(wlandev->netdev,
1064 "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1065 __func__, resultcode);
1066 result = 1;
1067 goto free_result;
1068 }
1069
1070
1071 for (i = 0; i < nfchunks; i++) {
1072 nwrites = fchunk[i].len / WRITESIZE_MAX;
1073 nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
1074 curroff = 0;
1075 for (j = 0; j < nwrites; j++) {
1076
1077 int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
1078
1079 if (fchunk[i].len > WRITESIZE_MAX)
1080 currlen = WRITESIZE_MAX;
1081 else
1082 currlen = lenleft;
1083 curroff = j * WRITESIZE_MAX;
1084 currdaddr = fchunk[i].addr + curroff;
1085
1086 rwrmsg->addr.data = currdaddr;
1087 rwrmsg->len.data = currlen;
1088 memcpy(rwrmsg->data.data,
1089 fchunk[i].data + curroff, currlen);
1090
1091
1092 pr_debug
1093 ("Sending xxxdl_write message addr=%06x len=%d.\n",
1094 currdaddr, currlen);
1095
1096 result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
1097
1098
1099 if (result) {
1100 netdev_err(wlandev->netdev,
1101 "%s chunk write failed w/ result=%d, aborting download\n",
1102 __func__, result);
1103 goto free_result;
1104 }
1105 resultcode = rstmsg->resultcode.data;
1106 if (resultcode != P80211ENUM_resultcode_success) {
1107 pr_err("%s()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n",
1108 __func__, resultcode);
1109 result = 1;
1110 goto free_result;
1111 }
1112 }
1113 }
1114
1115
1116 pr_debug("Sending dl_state(disable) message.\n");
1117 rstmsg->enable.data = P80211ENUM_truth_false;
1118 rstmsg->exeaddr.data = 0;
1119
1120 result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1121 if (result) {
1122 netdev_err(wlandev->netdev,
1123 "%s state disable failed w/ result=%d, aborting download\n",
1124 __func__, result);
1125 goto free_result;
1126 }
1127 resultcode = rstmsg->resultcode.data;
1128 if (resultcode != P80211ENUM_resultcode_success) {
1129 netdev_err(wlandev->netdev,
1130 "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1131 __func__, resultcode);
1132 result = 1;
1133 goto free_result;
1134 }
1135
1136free_result:
1137 kfree(rstmsg);
1138 kfree(rwrmsg);
1139 return result;
1140}
1141
1142static int validate_identity(void)
1143{
1144 int i;
1145 int result = 1;
1146 int trump = 0;
1147
1148 pr_debug("NIC ID: %#x v%d.%d.%d\n",
1149 nicid.id, nicid.major, nicid.minor, nicid.variant);
1150 pr_debug("MFI ID: %#x v%d %d->%d\n",
1151 rfid.id, rfid.variant, rfid.bottom, rfid.top);
1152 pr_debug("CFI ID: %#x v%d %d->%d\n",
1153 macid.id, macid.variant, macid.bottom, macid.top);
1154 pr_debug("PRI ID: %#x v%d %d->%d\n",
1155 priid.id, priid.variant, priid.bottom, priid.top);
1156
1157 for (i = 0; i < ns3info; i++) {
1158 switch (s3info[i].type) {
1159 case 1:
1160 pr_debug("Version: ID %#x %d.%d.%d\n",
1161 s3info[i].info.version.id,
1162 s3info[i].info.version.major,
1163 s3info[i].info.version.minor,
1164 s3info[i].info.version.variant);
1165 break;
1166 case 2:
1167 pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
1168 s3info[i].info.compat.role,
1169 s3info[i].info.compat.id,
1170 s3info[i].info.compat.variant,
1171 s3info[i].info.compat.bottom,
1172 s3info[i].info.compat.top);
1173
1174
1175 if ((s3info[i].info.compat.role == 1) &&
1176 (s3info[i].info.compat.id == 2)) {
1177 if (s3info[i].info.compat.variant !=
1178 macid.variant) {
1179 result = 2;
1180 }
1181 }
1182
1183
1184 if ((s3info[i].info.compat.role == 1) &&
1185 (s3info[i].info.compat.id == 3)) {
1186 if ((s3info[i].info.compat.bottom >
1187 priid.top) ||
1188 (s3info[i].info.compat.top <
1189 priid.bottom)) {
1190 result = 3;
1191 }
1192 }
1193
1194 if ((s3info[i].info.compat.role == 1) &&
1195 (s3info[i].info.compat.id == 4)) {
1196
1197 }
1198
1199 break;
1200 case 3:
1201 pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
1202
1203 break;
1204 case 4:
1205 pr_debug("Platform: ID %#x %d.%d.%d\n",
1206 s3info[i].info.version.id,
1207 s3info[i].info.version.major,
1208 s3info[i].info.version.minor,
1209 s3info[i].info.version.variant);
1210
1211 if (nicid.id != s3info[i].info.version.id)
1212 continue;
1213 if (nicid.major != s3info[i].info.version.major)
1214 continue;
1215 if (nicid.minor != s3info[i].info.version.minor)
1216 continue;
1217 if ((nicid.variant != s3info[i].info.version.variant) &&
1218 (nicid.id != 0x8008))
1219 continue;
1220
1221 trump = 1;
1222 break;
1223 case 0x8001:
1224 pr_debug("name inforec len %d\n", s3info[i].len);
1225
1226 break;
1227 default:
1228 pr_debug("Unknown inforec type %d\n", s3info[i].type);
1229 }
1230 }
1231
1232
1233 if (trump && (result != 2))
1234 result = 0;
1235 return result;
1236}
1237