1 /*---------------------------------------------------------------------------
2 FT1000 driver for Flarion Flash OFDM NIC Device
3
4 Copyright (C) 2002 Flarion Technologies, All rights reserved.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option) any
9 later version. This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details. You should have received a copy of the GNU General Public
13 License along with this program; if not, write to the
14 Free Software Foundation, Inc., 59 Temple Place -
15 Suite 330, Boston, MA 02111-1307, USA.
16 --------------------------------------------------------------------------
17
18 Description: This module will handshake with the DSP bootloader to
19 download the DSP runtime image.
20
21 ---------------------------------------------------------------------------*/
22
23 #define __KERNEL_SYSCALLS__
24
25 #include <linux/module.h>
26 #include <linux/fs.h>
27 #include <linux/mm.h>
28 #include <linux/slab.h>
29 #include <linux/unistd.h>
30 #include <linux/netdevice.h>
31 #include <linux/timer.h>
32 #include <linux/delay.h>
33 #include <linux/io.h>
34 #include <linux/uaccess.h>
35 #include <linux/vmalloc.h>
36
37 #include "ft1000.h"
38 #include "boot.h"
39
40 #define MAX_DSP_WAIT_LOOPS 100
41 #define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */
42
43 #define MAX_LENGTH 0x7f0
44
45 #define DWNLD_MAG_HANDSHAKE_LOC 0x00
46 #define DWNLD_MAG_TYPE_LOC 0x01
47 #define DWNLD_MAG_SIZE_LOC 0x02
48 #define DWNLD_MAG_PS_HDR_LOC 0x03
49
50 #define DWNLD_HANDSHAKE_LOC 0x02
51 #define DWNLD_TYPE_LOC 0x04
52 #define DWNLD_SIZE_MSW_LOC 0x06
53 #define DWNLD_SIZE_LSW_LOC 0x08
54 #define DWNLD_PS_HDR_LOC 0x0A
55
56 #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
57 #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
58 #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
59 #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
60 #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
61
62 #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
63 #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
64
65 #define REQUEST_CODE_LENGTH 0x0000
66 #define REQUEST_RUN_ADDRESS 0x0001
67 #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
68 #define REQUEST_DONE_BL 0x0003
69 #define REQUEST_DONE_CL 0x0004
70 #define REQUEST_VERSION_INFO 0x0005
71 #define REQUEST_CODE_BY_VERSION 0x0006
72 #define REQUEST_MAILBOX_DATA 0x0007
73 #define REQUEST_FILE_CHECKSUM 0x0008
74
75 #define STATE_START_DWNLD 0x01
76 #define STATE_BOOT_DWNLD 0x02
77 #define STATE_CODE_DWNLD 0x03
78 #define STATE_DONE_DWNLD 0x04
79 #define STATE_SECTION_PROV 0x05
80 #define STATE_DONE_PROV 0x06
81 #define STATE_DONE_FILE 0x07
82
83 u16 get_handshake(struct net_device *dev, u16 expected_value);
84 void put_handshake(struct net_device *dev, u16 handshake_value);
85 u16 get_request_type(struct net_device *dev);
86 long get_request_value(struct net_device *dev);
87 void put_request_value(struct net_device *dev, long lvalue);
88 u16 hdr_checksum(struct pseudo_hdr *pHdr);
89
90 struct dsp_file_hdr {
91 u32 version_id; /* Version ID of this image format. */
92 u32 package_id; /* Package ID of code release. */
93 u32 build_date; /* Date/time stamp when file was built. */
94 u32 commands_offset; /* Offset to attached commands in Pseudo Hdr format. */
95 u32 loader_offset; /* Offset to bootloader code. */
96 u32 loader_code_address; /* Start address of bootloader. */
97 u32 loader_code_end; /* Where bootloader code ends. */
98 u32 loader_code_size;
99 u32 version_data_offset; /* Offset were scrambled version data begins. */
100 u32 version_data_size; /* Size, in words, of scrambled version data. */
101 u32 nDspImages; /* Number of DSP images in file. */
102 } __attribute__ ((packed));
103
104 struct dsp_image_info {
105 u32 coff_date; /* Date/time when DSP Coff image was built. */
106 u32 begin_offset; /* Offset in file where image begins. */
107 u32 end_offset; /* Offset in file where image begins. */
108 u32 run_address; /* On chip Start address of DSP code. */
109 u32 image_size; /* Size of image. */
110 u32 version; /* Embedded version # of DSP code. */
111 unsigned short checksum; /* Dsp File checksum */
112 unsigned short pad1;
113 } __attribute__ ((packed));
114
card_bootload(struct net_device * dev)115 void card_bootload(struct net_device *dev)
116 {
117 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
118 unsigned long flags;
119 u32 *pdata;
120 u32 size;
121 u32 i;
122 u32 templong;
123
124 netdev_dbg(dev, "card_bootload is called\n");
125
126 pdata = (u32 *) bootimage;
127 size = sizeof(bootimage);
128
129 /* check for odd word */
130 if (size & 0x0003)
131 size += 4;
132
133 /* Provide mutual exclusive access while reading ASIC registers. */
134 spin_lock_irqsave(&info->dpram_lock, flags);
135
136 /* need to set i/o base address initially and hardware will autoincrement */
137 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
138 /* write bytes */
139 for (i = 0; i < (size >> 2); i++) {
140 templong = *pdata++;
141 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
142 }
143
144 spin_unlock_irqrestore(&info->dpram_lock, flags);
145 }
146
get_handshake(struct net_device * dev,u16 expected_value)147 u16 get_handshake(struct net_device *dev, u16 expected_value)
148 {
149 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
150 u16 handshake;
151 u32 tempx;
152 int loopcnt;
153
154 loopcnt = 0;
155 while (loopcnt < MAX_DSP_WAIT_LOOPS) {
156 if (info->AsicID == ELECTRABUZZ_ID) {
157 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
158 DWNLD_HANDSHAKE_LOC);
159
160 handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
161 } else {
162 tempx =
163 ntohl(ft1000_read_dpram_mag_32
164 (dev, DWNLD_MAG_HANDSHAKE_LOC));
165 handshake = (u16) tempx;
166 }
167
168 if ((handshake == expected_value)
169 || (handshake == HANDSHAKE_RESET_VALUE)) {
170 return handshake;
171 }
172 loopcnt++;
173 mdelay(DSP_WAIT_SLEEP_TIME);
174
175 }
176
177 return HANDSHAKE_TIMEOUT_VALUE;
178
179 }
180
put_handshake(struct net_device * dev,u16 handshake_value)181 void put_handshake(struct net_device *dev, u16 handshake_value)
182 {
183 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
184 u32 tempx;
185
186 if (info->AsicID == ELECTRABUZZ_ID) {
187 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
188 DWNLD_HANDSHAKE_LOC);
189 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */
190 } else {
191 tempx = (u32) handshake_value;
192 tempx = ntohl(tempx);
193 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
194 }
195 }
196
get_request_type(struct net_device * dev)197 u16 get_request_type(struct net_device *dev)
198 {
199 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
200 u16 request_type;
201 u32 tempx;
202
203 if (info->AsicID == ELECTRABUZZ_ID) {
204 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
205 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
206 } else {
207 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
208 tempx = ntohl(tempx);
209 request_type = (u16) tempx;
210 }
211
212 return request_type;
213
214 }
215
get_request_value(struct net_device * dev)216 long get_request_value(struct net_device *dev)
217 {
218 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
219 long value;
220 u16 w_val;
221
222 if (info->AsicID == ELECTRABUZZ_ID) {
223 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
224 DWNLD_SIZE_MSW_LOC);
225
226 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
227
228 value = (long)(w_val << 16);
229
230 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
231 DWNLD_SIZE_LSW_LOC);
232
233 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
234
235 value = (long)(value | w_val);
236 } else {
237 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
238 value = ntohl(value);
239 }
240
241 return value;
242
243 }
244
put_request_value(struct net_device * dev,long lvalue)245 void put_request_value(struct net_device *dev, long lvalue)
246 {
247 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
248 u16 size;
249 u32 tempx;
250
251 if (info->AsicID == ELECTRABUZZ_ID) {
252 size = (u16) (lvalue >> 16);
253
254 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
255 DWNLD_SIZE_MSW_LOC);
256
257 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
258
259 size = (u16) (lvalue);
260
261 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
262 DWNLD_SIZE_LSW_LOC);
263
264 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
265 } else {
266 tempx = ntohl(lvalue);
267 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */
268 }
269
270 }
271
hdr_checksum(struct pseudo_hdr * pHdr)272 u16 hdr_checksum(struct pseudo_hdr *pHdr)
273 {
274 u16 *usPtr = (u16 *) pHdr;
275 u16 chksum;
276
277 chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
278 usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
279
280 return chksum;
281 }
282
card_download(struct net_device * dev,const u8 * pFileStart,size_t FileLength)283 int card_download(struct net_device *dev, const u8 *pFileStart,
284 size_t FileLength)
285 {
286 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
287 int Status = SUCCESS;
288 u32 uiState;
289 u16 handshake;
290 struct pseudo_hdr *pHdr;
291 u16 usHdrLength;
292 long word_length;
293 u16 request;
294 u16 temp;
295 struct prov_record *pprov_record;
296 u8 *pbuffer;
297 struct dsp_file_hdr *pFileHdr5;
298 struct dsp_image_info *pDspImageInfoV6 = NULL;
299 long requested_version;
300 bool bGoodVersion = false;
301 struct drv_msg *pMailBoxData;
302 u16 *pUsData = NULL;
303 u16 *pUsFile = NULL;
304 u8 *pUcFile = NULL;
305 u8 *pBootEnd = NULL;
306 u8 *pCodeEnd = NULL;
307 int imageN;
308 long file_version;
309 long loader_code_address = 0;
310 long loader_code_size = 0;
311 long run_address = 0;
312 long run_size = 0;
313 unsigned long flags;
314 unsigned long templong;
315 unsigned long image_chksum = 0;
316
317 file_version = *(long *)pFileStart;
318 if (file_version != 6) {
319 printk(KERN_ERR "ft1000: unsupported firmware version %ld\n", file_version);
320 Status = FAILURE;
321 }
322
323 uiState = STATE_START_DWNLD;
324
325 pFileHdr5 = (struct dsp_file_hdr *) pFileStart;
326
327 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->loader_offset);
328 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->loader_offset);
329 pBootEnd = (u8 *) ((long)pFileStart + pFileHdr5->loader_code_end);
330 loader_code_address = pFileHdr5->loader_code_address;
331 loader_code_size = pFileHdr5->loader_code_size;
332 bGoodVersion = false;
333
334 while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
335
336 switch (uiState) {
337 case STATE_START_DWNLD:
338
339 handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
340
341 if (handshake == HANDSHAKE_DSP_BL_READY)
342 put_handshake(dev, HANDSHAKE_DRIVER_READY);
343 else
344 Status = FAILURE;
345
346 uiState = STATE_BOOT_DWNLD;
347
348 break;
349
350 case STATE_BOOT_DWNLD:
351 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
352 if (handshake == HANDSHAKE_REQUEST) {
353 /*
354 * Get type associated with the request.
355 */
356 request = get_request_type(dev);
357 switch (request) {
358 case REQUEST_RUN_ADDRESS:
359 put_request_value(dev,
360 loader_code_address);
361 break;
362 case REQUEST_CODE_LENGTH:
363 put_request_value(dev,
364 loader_code_size);
365 break;
366 case REQUEST_DONE_BL:
367 /* Reposition ptrs to beginning of code section */
368 pUsFile = (u16 *) ((long)pBootEnd);
369 pUcFile = (u8 *) ((long)pBootEnd);
370 uiState = STATE_CODE_DWNLD;
371 break;
372 case REQUEST_CODE_SEGMENT:
373 word_length = get_request_value(dev);
374 if (word_length > MAX_LENGTH) {
375 Status = FAILURE;
376 break;
377 }
378 if ((word_length * 2 + (long)pUcFile) >
379 (long)pBootEnd) {
380 /*
381 * Error, beyond boot code range.
382 */
383 Status = FAILURE;
384 break;
385 }
386 /* Provide mutual exclusive access while reading ASIC registers. */
387 spin_lock_irqsave(&info->dpram_lock,
388 flags);
389 /*
390 * Position ASIC DPRAM auto-increment pointer.
391 */
392 outw(DWNLD_MAG_PS_HDR_LOC,
393 dev->base_addr +
394 FT1000_REG_DPRAM_ADDR);
395 if (word_length & 0x01)
396 word_length++;
397 word_length = word_length / 2;
398
399 for (; word_length > 0; word_length--) { /* In words */
400 templong = *pUsFile++;
401 templong |=
402 (*pUsFile++ << 16);
403 pUcFile += 4;
404 outl(templong,
405 dev->base_addr +
406 FT1000_REG_MAG_DPDATAL);
407 }
408 spin_unlock_irqrestore(&info->
409 dpram_lock,
410 flags);
411 break;
412 default:
413 Status = FAILURE;
414 break;
415 }
416 put_handshake(dev, HANDSHAKE_RESPONSE);
417 } else {
418 Status = FAILURE;
419 }
420
421 break;
422
423 case STATE_CODE_DWNLD:
424 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
425 if (handshake == HANDSHAKE_REQUEST) {
426 /*
427 * Get type associated with the request.
428 */
429 request = get_request_type(dev);
430 switch (request) {
431 case REQUEST_FILE_CHECKSUM:
432 netdev_dbg(dev,
433 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
434 put_request_value(dev, image_chksum);
435 break;
436 case REQUEST_RUN_ADDRESS:
437 if (bGoodVersion) {
438 put_request_value(dev,
439 run_address);
440 } else {
441 Status = FAILURE;
442 break;
443 }
444 break;
445 case REQUEST_CODE_LENGTH:
446 if (bGoodVersion) {
447 put_request_value(dev,
448 run_size);
449 } else {
450 Status = FAILURE;
451 break;
452 }
453 break;
454 case REQUEST_DONE_CL:
455 /* Reposition ptrs to beginning of provisioning section */
456 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->commands_offset);
457 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->commands_offset);
458 uiState = STATE_DONE_DWNLD;
459 break;
460 case REQUEST_CODE_SEGMENT:
461 if (!bGoodVersion) {
462 Status = FAILURE;
463 break;
464 }
465 word_length = get_request_value(dev);
466 if (word_length > MAX_LENGTH) {
467 Status = FAILURE;
468 break;
469 }
470 if ((word_length * 2 + (long)pUcFile) >
471 (long)pCodeEnd) {
472 /*
473 * Error, beyond boot code range.
474 */
475 Status = FAILURE;
476 break;
477 }
478 /*
479 * Position ASIC DPRAM auto-increment pointer.
480 */
481 outw(DWNLD_MAG_PS_HDR_LOC,
482 dev->base_addr +
483 FT1000_REG_DPRAM_ADDR);
484 if (word_length & 0x01)
485 word_length++;
486 word_length = word_length / 2;
487
488 for (; word_length > 0; word_length--) { /* In words */
489 templong = *pUsFile++;
490 templong |=
491 (*pUsFile++ << 16);
492 pUcFile += 4;
493 outl(templong,
494 dev->base_addr +
495 FT1000_REG_MAG_DPDATAL);
496 }
497 break;
498
499 case REQUEST_MAILBOX_DATA:
500 /* Convert length from byte count to word count. Make sure we round up. */
501 word_length =
502 (long)(info->DSPInfoBlklen + 1) / 2;
503 put_request_value(dev, word_length);
504 pMailBoxData =
505 (struct drv_msg *) &info->DSPInfoBlk[0];
506 pUsData =
507 (u16 *) &pMailBoxData->data[0];
508 /* Provide mutual exclusive access while reading ASIC registers. */
509 spin_lock_irqsave(&info->dpram_lock,
510 flags);
511 if (file_version == 5) {
512 /*
513 * Position ASIC DPRAM auto-increment pointer.
514 */
515 ft1000_write_reg(dev,
516 FT1000_REG_DPRAM_ADDR,
517 DWNLD_PS_HDR_LOC);
518
519 for (; word_length > 0; word_length--) { /* In words */
520 temp = ntohs(*pUsData);
521 ft1000_write_reg(dev,
522 FT1000_REG_DPRAM_DATA,
523 temp);
524 pUsData++;
525 }
526 } else {
527 /*
528 * Position ASIC DPRAM auto-increment pointer.
529 */
530 outw(DWNLD_MAG_PS_HDR_LOC,
531 dev->base_addr +
532 FT1000_REG_DPRAM_ADDR);
533 if (word_length & 0x01)
534 word_length++;
535
536 word_length = word_length / 2;
537
538 for (; word_length > 0; word_length--) { /* In words */
539 templong = *pUsData++;
540 templong |=
541 (*pUsData++ << 16);
542 outl(templong,
543 dev->base_addr +
544 FT1000_REG_MAG_DPDATAL);
545 }
546 }
547 spin_unlock_irqrestore(&info->
548 dpram_lock,
549 flags);
550 break;
551
552 case REQUEST_VERSION_INFO:
553 word_length =
554 pFileHdr5->version_data_size;
555 put_request_value(dev, word_length);
556 pUsFile =
557 (u16 *) ((long)pFileStart +
558 pFileHdr5->
559 version_data_offset);
560 /* Provide mutual exclusive access while reading ASIC registers. */
561 spin_lock_irqsave(&info->dpram_lock,
562 flags);
563 /*
564 * Position ASIC DPRAM auto-increment pointer.
565 */
566 outw(DWNLD_MAG_PS_HDR_LOC,
567 dev->base_addr +
568 FT1000_REG_DPRAM_ADDR);
569 if (word_length & 0x01)
570 word_length++;
571 word_length = word_length / 2;
572
573 for (; word_length > 0; word_length--) { /* In words */
574 templong =
575 ntohs(*pUsFile++);
576 temp =
577 ntohs(*pUsFile++);
578 templong |=
579 (temp << 16);
580 outl(templong,
581 dev->base_addr +
582 FT1000_REG_MAG_DPDATAL);
583 }
584 spin_unlock_irqrestore(&info->
585 dpram_lock,
586 flags);
587 break;
588
589 case REQUEST_CODE_BY_VERSION:
590 bGoodVersion = false;
591 requested_version =
592 get_request_value(dev);
593 pDspImageInfoV6 =
594 (struct dsp_image_info *) ((long)
595 pFileStart
596 +
597 sizeof
598 (struct dsp_file_hdr));
599 for (imageN = 0;
600 imageN <
601 pFileHdr5->nDspImages;
602 imageN++) {
603 temp = (u16)
604 (pDspImageInfoV6->
605 version);
606 templong = temp;
607 temp = (u16)
608 (pDspImageInfoV6->
609 version >> 16);
610 templong |=
611 (temp << 16);
612 if (templong ==
613 requested_version) {
614 bGoodVersion =
615 true;
616 pUsFile =
617 (u16
618 *) ((long)
619 pFileStart
620 +
621 pDspImageInfoV6->
622 begin_offset);
623 pUcFile =
624 (u8
625 *) ((long)
626 pFileStart
627 +
628 pDspImageInfoV6->
629 begin_offset);
630 pCodeEnd =
631 (u8
632 *) ((long)
633 pFileStart
634 +
635 pDspImageInfoV6->
636 end_offset);
637 run_address =
638 pDspImageInfoV6->
639 run_address;
640 run_size =
641 pDspImageInfoV6->
642 image_size;
643 image_chksum =
644 (u32)
645 pDspImageInfoV6->
646 checksum;
647 netdev_dbg(dev,
648 "ft1000_dnld: image_chksum = 0x%8x\n",
649 (unsigned
650 int)
651 image_chksum);
652 break;
653 }
654 pDspImageInfoV6++;
655 }
656 if (!bGoodVersion) {
657 /*
658 * Error, beyond boot code range.
659 */
660 Status = FAILURE;
661 break;
662 }
663 break;
664
665 default:
666 Status = FAILURE;
667 break;
668 }
669 put_handshake(dev, HANDSHAKE_RESPONSE);
670 } else {
671 Status = FAILURE;
672 }
673
674 break;
675
676 case STATE_DONE_DWNLD:
677 if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
678 (unsigned long) FileLength) {
679 uiState = STATE_DONE_FILE;
680 break;
681 }
682
683 pHdr = (struct pseudo_hdr *) pUsFile;
684
685 if (pHdr->portdest == 0x80 /* DspOAM */
686 && (pHdr->portsrc == 0x00 /* Driver */
687 || pHdr->portsrc == 0x10 /* FMM */)) {
688 uiState = STATE_SECTION_PROV;
689 } else {
690 netdev_dbg(dev,
691 "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
692 netdev_dbg(dev, "\t Port Source = 0x%2.2x\n",
693 pHdr->portsrc);
694 netdev_dbg(dev, "\t Port Destination = 0x%2.2x\n",
695 pHdr->portdest);
696 Status = FAILURE;
697 }
698
699 break;
700
701 case STATE_SECTION_PROV:
702
703 pHdr = (struct pseudo_hdr *) pUcFile;
704
705 if (pHdr->checksum == hdr_checksum(pHdr)) {
706 if (pHdr->portdest != 0x80 /* Dsp OAM */) {
707 uiState = STATE_DONE_PROV;
708 break;
709 }
710 usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
711
712 /* Get buffer for provisioning data */
713 pbuffer =
714 kmalloc((usHdrLength + sizeof(struct pseudo_hdr)),
715 GFP_ATOMIC);
716 if (pbuffer) {
717 memcpy(pbuffer, (void *)pUcFile,
718 (u32) (usHdrLength +
719 sizeof(struct pseudo_hdr)));
720 /* link provisioning data */
721 pprov_record =
722 kmalloc(sizeof(struct prov_record),
723 GFP_ATOMIC);
724 if (pprov_record) {
725 pprov_record->pprov_data =
726 pbuffer;
727 list_add_tail(&pprov_record->
728 list,
729 &info->prov_list);
730 /* Move to next entry if available */
731 pUcFile =
732 (u8 *) ((unsigned long) pUcFile +
733 (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
734 if ((unsigned long) (pUcFile) -
735 (unsigned long) (pFileStart) >=
736 (unsigned long) FileLength) {
737 uiState =
738 STATE_DONE_FILE;
739 }
740 } else {
741 kfree(pbuffer);
742 Status = FAILURE;
743 }
744 } else {
745 Status = FAILURE;
746 }
747 } else {
748 /* Checksum did not compute */
749 Status = FAILURE;
750 }
751
752 break;
753
754 case STATE_DONE_PROV:
755 uiState = STATE_DONE_FILE;
756 break;
757
758 default:
759 Status = FAILURE;
760 break;
761 } /* End Switch */
762
763 } /* End while */
764
765 return Status;
766
767 }
768