staging: ft1000-pcmcia: remove PSEUDOSZ, use sizeof(struct pseudo_hdr) instead
[deliverable/linux.git] / drivers / staging / ft1000 / ft1000-pcmcia / ft1000_dnld.c
CommitLineData
f7c1be0c
MB
1/*---------------------------------------------------------------------------
2 FT1000 driver for Flarion Flash OFDM NIC Device
bf3146c8 3
f7c1be0c 4 Copyright (C) 2002 Flarion Technologies, All rights reserved.
bf3146c8
GKH
5
6 This program is free software; you can redistribute it and/or modify it
f7c1be0c 7 under the terms of the GNU General Public License as published by the Free
bf3146c8
GKH
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.
f7c1be0c
MB
16 --------------------------------------------------------------------------
17
bf3146c8 18 Description: This module will handshake with the DSP bootloader to
f7c1be0c 19 download the DSP runtime image.
bf3146c8 20
f7c1be0c
MB
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>
f7c1be0c
MB
33#include <asm/io.h>
34#include <asm/uaccess.h>
35#include <linux/vmalloc.h>
36
f7c1be0c
MB
37#include "ft1000.h"
38#include "boot.h"
39
40#ifdef FT_DEBUG
41#define DEBUG(n, args...) printk(KERN_DEBUG args);
42#else
43#define DEBUG(n, args...)
44#endif
45
46#define MAX_DSP_WAIT_LOOPS 100
47#define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */
48
49#define MAX_LENGTH 0x7f0
50
51#define DWNLD_MAG_HANDSHAKE_LOC 0x00
52#define DWNLD_MAG_TYPE_LOC 0x01
53#define DWNLD_MAG_SIZE_LOC 0x02
54#define DWNLD_MAG_PS_HDR_LOC 0x03
55
56#define DWNLD_HANDSHAKE_LOC 0x02
57#define DWNLD_TYPE_LOC 0x04
58#define DWNLD_SIZE_MSW_LOC 0x06
59#define DWNLD_SIZE_LSW_LOC 0x08
60#define DWNLD_PS_HDR_LOC 0x0A
61
62#define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
63#define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
64#define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
65#define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
66#define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
67
68#define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
69#define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
70
71#define REQUEST_CODE_LENGTH 0x0000
72#define REQUEST_RUN_ADDRESS 0x0001
73#define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
74#define REQUEST_DONE_BL 0x0003
75#define REQUEST_DONE_CL 0x0004
76#define REQUEST_VERSION_INFO 0x0005
77#define REQUEST_CODE_BY_VERSION 0x0006
78#define REQUEST_MAILBOX_DATA 0x0007
79#define REQUEST_FILE_CHECKSUM 0x0008
80
81#define STATE_START_DWNLD 0x01
82#define STATE_BOOT_DWNLD 0x02
83#define STATE_CODE_DWNLD 0x03
84#define STATE_DONE_DWNLD 0x04
85#define STATE_SECTION_PROV 0x05
86#define STATE_DONE_PROV 0x06
87#define STATE_DONE_FILE 0x07
88
ca145277
OZ
89u16 get_handshake(struct net_device *dev, u16 expected_value);
90void put_handshake(struct net_device *dev, u16 handshake_value);
91u16 get_request_type(struct net_device *dev);
f7c1be0c
MB
92long get_request_value(struct net_device *dev);
93void put_request_value(struct net_device *dev, long lvalue);
ca145277 94u16 hdr_checksum(struct pseudo_hdr *pHdr);
f7c1be0c 95
8e0fd2cf 96struct dsp_file_hdr {
14e5d8ef 97 u32 build_date;
98 u32 dsp_coff_date;
99 u32 loader_code_address;
100 u32 loader_code_size;
101 u32 loader_code_end;
102 u32 dsp_code_address;
103 u32 dsp_code_size;
104 u32 dsp_code_end;
105 u32 reserved[8];
8e0fd2cf 106} __attribute__ ((packed));
f7c1be0c 107
8e0fd2cf 108struct dsp_file_hdr_5 {
14e5d8ef 109 u32 version_id; // Version ID of this image format.
110 u32 package_id; // Package ID of code release.
111 u32 build_date; // Date/time stamp when file was built.
112 u32 commands_offset; // Offset to attached commands in Pseudo Hdr format.
113 u32 loader_offset; // Offset to bootloader code.
114 u32 loader_code_address; // Start address of bootloader.
115 u32 loader_code_end; // Where bootloader code ends.
116 u32 loader_code_size;
117 u32 version_data_offset; // Offset were scrambled version data begins.
118 u32 version_data_size; // Size, in words, of scrambled version data.
119 u32 nDspImages; // Number of DSP images in file.
8e0fd2cf 120} __attribute__ ((packed));
f7c1be0c 121
8e0fd2cf 122struct dsp_image_info {
14e5d8ef 123 u32 coff_date; // Date/time when DSP Coff image was built.
124 u32 begin_offset; // Offset in file where image begins.
125 u32 end_offset; // Offset in file where image begins.
126 u32 run_address; // On chip Start address of DSP code.
127 u32 image_size; // Size of image.
128 u32 version; // Embedded version # of DSP code.
8e0fd2cf 129} __attribute__ ((packed));
f7c1be0c 130
8e0fd2cf 131struct dsp_image_info_v6 {
14e5d8ef 132 u32 coff_date; // Date/time when DSP Coff image was built.
133 u32 begin_offset; // Offset in file where image begins.
134 u32 end_offset; // Offset in file where image begins.
135 u32 run_address; // On chip Start address of DSP code.
136 u32 image_size; // Size of image.
137 u32 version; // Embedded version # of DSP code.
f7c1be0c
MB
138 unsigned short checksum; // Dsp File checksum
139 unsigned short pad1;
8e0fd2cf 140} __attribute__ ((packed));
f7c1be0c
MB
141
142void card_bootload(struct net_device *dev)
143{
d3706552 144 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
f7c1be0c 145 unsigned long flags;
ca145277
OZ
146 u32 *pdata;
147 u32 size;
148 u32 i;
149 u32 templong;
f7c1be0c
MB
150
151 DEBUG(0, "card_bootload is called\n");
152
ca145277 153 pdata = (u32 *) bootimage;
f7c1be0c
MB
154 size = sizeof(bootimage);
155
156 // check for odd word
157 if (size & 0x0003) {
158 size += 4;
159 }
160 // Provide mutual exclusive access while reading ASIC registers.
161 spin_lock_irqsave(&info->dpram_lock, flags);
162
163 // need to set i/o base address initially and hardware will autoincrement
164 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
165 // write bytes
166 for (i = 0; i < (size >> 2); i++) {
167 templong = *pdata++;
168 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
169 }
170
171 spin_unlock_irqrestore(&info->dpram_lock, flags);
172}
173
ca145277 174u16 get_handshake(struct net_device *dev, u16 expected_value)
f7c1be0c 175{
d3706552 176 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
ca145277
OZ
177 u16 handshake;
178 u32 tempx;
f7c1be0c
MB
179 int loopcnt;
180
181 loopcnt = 0;
182 while (loopcnt < MAX_DSP_WAIT_LOOPS) {
183 if (info->AsicID == ELECTRABUZZ_ID) {
184 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
185 DWNLD_HANDSHAKE_LOC);
186
187 handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
188 } else {
189 tempx =
190 ntohl(ft1000_read_dpram_mag_32
191 (dev, DWNLD_MAG_HANDSHAKE_LOC));
ca145277 192 handshake = (u16) tempx;
f7c1be0c
MB
193 }
194
195 if ((handshake == expected_value)
196 || (handshake == HANDSHAKE_RESET_VALUE)) {
197 return handshake;
198 } else {
199 loopcnt++;
200 mdelay(DSP_WAIT_SLEEP_TIME);
201 }
202
203 }
204
205 return HANDSHAKE_TIMEOUT_VALUE;
206
207}
208
ca145277 209void put_handshake(struct net_device *dev, u16 handshake_value)
f7c1be0c 210{
d3706552 211 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
ca145277 212 u32 tempx;
f7c1be0c
MB
213
214 if (info->AsicID == ELECTRABUZZ_ID) {
215 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
216 DWNLD_HANDSHAKE_LOC);
217 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */
218 } else {
ca145277 219 tempx = (u32) handshake_value;
f7c1be0c
MB
220 tempx = ntohl(tempx);
221 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
222 }
223}
224
ca145277 225u16 get_request_type(struct net_device *dev)
f7c1be0c 226{
d3706552 227 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
ca145277
OZ
228 u16 request_type;
229 u32 tempx;
f7c1be0c
MB
230
231 if (info->AsicID == ELECTRABUZZ_ID) {
232 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
233 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
234 } else {
235 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
236 tempx = ntohl(tempx);
ca145277 237 request_type = (u16) tempx;
f7c1be0c
MB
238 }
239
240 return request_type;
241
242}
243
244long get_request_value(struct net_device *dev)
245{
d3706552 246 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
f7c1be0c 247 long value;
ca145277 248 u16 w_val;
f7c1be0c
MB
249
250 if (info->AsicID == ELECTRABUZZ_ID) {
251 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
252 DWNLD_SIZE_MSW_LOC);
253
254 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
255
256 value = (long)(w_val << 16);
257
258 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
259 DWNLD_SIZE_LSW_LOC);
260
261 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
262
263 value = (long)(value | w_val);
264 } else {
265 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
266 value = ntohl(value);
267 }
268
269 return value;
270
271}
272
273void put_request_value(struct net_device *dev, long lvalue)
274{
d3706552 275 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
ca145277
OZ
276 u16 size;
277 u32 tempx;
f7c1be0c
MB
278
279 if (info->AsicID == ELECTRABUZZ_ID) {
ca145277 280 size = (u16) (lvalue >> 16);
f7c1be0c
MB
281
282 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
283 DWNLD_SIZE_MSW_LOC);
284
285 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
286
ca145277 287 size = (u16) (lvalue);
f7c1be0c
MB
288
289 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
290 DWNLD_SIZE_LSW_LOC);
291
292 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
293 } else {
294 tempx = ntohl(lvalue);
295 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */
296 }
297
298}
299
ca145277 300u16 hdr_checksum(struct pseudo_hdr *pHdr)
f7c1be0c 301{
ca145277
OZ
302 u16 *usPtr = (u16 *) pHdr;
303 u16 chksum;
f7c1be0c
MB
304
305 chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
306 usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
307
308 return chksum;
309}
310
ca145277 311int card_download(struct net_device *dev, const u8 *pFileStart, u32 FileLength)
f7c1be0c 312{
d3706552 313 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
f7c1be0c 314 int Status = SUCCESS;
ca145277
OZ
315 u16 DspWordCnt = 0;
316 u32 uiState;
317 u16 handshake;
2c9bf839 318 struct pseudo_hdr *pHdr;
ca145277 319 u16 usHdrLength;
8e0fd2cf 320 struct dsp_file_hdr *pFileHdr;
f7c1be0c 321 long word_length;
ca145277
OZ
322 u16 request;
323 u16 temp;
3aaf8073 324 struct prov_record *pprov_record;
ca145277 325 u8 *pbuffer;
8e0fd2cf
OZ
326 struct dsp_file_hdr_5 *pFileHdr5;
327 struct dsp_image_info *pDspImageInfo = NULL;
328 struct dsp_image_info_v6 *pDspImageInfoV6 = NULL;
f7c1be0c 329 long requested_version;
ca145277 330 bool bGoodVersion = 0;
8bc0d6fb 331 struct drv_msg *pMailBoxData;
ca145277
OZ
332 u16 *pUsData = NULL;
333 u16 *pUsFile = NULL;
334 u8 *pUcFile = NULL;
335 u8 *pBootEnd = NULL;
336 u8 *pCodeEnd = NULL;
f7c1be0c
MB
337 int imageN;
338 long file_version;
339 long loader_code_address = 0;
340 long loader_code_size = 0;
341 long run_address = 0;
342 long run_size = 0;
343 unsigned long flags;
344 unsigned long templong;
345 unsigned long image_chksum = 0;
346
347 //
348 // Get version id of file, at first 4 bytes of file, for newer files.
349 //
350 file_version = *(long *)pFileStart;
351
352 uiState = STATE_START_DWNLD;
353
8e0fd2cf
OZ
354 pFileHdr = (struct dsp_file_hdr *) pFileStart;
355 pFileHdr5 = (struct dsp_file_hdr_5 *) pFileStart;
f7c1be0c
MB
356
357 switch (file_version) {
358 case 5:
359 case 6:
360 pUsFile =
ca145277 361 (u16 *) ((long)pFileStart + pFileHdr5->loader_offset);
f7c1be0c 362 pUcFile =
ca145277 363 (u8 *) ((long)pFileStart + pFileHdr5->loader_offset);
f7c1be0c
MB
364
365 pBootEnd =
ca145277 366 (u8 *) ((long)pFileStart + pFileHdr5->loader_code_end);
f7c1be0c
MB
367
368 loader_code_address = pFileHdr5->loader_code_address;
369 loader_code_size = pFileHdr5->loader_code_size;
ca145277 370 bGoodVersion = false;
f7c1be0c
MB
371 break;
372
373 default:
374 Status = FAILURE;
375 break;
376 }
377
378 while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
379
380 switch (uiState) {
381 case STATE_START_DWNLD:
382
383 handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
384
385 if (handshake == HANDSHAKE_DSP_BL_READY) {
386 put_handshake(dev, HANDSHAKE_DRIVER_READY);
387 } else {
388 Status = FAILURE;
389 }
390
391 uiState = STATE_BOOT_DWNLD;
392
393 break;
394
395 case STATE_BOOT_DWNLD:
396 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
397 if (handshake == HANDSHAKE_REQUEST) {
398 /*
399 * Get type associated with the request.
400 */
401 request = get_request_type(dev);
402 switch (request) {
403 case REQUEST_RUN_ADDRESS:
404 put_request_value(dev,
405 loader_code_address);
406 break;
407 case REQUEST_CODE_LENGTH:
408 put_request_value(dev,
409 loader_code_size);
410 break;
411 case REQUEST_DONE_BL:
412 /* Reposition ptrs to beginning of code section */
ca145277
OZ
413 pUsFile = (u16 *) ((long)pBootEnd);
414 pUcFile = (u8 *) ((long)pBootEnd);
f7c1be0c
MB
415 uiState = STATE_CODE_DWNLD;
416 break;
417 case REQUEST_CODE_SEGMENT:
418 word_length = get_request_value(dev);
419 if (word_length > MAX_LENGTH) {
420 Status = FAILURE;
421 break;
422 }
423 if ((word_length * 2 + (long)pUcFile) >
424 (long)pBootEnd) {
425 /*
426 * Error, beyond boot code range.
427 */
428 Status = FAILURE;
429 break;
430 }
431 // Provide mutual exclusive access while reading ASIC registers.
432 spin_lock_irqsave(&info->dpram_lock,
433 flags);
434 if (file_version == 5) {
435 /*
436 * Position ASIC DPRAM auto-increment pointer.
437 */
438 ft1000_write_reg(dev,
439 FT1000_REG_DPRAM_ADDR,
440 DWNLD_PS_HDR_LOC);
441
442 for (; word_length > 0; word_length--) { /* In words */
443 //temp = *pUsFile;
444 //temp = RtlUshortByteSwap(temp);
445 ft1000_write_reg(dev,
446 FT1000_REG_DPRAM_DATA,
447 *pUsFile);
448 pUsFile++;
449 pUcFile += 2;
450 DspWordCnt++;
451 }
452 } else {
453 /*
454 * Position ASIC DPRAM auto-increment pointer.
455 */
456 outw(DWNLD_MAG_PS_HDR_LOC,
457 dev->base_addr +
458 FT1000_REG_DPRAM_ADDR);
459 if (word_length & 0x01) {
460 word_length++;
461 }
462 word_length = word_length / 2;
463
464 for (; word_length > 0; word_length--) { /* In words */
465 templong = *pUsFile++;
466 templong |=
467 (*pUsFile++ << 16);
468 pUcFile += 4;
469 outl(templong,
470 dev->base_addr +
471 FT1000_REG_MAG_DPDATAL);
472 }
473 }
474 spin_unlock_irqrestore(&info->
475 dpram_lock,
476 flags);
477 break;
478 default:
479 Status = FAILURE;
480 break;
481 }
482 put_handshake(dev, HANDSHAKE_RESPONSE);
483 } else {
484 Status = FAILURE;
485 }
486
487 break;
488
489 case STATE_CODE_DWNLD:
490 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
491 if (handshake == HANDSHAKE_REQUEST) {
492 /*
493 * Get type associated with the request.
494 */
495 request = get_request_type(dev);
496 switch (request) {
497 case REQUEST_FILE_CHECKSUM:
498 DEBUG(0,
499 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
500 put_request_value(dev, image_chksum);
501 break;
502 case REQUEST_RUN_ADDRESS:
503 if (bGoodVersion) {
504 put_request_value(dev,
505 run_address);
506 } else {
507 Status = FAILURE;
508 break;
509 }
510 break;
511 case REQUEST_CODE_LENGTH:
512 if (bGoodVersion) {
513 put_request_value(dev,
514 run_size);
515 } else {
516 Status = FAILURE;
517 break;
518 }
519 break;
520 case REQUEST_DONE_CL:
521 /* Reposition ptrs to beginning of provisioning section */
522 switch (file_version) {
523 case 5:
524 case 6:
525 pUsFile =
ca145277 526 (u16 *) ((long)pFileStart
f7c1be0c
MB
527 +
528 pFileHdr5->
529 commands_offset);
530 pUcFile =
ca145277 531 (u8 *) ((long)pFileStart
f7c1be0c
MB
532 +
533 pFileHdr5->
534 commands_offset);
535 break;
536 default:
537 Status = FAILURE;
538 break;
539 }
540 uiState = STATE_DONE_DWNLD;
541 break;
542 case REQUEST_CODE_SEGMENT:
543 if (!bGoodVersion) {
544 Status = FAILURE;
545 break;
546 }
547 word_length = get_request_value(dev);
548 if (word_length > MAX_LENGTH) {
549 Status = FAILURE;
550 break;
551 }
552 if ((word_length * 2 + (long)pUcFile) >
553 (long)pCodeEnd) {
554 /*
555 * Error, beyond boot code range.
556 */
557 Status = FAILURE;
558 break;
559 }
560 if (file_version == 5) {
561 /*
562 * Position ASIC DPRAM auto-increment pointer.
563 */
564 ft1000_write_reg(dev,
565 FT1000_REG_DPRAM_ADDR,
566 DWNLD_PS_HDR_LOC);
567
568 for (; word_length > 0; word_length--) { /* In words */
569 //temp = *pUsFile;
570 //temp = RtlUshortByteSwap(temp);
571 ft1000_write_reg(dev,
572 FT1000_REG_DPRAM_DATA,
573 *pUsFile);
574 pUsFile++;
575 pUcFile += 2;
576 DspWordCnt++;
577 }
578 } else {
579 /*
580 * Position ASIC DPRAM auto-increment pointer.
581 */
582 outw(DWNLD_MAG_PS_HDR_LOC,
583 dev->base_addr +
584 FT1000_REG_DPRAM_ADDR);
585 if (word_length & 0x01) {
586 word_length++;
587 }
588 word_length = word_length / 2;
589
590 for (; word_length > 0; word_length--) { /* In words */
591 templong = *pUsFile++;
592 templong |=
593 (*pUsFile++ << 16);
594 pUcFile += 4;
595 outl(templong,
596 dev->base_addr +
597 FT1000_REG_MAG_DPDATAL);
598 }
599 }
600 break;
601
602 case REQUEST_MAILBOX_DATA:
603 // Convert length from byte count to word count. Make sure we round up.
604 word_length =
605 (long)(info->DSPInfoBlklen + 1) / 2;
606 put_request_value(dev, word_length);
607 pMailBoxData =
8bc0d6fb 608 (struct drv_msg *) & info->DSPInfoBlk[0];
f7c1be0c 609 pUsData =
ca145277 610 (u16 *) & pMailBoxData->data[0];
f7c1be0c
MB
611 // Provide mutual exclusive access while reading ASIC registers.
612 spin_lock_irqsave(&info->dpram_lock,
613 flags);
614 if (file_version == 5) {
615 /*
616 * Position ASIC DPRAM auto-increment pointer.
617 */
618 ft1000_write_reg(dev,
619 FT1000_REG_DPRAM_ADDR,
620 DWNLD_PS_HDR_LOC);
621
622 for (; word_length > 0; word_length--) { /* In words */
623 temp = ntohs(*pUsData);
624 ft1000_write_reg(dev,
625 FT1000_REG_DPRAM_DATA,
626 temp);
627 pUsData++;
628 }
629 } else {
630 /*
631 * Position ASIC DPRAM auto-increment pointer.
632 */
633 outw(DWNLD_MAG_PS_HDR_LOC,
634 dev->base_addr +
635 FT1000_REG_DPRAM_ADDR);
636 if (word_length & 0x01) {
637 word_length++;
638 }
639 word_length = word_length / 2;
640
641 for (; word_length > 0; word_length--) { /* In words */
642 templong = *pUsData++;
643 templong |=
644 (*pUsData++ << 16);
645 outl(templong,
646 dev->base_addr +
647 FT1000_REG_MAG_DPDATAL);
648 }
649 }
650 spin_unlock_irqrestore(&info->
651 dpram_lock,
652 flags);
653 break;
654
655 case REQUEST_VERSION_INFO:
656 word_length =
657 pFileHdr5->version_data_size;
658 put_request_value(dev, word_length);
659 pUsFile =
ca145277 660 (u16 *) ((long)pFileStart +
f7c1be0c
MB
661 pFileHdr5->
662 version_data_offset);
663 // Provide mutual exclusive access while reading ASIC registers.
664 spin_lock_irqsave(&info->dpram_lock,
665 flags);
666 if (file_version == 5) {
667 /*
668 * Position ASIC DPRAM auto-increment pointer.
669 */
670 ft1000_write_reg(dev,
671 FT1000_REG_DPRAM_ADDR,
672 DWNLD_PS_HDR_LOC);
673
674 for (; word_length > 0; word_length--) { /* In words */
675 ft1000_write_reg(dev,
676 FT1000_REG_DPRAM_DATA,
677 *pUsFile
678 /*temp */
679 );
680 pUsFile++;
681 }
682 } else {
683 /*
684 * Position ASIC DPRAM auto-increment pointer.
685 */
686 outw(DWNLD_MAG_PS_HDR_LOC,
687 dev->base_addr +
688 FT1000_REG_DPRAM_ADDR);
689 if (word_length & 0x01) {
690 word_length++;
691 }
692 word_length = word_length / 2;
693
694 for (; word_length > 0; word_length--) { /* In words */
695 templong =
696 ntohs(*pUsFile++);
697 temp =
698 ntohs(*pUsFile++);
699 templong |=
700 (temp << 16);
701 outl(templong,
702 dev->base_addr +
703 FT1000_REG_MAG_DPDATAL);
704 }
705 }
706 spin_unlock_irqrestore(&info->
707 dpram_lock,
708 flags);
709 break;
710
711 case REQUEST_CODE_BY_VERSION:
ca145277 712 bGoodVersion = false;
f7c1be0c
MB
713 requested_version =
714 get_request_value(dev);
715 if (file_version == 5) {
716 pDspImageInfo =
8e0fd2cf 717 (struct dsp_image_info *) ((long)
f7c1be0c
MB
718 pFileStart
719 +
720 sizeof
8e0fd2cf 721 (struct dsp_file_hdr_5));
f7c1be0c
MB
722 for (imageN = 0;
723 imageN <
724 pFileHdr5->nDspImages;
725 imageN++) {
726 if (pDspImageInfo->
727 version ==
728 requested_version) {
729 bGoodVersion =
ca145277 730 true;
f7c1be0c 731 pUsFile =
ca145277 732 (u16
f7c1be0c
MB
733 *) ((long)
734 pFileStart
735 +
736 pDspImageInfo->
737 begin_offset);
738 pUcFile =
ca145277 739 (u8
f7c1be0c
MB
740 *) ((long)
741 pFileStart
742 +
743 pDspImageInfo->
744 begin_offset);
745 pCodeEnd =
ca145277 746 (u8
f7c1be0c
MB
747 *) ((long)
748 pFileStart
749 +
750 pDspImageInfo->
751 end_offset);
752 run_address =
753 pDspImageInfo->
754 run_address;
755 run_size =
756 pDspImageInfo->
757 image_size;
758 break;
759 }
760 pDspImageInfo++;
761 }
762 } else {
763 pDspImageInfoV6 =
8e0fd2cf 764 (struct dsp_image_info_v6 *) ((long)
f7c1be0c
MB
765 pFileStart
766 +
767 sizeof
8e0fd2cf 768 (struct dsp_file_hdr_5));
f7c1be0c
MB
769 for (imageN = 0;
770 imageN <
771 pFileHdr5->nDspImages;
772 imageN++) {
ca145277 773 temp = (u16)
f7c1be0c
MB
774 (pDspImageInfoV6->
775 version);
776 templong = temp;
ca145277 777 temp = (u16)
f7c1be0c
MB
778 (pDspImageInfoV6->
779 version >> 16);
780 templong |=
781 (temp << 16);
782 if (templong ==
783 requested_version) {
784 bGoodVersion =
ca145277 785 true;
f7c1be0c 786 pUsFile =
ca145277 787 (u16
f7c1be0c
MB
788 *) ((long)
789 pFileStart
790 +
791 pDspImageInfoV6->
792 begin_offset);
793 pUcFile =
ca145277 794 (u8
f7c1be0c
MB
795 *) ((long)
796 pFileStart
797 +
798 pDspImageInfoV6->
799 begin_offset);
800 pCodeEnd =
ca145277 801 (u8
f7c1be0c
MB
802 *) ((long)
803 pFileStart
804 +
805 pDspImageInfoV6->
806 end_offset);
807 run_address =
808 pDspImageInfoV6->
809 run_address;
810 run_size =
811 pDspImageInfoV6->
812 image_size;
813 image_chksum =
ca145277 814 (u32)
f7c1be0c
MB
815 pDspImageInfoV6->
816 checksum;
817 DEBUG(0,
818 "ft1000_dnld: image_chksum = 0x%8x\n",
819 (unsigned
820 int)
821 image_chksum);
822 break;
823 }
824 pDspImageInfoV6++;
825 }
826 }
827 if (!bGoodVersion) {
828 /*
829 * Error, beyond boot code range.
830 */
831 Status = FAILURE;
832 break;
833 }
834 break;
835
836 default:
837 Status = FAILURE;
838 break;
839 }
840 put_handshake(dev, HANDSHAKE_RESPONSE);
841 } else {
842 Status = FAILURE;
843 }
844
845 break;
846
847 case STATE_DONE_DWNLD:
14e5d8ef 848 if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
849 (unsigned long) FileLength) {
f7c1be0c
MB
850 uiState = STATE_DONE_FILE;
851 break;
852 }
853
2c9bf839 854 pHdr = (struct pseudo_hdr *) pUsFile;
f7c1be0c
MB
855
856 if (pHdr->portdest == 0x80 /* DspOAM */
857 && (pHdr->portsrc == 0x00 /* Driver */
858 || pHdr->portsrc == 0x10 /* FMM */ )) {
859 uiState = STATE_SECTION_PROV;
860 } else {
861 DEBUG(1,
862 "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
863 DEBUG(1, "\t Port Source = 0x%2.2x\n",
864 pHdr->portsrc);
865 DEBUG(1, "\t Port Destination = 0x%2.2x\n",
866 pHdr->portdest);
867 Status = FAILURE;
868 }
869
870 break;
871
872 case STATE_SECTION_PROV:
873
2c9bf839 874 pHdr = (struct pseudo_hdr *) pUcFile;
f7c1be0c
MB
875
876 if (pHdr->checksum == hdr_checksum(pHdr)) {
877 if (pHdr->portdest != 0x80 /* Dsp OAM */ ) {
878 uiState = STATE_DONE_PROV;
879 break;
880 }
881 usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
882
883 // Get buffer for provisioning data
884 pbuffer =
2c9bf839 885 kmalloc((usHdrLength + sizeof(struct pseudo_hdr)),
f7c1be0c
MB
886 GFP_ATOMIC);
887 if (pbuffer) {
888 memcpy(pbuffer, (void *)pUcFile,
ca145277 889 (u32) (usHdrLength +
2c9bf839 890 sizeof(struct pseudo_hdr)));
bf3146c8 891 // link provisioning data
f7c1be0c 892 pprov_record =
3aaf8073 893 kmalloc(sizeof(struct prov_record),
f7c1be0c
MB
894 GFP_ATOMIC);
895 if (pprov_record) {
896 pprov_record->pprov_data =
897 pbuffer;
898 list_add_tail(&pprov_record->
899 list,
900 &info->prov_list);
901 // Move to next entry if available
902 pUcFile =
ca145277 903 (u8 *) ((unsigned long) pUcFile +
2c9bf839 904 (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
14e5d8ef 905 if ((unsigned long) (pUcFile) -
906 (unsigned long) (pFileStart) >=
907 (unsigned long) FileLength) {
f7c1be0c
MB
908 uiState =
909 STATE_DONE_FILE;
910 }
911 } else {
912 kfree(pbuffer);
913 Status = FAILURE;
914 }
915 } else {
916 Status = FAILURE;
917 }
918 } else {
919 /* Checksum did not compute */
920 Status = FAILURE;
921 }
922
923 break;
924
925 case STATE_DONE_PROV:
926 uiState = STATE_DONE_FILE;
927 break;
928
929 default:
930 Status = FAILURE;
931 break;
932 } /* End Switch */
933
934 } /* End while */
935
936 return Status;
937
938}
This page took 0.160064 seconds and 5 git commands to generate.