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