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