• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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