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