http://www.usr.com/support/gpl/USR9107_release1.1.tar.gz
[bcm963xx.git] / bcmdrivers / opensource / char / board / bcm963xx / impl1 / bcm63xx_flash.c
1 /*
2 <:copyright-gpl
3  Copyright 2002 Broadcom Corp. All Rights Reserved.
4
5  This program is free software; you can distribute it and/or modify it
6  under the terms of the GNU General Public License (Version 2) as
7  published by the Free Software Foundation.
8
9  This program is distributed in the hope it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  for more details.
13
14  You should have received a copy of the GNU General Public License along
15  with this program; if not, write to the Free Software Foundation, Inc.,
16  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 :>
18 */
19 /*
20  ***************************************************************************
21  * File Name  : bcm63xx_flash.c
22  *
23  * Description: This file contains the flash device driver APIs for bcm63xx board. 
24  *
25  * Created on :  8/10/2002  seanl:  use cfiflash.c, cfliflash.h (AMD specific)
26  *
27  ***************************************************************************/
28
29
30 /* Includes. */
31 #include <linux/fs.h>
32 #include <linux/capability.h>
33 #include <linux/slab.h>
34 #include <linux/errno.h>
35 #include <linux/module.h>
36 #include <asm/uaccess.h>
37
38 #include <bcm_map_part.h>
39 #include <board.h>
40 #define  BCMTAG_EXE_USE
41 #include <bcmTag.h>
42 #include "cfiflash.h"
43 #include "boardparms.h"
44
45 //#define DEBUG_FLASH
46
47 static FLASH_ADDR_INFO fInfo;
48 static int flashInitialized = 0;
49
50 void *retriedKmalloc(size_t size)
51 {
52         void *pBuf;
53     int tryCount = 0;
54
55     // try 1000 times before quit
56     while (((pBuf = kmalloc(size, GFP_KERNEL)) == NULL) && (tryCount++ < 1000))
57     {
58                 current->state   = TASK_INTERRUPTIBLE;
59                 schedule_timeout(HZ/10);
60         }
61     if (tryCount >= 1000)
62         pBuf = NULL;
63     else
64             memset(pBuf, 0, size);
65
66     return pBuf;
67 }
68
69 void retriedKfree(void *pBuf)
70 {
71         kfree(pBuf);
72 }
73
74 /***************************************************************************
75 // Function Name: getCrc32
76 // Description  : caculate the CRC 32 of the given data.
77 // Parameters   : pdata - array of data.
78 //                size - number of input data bytes.
79 //                crc - either CRC32_INIT_VALUE or previous return value.
80 // Returns      : crc.
81 ****************************************************************************/
82 UINT32 getCrc32(byte *pdata, UINT32 size, UINT32 crc) 
83 {
84     while (size-- > 0)
85         crc = (crc >> 8) ^ Crc32_table[(crc ^ *pdata++) & 0xff];
86
87     return crc;
88 }
89
90 // get the nvram start addr
91 //
92 unsigned long get_nvram_start_addr(void)
93 {
94     return ((unsigned long) 
95         (flash_get_memptr(fInfo.flash_nvram_start_blk) + fInfo.flash_nvram_blk_offset));
96 }
97
98 // get the scratch_pad start addr
99 //
100 unsigned long get_scratch_pad_start_addr(void)
101 {
102     return ((unsigned long) 
103         (flash_get_memptr(fInfo.flash_scratch_pad_start_blk) + fInfo.flash_scratch_pad_blk_offset));
104 }
105
106
107
108 /*  *********************************************************************
109     *  kerSysImageTagGet()
110     *   Get the image tag
111     *  Input parameters:
112     *      none
113     *  Return value:
114     *      point to tag -- Found
115     *      NULL -- failed
116     ********************************************************************* */
117 PFILE_TAG kerSysImageTagGet(void)
118 {
119     int i;
120     int totalBlks = flash_get_numsectors();
121     UINT32 crc;
122     unsigned char *sectAddr;
123     PFILE_TAG pTag;
124
125 #if defined(DEBUG_FLASH)
126     printk("totalblks in tagGet=%d\n", totalBlks);
127 #endif
128
129     // start from 2nd blk, assume 1st one is always CFE
130     for (i = 1; i < totalBlks; i++)
131     {
132         sectAddr =  flash_get_memptr((byte) i);
133         crc = CRC32_INIT_VALUE;
134         crc = getCrc32(sectAddr, (UINT32)TAG_LEN-TOKEN_LEN, crc);      
135         pTag = (PFILE_TAG) sectAddr;
136
137 #if defined(DEBUG_FLASH)
138         printk("Check Tag crc on blk [%d]\n", i);
139 #endif
140
141         if (crc == (UINT32)(*(UINT32*)(pTag->tagValidationToken)))
142             return pTag;
143     }
144
145     return (PFILE_TAG) NULL;
146 }
147
148 // Initialize the flash and fill out the fInfo structure
149 void kerSysFlashInit( void )
150 {
151     int i = 0;
152     int totalBlks = 0;
153     int totalSize = 0;
154     int startAddr = 0;
155     int usedBlkSize = 0;
156     NVRAM_DATA nvramData;
157     UINT32 crc = CRC32_INIT_VALUE, savedCrc;
158     PFILE_TAG pTag = NULL;
159     unsigned long kernelEndAddr = 0;
160     unsigned long spAddr = 0;
161
162     if (flashInitialized)
163         return;
164
165     flashInitialized = 1;
166     flash_init();
167
168     totalBlks = flash_get_numsectors();
169     totalSize = flash_get_total_size();
170
171     printk("Total Flash size: %dK with %d sectors\n", totalSize/1024, totalBlks);
172
173     /* nvram is always at the end of flash */
174     fInfo.flash_nvram_length = FLASH45_LENGTH_NVRAM;
175     fInfo.flash_nvram_start_blk = 0;  /* always the first block */
176     fInfo.flash_nvram_number_blk = 1; /*always fits in the first block */
177     fInfo.flash_nvram_blk_offset = NVRAM_DATA_OFFSET;
178  
179     // check nvram CRC
180     memcpy((char *)&nvramData, (char *)get_nvram_start_addr(), sizeof(NVRAM_DATA));
181     savedCrc = nvramData.ulCheckSum;
182     nvramData.ulCheckSum = 0;
183     crc = getCrc32((char *)&nvramData, (UINT32) sizeof(NVRAM_DATA), crc);   
184
185     BpSetBoardId( nvramData.szBoardId );
186
187     fInfo.flash_persistent_length = NVRAM_PSI_DEFAULT;
188     if (savedCrc != crc)
189     {
190         printk("***Board is not initialized****: Using the default PSI size: %d\n",
191             fInfo.flash_persistent_length);
192     }
193     else
194     {
195         unsigned long ulPsiSize;
196         if( BpGetPsiSize( &ulPsiSize ) == BP_SUCCESS )
197             fInfo.flash_persistent_length = ulPsiSize;
198         else
199         {
200             printk("***Board id is not set****: Using the default PSI size: %d\n",
201                 fInfo.flash_persistent_length);
202         }
203     }
204
205     fInfo.flash_persistent_length *= ONEK;
206     startAddr = totalSize - fInfo.flash_persistent_length;
207     fInfo.flash_persistent_start_blk = flash_get_blk(startAddr+FLASH_BASE_ADDR_REG);
208     fInfo.flash_persistent_number_blk = totalBlks - fInfo.flash_persistent_start_blk;
209     // save abs SP address (Scratch Pad). it is before PSI 
210     spAddr = startAddr - SP_MAX_LEN ;
211     // find out the offset in the start_blk
212     usedBlkSize = 0;
213     for (i = fInfo.flash_persistent_start_blk; 
214         i < (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk); i++)
215     {
216         usedBlkSize += flash_get_sector_size((byte) i);
217     }
218     fInfo.flash_persistent_blk_offset =  usedBlkSize - fInfo.flash_persistent_length;
219
220     // get the info for sp
221     if (!(pTag = kerSysImageTagGet()))
222     {
223         printk("Failed to read image tag from flash\n");
224         return;
225     }
226     kernelEndAddr = (unsigned long) simple_strtoul(pTag->kernelAddress, NULL, 10) + \
227         (unsigned long) simple_strtoul(pTag->kernelLen, NULL, 10);
228
229     // make suer sp does not share kernel block
230     fInfo.flash_scratch_pad_start_blk = flash_get_blk(spAddr+FLASH_BASE_ADDR_REG);
231     if (fInfo.flash_scratch_pad_start_blk != flash_get_blk(kernelEndAddr))
232     {
233         fInfo.flash_scratch_pad_length = SP_MAX_LEN;
234         if (fInfo.flash_persistent_start_blk == fInfo.flash_scratch_pad_start_blk)  // share blk
235         {
236 #if 1 /* do not used scratch pad unless it's in its own sector */
237             printk("Scratch pad is not used for this flash part.\n");  
238             fInfo.flash_scratch_pad_length = 0;     // no sp
239 #else /* allow scratch pad to share a sector with another section such as PSI */
240             fInfo.flash_scratch_pad_number_blk = 1;
241             fInfo.flash_scratch_pad_blk_offset = fInfo.flash_persistent_blk_offset - fInfo.flash_scratch_pad_length;
242 #endif
243         }
244         else // on different blk
245         {
246             fInfo.flash_scratch_pad_number_blk = fInfo.flash_persistent_start_blk\
247                 - fInfo.flash_scratch_pad_start_blk;
248             // find out the offset in the start_blk
249             usedBlkSize = 0;
250             for (i = fInfo.flash_scratch_pad_start_blk; 
251                 i < (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk); i++)
252                 usedBlkSize += flash_get_sector_size((byte) i);
253                 fInfo.flash_scratch_pad_blk_offset =  usedBlkSize - fInfo.flash_scratch_pad_length;
254         }
255     }
256     else
257     {
258         printk("No flash for scratch pad!\n");  
259         fInfo.flash_scratch_pad_length = 0;     // no sp
260     }
261
262 #if defined(DEBUG_FLASH)
263     printk("fInfo.flash_scratch_pad_start_blk = %d\n", fInfo.flash_scratch_pad_start_blk);
264     printk("fInfo.flash_scratch_pad_number_blk = %d\n", fInfo.flash_scratch_pad_number_blk);
265     printk("fInfo.flash_scratch_pad_length = 0x%x\n", fInfo.flash_scratch_pad_length);
266     printk("fInfo.flash_scratch_pad_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_scratch_pad_blk_offset);
267
268     printk("fInfo.flash_nvram_start_blk = %d\n", fInfo.flash_nvram_start_blk);
269     printk("fInfo.flash_nvram_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_nvram_blk_offset);
270     printk("fInfo.flash_nvram_number_blk = %d\n", fInfo.flash_nvram_number_blk);
271
272     printk("psi startAddr = %x\n", startAddr+FLASH_BASE_ADDR_REG);
273     printk("fInfo.flash_persistent_start_blk = %d\n", fInfo.flash_persistent_start_blk);
274     printk("fInfo.flash_persistent_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_persistent_blk_offset);
275     printk("fInfo.flash_persistent_number_blk = %d\n", fInfo.flash_persistent_number_blk);
276 #endif
277
278 }
279
280
281
282 /***********************************************************************
283  * Function Name: kerSysFlashAddrInfoGet
284  * Description  : Fills in a structure with information about the NVRAM
285  *                and persistent storage sections of flash memory.  
286  *                Fro physmap.c to mount the fs vol.
287  * Returns      : None.
288  ***********************************************************************/
289 void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info)
290 {
291     pflash_addr_info->flash_nvram_blk_offset = fInfo.flash_nvram_blk_offset;
292     pflash_addr_info->flash_nvram_length = fInfo.flash_nvram_length;
293     pflash_addr_info->flash_nvram_number_blk = fInfo.flash_nvram_number_blk;
294     pflash_addr_info->flash_nvram_start_blk = fInfo.flash_nvram_start_blk;
295     pflash_addr_info->flash_persistent_blk_offset = fInfo.flash_persistent_blk_offset;
296     pflash_addr_info->flash_persistent_length = fInfo.flash_persistent_length;
297     pflash_addr_info->flash_persistent_number_blk = fInfo.flash_persistent_number_blk;
298     pflash_addr_info->flash_persistent_start_blk = fInfo.flash_persistent_start_blk;
299 }
300
301
302 // get shared blks into *** pTempBuf *** which has to be released bye the caller!
303 // return: if pTempBuf != NULL, poits to the data with the dataSize of the buffer
304 // !NULL -- ok
305 // NULL  -- fail
306 static char *getSharedBlks(int start_blk, int end_blk)
307 {
308     int i = 0;
309     int usedBlkSize = 0;
310     int sect_size = 0;
311     char *pTempBuf = NULL;
312     char *pBuf = NULL;
313
314     for (i = start_blk; i < end_blk; i++)
315         usedBlkSize += flash_get_sector_size((byte) i);
316
317 #if defined(DEBUG_FLASH)
318     printk("usedBlkSize = %d\n", usedBlkSize);
319 #endif
320
321     if ((pTempBuf = (char *) retriedKmalloc(usedBlkSize)) == NULL)
322     {
323         printk("failed to allocate memory with size: %d\n", usedBlkSize);
324         return pTempBuf;
325     }
326     
327     pBuf = pTempBuf;
328     for (i = start_blk; i < end_blk; i++)
329     {
330         sect_size = flash_get_sector_size((byte) i);
331
332 #if defined(DEBUG_FLASH)
333         printk("i = %d, sect_size = %d, end_blk = %d\n", i, sect_size, end_blk);
334 #endif
335         flash_read_buf((byte)i, 0, pBuf, sect_size);
336         pBuf += sect_size;
337     }
338     
339     return pTempBuf;
340 }
341
342
343
344 // Set the pTempBuf to flash from start_blk to end_blk
345 // return:
346 // 0 -- ok
347 // -1 -- fail
348 static int setSharedBlks(int start_blk, int end_blk, char *pTempBuf)
349 {
350     int i = 0;
351     int sect_size = 0;
352     int sts = 0;
353     char *pBuf = pTempBuf;
354
355     for (i = start_blk; i < end_blk; i++)
356     {
357         sect_size = flash_get_sector_size((byte) i);
358         flash_sector_erase_int(i);
359         if (flash_write_buf(i, 0, pBuf, sect_size) != sect_size)
360         {
361             printk("Error writing flash sector %d.", i);
362             sts = -1;
363             break;
364         }
365         pBuf += sect_size;
366     }
367
368     return sts;
369 }
370
371
372
373 /*******************************************************************************
374  * NVRAM functions
375  *******************************************************************************/
376
377 // get nvram data
378 // return:
379 //  0 - ok
380 //  -1 - fail
381 int kerSysNvRamGet(char *string, int strLen, int offset)
382 {
383     char *pBuf = NULL;
384
385     if (!flashInitialized)
386         kerSysFlashInit();
387
388     if (strLen > FLASH45_LENGTH_NVRAM)
389         return -1;
390
391     if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
392         (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
393         return -1;
394
395     // get string off the memory buffer
396     memcpy(string, (pBuf + fInfo.flash_nvram_blk_offset + offset), strLen);
397
398     retriedKfree(pBuf);
399
400     return 0;
401 }
402
403
404 // set nvram 
405 // return:
406 //  0 - ok
407 //  -1 - fail
408 int kerSysNvRamSet(char *string, int strLen, int offset)
409 {
410     int sts = 0;
411     char *pBuf = NULL;
412
413     if (strLen > FLASH45_LENGTH_NVRAM)
414         return -1;
415
416     if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
417         (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
418         return -1;
419
420     // set string to the memory buffer
421     memcpy((pBuf + fInfo.flash_nvram_blk_offset + offset), string, strLen);
422
423     if (setSharedBlks(fInfo.flash_nvram_start_blk, 
424         (fInfo.flash_nvram_number_blk + fInfo.flash_nvram_start_blk), pBuf) != 0)
425         sts = -1;
426     
427     retriedKfree(pBuf);
428
429     return sts;
430 }
431
432
433 /***********************************************************************
434  * Function Name: kerSysEraseNvRam
435  * Description  : Erase the NVRAM storage section of flash memory.
436  * Returns      : 1 -- ok, 0 -- fail
437  ***********************************************************************/
438 int kerSysEraseNvRam(void)
439 {
440     int sts = 1;
441     char *tempStorage = retriedKmalloc(FLASH45_LENGTH_NVRAM);
442     
443     // just write the whole buf with '0xff' to the flash
444     if (!tempStorage)
445         sts = 0;
446     else
447     {
448         memset(tempStorage, 0xff, FLASH45_LENGTH_NVRAM);
449         if (kerSysNvRamSet(tempStorage, FLASH45_LENGTH_NVRAM, 0) != 0)
450             sts = 0;
451         retriedKfree(tempStorage);
452     }
453
454     return sts;
455 }
456
457
458 /*******************************************************************************
459  * PSI functions
460  *******************************************************************************/
461 // get psi data
462 // return:
463 //  0 - ok
464 //  -1 - fail
465 int kerSysPersistentGet(char *string, int strLen, int offset)
466 {
467     char *pBuf = NULL;
468
469     if (strLen > fInfo.flash_persistent_length)
470         return -1;
471
472     if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
473         (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
474         return -1;
475
476     // get string off the memory buffer
477     memcpy(string, (pBuf + fInfo.flash_persistent_blk_offset + offset), strLen);
478
479     retriedKfree(pBuf);
480
481     return 0;
482 }
483
484
485 // set psi 
486 // return:
487 //  0 - ok
488 //  -1 - fail
489 int kerSysPersistentSet(char *string, int strLen, int offset)
490 {
491     int sts = 0;
492     char *pBuf = NULL;
493
494     if (strLen > fInfo.flash_persistent_length)
495         return -1;
496
497     if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
498         (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
499         return -1;
500
501     // set string to the memory buffer
502     memcpy((pBuf + fInfo.flash_persistent_blk_offset + offset), string, strLen);
503
504     if (setSharedBlks(fInfo.flash_persistent_start_blk, 
505         (fInfo.flash_persistent_number_blk + fInfo.flash_persistent_start_blk), pBuf) != 0)
506         sts = -1;
507     
508     retriedKfree(pBuf);
509
510     return sts;
511 }
512
513
514 // flash bcm image 
515 // return: 
516 // 0 - ok
517 // !0 - the sector number fail to be flashed (should not be 0)
518 int kerSysBcmImageSet( int flash_start_addr, char *string, int size)
519 {
520     int sts;
521     int sect_size;
522     int blk_start;
523     int i;
524     char *pTempBuf = NULL;
525     int whole_image = 0;
526
527     blk_start = flash_get_blk(flash_start_addr);
528     if( blk_start < 0 )
529         return( -1 );
530
531     if (flash_start_addr == FLASH_BASE && size > FLASH45_LENGTH_BOOT_ROM)
532         whole_image = 1;
533
534    /* write image to flash memory */
535     do 
536     {
537         sect_size = flash_get_sector_size(blk_start);
538 // NOTE: for memory problem in multiple PVC configuration, temporary get rid of kmalloc this 64K for now.
539 //        if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
540 //        {
541 //            printk("Failed to allocate memory with size: %d.  Reset the router...\n", sect_size);
542 //            kerSysMipsSoftReset();     // reset the board right away.
543 //        }
544         // for whole image, no check on psi
545         if (!whole_image && blk_start == fInfo.flash_persistent_start_blk)  // share the blk with psi
546         {
547             if (size > (sect_size - fInfo.flash_persistent_length))
548             {
549                 printk("Image is too big\n");
550                 break;          // image is too big. Can not overwrite to nvram
551             }
552             if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
553             {
554                printk("Failed to allocate memory with size: %d.  Reset the router...\n", sect_size);
555                kerSysMipsSoftReset();     // reset the board right away.
556             }
557             flash_read_buf((byte)blk_start, 0, pTempBuf, sect_size);
558             if (copy_from_user((void *)pTempBuf,(void *)string, size) != 0)
559                 break;  // failed ?
560             flash_sector_erase_int(blk_start);     // erase blk before flash
561             if (flash_write_buf(blk_start, 0, pTempBuf, sect_size) == sect_size) 
562                 size = 0;   // break out and say all is ok
563             retriedKfree(pTempBuf);
564             break;
565         }
566         
567         flash_sector_erase_int(blk_start);     // erase blk before flash
568
569         if (sect_size > size) 
570         {
571             if (size & 1) 
572                 size++;
573             sect_size = size;
574         }
575         
576         if ((i = flash_write_buf(blk_start, 0, string, sect_size)) != sect_size) {
577             break;
578         }
579         blk_start++;
580         string += sect_size;
581         size -= sect_size; 
582     } while (size > 0);
583
584     if (whole_image)  
585     {
586         // If flashing a whole image, erase to end of flash.
587         int total_blks = flash_get_numsectors();
588         while( blk_start < total_blks )
589         {
590             flash_sector_erase_int(blk_start);
591             blk_start++;
592         }
593     }
594     if (pTempBuf)
595         retriedKfree(pTempBuf);
596
597     if( size == 0 ) 
598         sts = 0;  // ok
599     else  
600         sts = blk_start;    // failed to flash this sector
601
602     return sts;
603 }
604
605 /*******************************************************************************
606  * SP functions
607  *******************************************************************************/
608 // get sp data.  NOTE: memcpy work here -- not using copy_from/to_user
609 // return:
610 //  0 - ok
611 //  -1 - fail
612 int kerSysScratchPadGet(char *tokenId, char *tokBuf, int bufLen)
613 {
614     PSP_HEADER pHead = NULL;
615     PSP_TOKEN pToken = NULL;
616     char *pBuf = NULL;
617     char *pShareBuf = NULL;
618     char *startPtr = NULL;
619     char *endPtr = NULL;
620     char *spEndPtr = NULL;
621     int sts = -1;
622
623     if (fInfo.flash_scratch_pad_length == 0)
624         return sts;
625
626     if (bufLen >= (fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) - sizeof(SP_TOKEN))) 
627     {
628         printk("Exceed scratch pad space by %d\n", bufLen  - fInfo.flash_scratch_pad_length \
629             - sizeof(SP_HEADER) - sizeof(SP_TOKEN));
630         return sts;
631     }
632
633     if ((pShareBuf = getSharedBlks(fInfo.flash_scratch_pad_start_blk,
634         (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk))) == NULL)
635         return sts;
636
637     // pBuf points to SP buf
638     pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;  
639
640     pHead = (PSP_HEADER) pBuf;
641     if (memcmp(pHead->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0) 
642     {
643         printk("Scrap pad is not initialized.\n");
644         return sts;
645     }
646
647     // search up to SPUsedLen for the token
648     startPtr = pBuf + sizeof(SP_HEADER);
649     endPtr = pBuf + pHead->SPUsedLen;
650     spEndPtr = pBuf + SP_MAX_LEN;
651     while (startPtr < endPtr && startPtr < spEndPtr)
652     {
653         pToken = (PSP_TOKEN) startPtr;
654         if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
655         {
656             memcpy(tokBuf, startPtr + sizeof(SP_TOKEN), bufLen);
657             sts = 0;
658             break;
659         }
660         // get next token
661         startPtr += sizeof(SP_TOKEN) + pToken->tokenLen;
662     }
663
664     retriedKfree(pShareBuf);
665
666     return sts;
667 }
668
669
670 // set sp.  NOTE: memcpy work here -- not using copy_from/to_user
671 // return:
672 //  0 - ok
673 //  -1 - fail
674 int kerSysScratchPadSet(char *tokenId, char *tokBuf, int bufLen)
675 {
676     PSP_TOKEN pToken = NULL;
677     PSP_HEADER pHead = NULL;
678     char *pShareBuf = NULL;
679     char *pBuf = NULL;
680     SP_HEADER SPHead;
681     SP_TOKEN SPToken;
682     char *curPtr;
683     int sts = -1;
684
685     if (fInfo.flash_scratch_pad_length == 0)
686         return sts;
687
688     if (bufLen >= (fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) - sizeof(SP_TOKEN))) 
689     {
690         printk("Exceed scratch pad space by %d\n", bufLen  - fInfo.flash_scratch_pad_length \
691             - sizeof(SP_HEADER) - sizeof(SP_TOKEN));
692         return sts;
693     }
694
695     if ((pShareBuf = getSharedBlks(fInfo.flash_scratch_pad_start_blk,
696         (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk))) == NULL)
697         return sts;
698
699     // pBuf points to SP buf
700     pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;  
701     pHead = (PSP_HEADER) pBuf;
702
703     // form header info.  SPUsedLen later on...
704     memset((char *)&SPHead, 0, sizeof(SP_HEADER));
705     memcpy(SPHead.SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN);
706     SPHead.SPVersion = SP_VERSION;
707
708     // form token info.
709     memset((char*)&SPToken, 0, sizeof(SP_TOKEN));
710     strncpy(SPToken.tokenName, tokenId, TOKEN_NAME_LEN - 1);
711     SPToken.tokenLen = bufLen;
712     if (memcmp(pHead->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0) 
713     {
714         // new sp, so just flash the token
715         printk("No Scrap pad found.  Initialize scratch pad...\n");
716         SPHead.SPUsedLen = sizeof(SP_HEADER) + sizeof(SP_TOKEN) + bufLen;
717         memcpy(pBuf, (char *)&SPHead, sizeof(SP_HEADER));
718         curPtr = pBuf + sizeof(SP_HEADER);
719         memcpy(curPtr, (char *)&SPToken, sizeof(SP_TOKEN));
720         curPtr += sizeof(SP_TOKEN);
721         memcpy(curPtr, tokBuf, bufLen);
722     }
723     else  
724     {
725         // need search for the token, if exist with same size overwrite it. if sizes differ, 
726         // move over the later token data over and put the new one at the end
727         char *endPtr = pBuf + pHead->SPUsedLen;
728         char *spEndPtr = pBuf + SP_MAX_LEN;
729         curPtr = pBuf + sizeof(SP_HEADER);
730         while (curPtr < endPtr && curPtr < spEndPtr)
731         {
732             pToken = (PSP_TOKEN) curPtr;
733             if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
734             {
735                 if (pToken->tokenLen == bufLen) // overwirte it
736                 {
737                     memcpy((curPtr+sizeof(SP_TOKEN)), tokBuf, bufLen);
738                     break;
739                 }
740                 else // move later data over and put the new token at the end
741                 {
742                     memcpy((curPtr+sizeof(SP_TOKEN)), tokBuf, bufLen);  // ~~~
743                     break;
744                 }
745             }
746             else // not same token ~~~
747             {
748             }
749             // get next token
750             curPtr += sizeof(SP_TOKEN) + pToken->tokenLen;
751         } // end while
752         SPHead.SPUsedLen = sizeof(SP_HEADER) + sizeof(SP_TOKEN) + bufLen; // ~~~
753         if (SPHead.SPUsedLen > SP_MAX_LEN)
754         {
755             printk("No more Scratch pad space left! Over limit by %d bytes\n", SPHead.SPUsedLen - SP_MAX_LEN);
756             return sts;
757         }
758
759     } // else if not new sp
760
761     sts = setSharedBlks(fInfo.flash_scratch_pad_start_blk, 
762         (fInfo.flash_scratch_pad_number_blk + fInfo.flash_scratch_pad_start_blk), pShareBuf);
763     
764     retriedKfree(pShareBuf);
765
766     return sts;
767
768     
769 }
770
771 int kerSysFlashSizeGet(void)
772 {
773    return flash_get_total_size();
774 }
775