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 
card_bootload(struct net_device * dev)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 
get_handshake(struct net_device * dev,u16 expected_value)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 
put_handshake(struct net_device * dev,u16 handshake_value)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 
get_request_type(struct net_device * dev)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 
get_request_value(struct net_device * dev)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 
put_request_value(struct net_device * dev,long lvalue)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 
hdr_checksum(struct pseudo_hdr * pHdr)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 
card_download(struct net_device * dev,const u8 * pFileStart,size_t FileLength)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 }
770