source: src/linux/universal/linux-4.9/arch/arm/plat-brcm/nvram_linux.c @ 31574

Last change on this file since 31574 was 31574, checked in by brainslayer, 5 months ago

kernel 4.9 update

File size: 23.7 KB
Line 
1/*
2 * NVRAM variable manipulation (Linux kernel half)
3 *
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: nvram_linux.c,v 1.10 2010-09-17 04:51:19 $
19 */
20
21#include <linux/version.h>
22
23#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
24#include <linux/config.h>
25#endif
26
27#include <linux/init.h>
28#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/string.h>
31#include <linux/interrupt.h>
32#include <linux/spinlock.h>
33#include <linux/slab.h>
34#include <linux/bootmem.h>
35#include <linux/fs.h>
36#include <linux/miscdevice.h>
37#include <linux/mtd/mtd.h>
38#include <linux/vmalloc.h>
39
40#include <typedefs.h>
41#include <bcmendian.h>
42#include <bcmnvram.h>
43#include <bcmutils.h>
44#include <bcmdefs.h>
45#include <hndsoc.h>
46#include <siutils.h>
47#include <hndmips.h>
48#include <hndsflash.h>
49#ifdef CONFIG_MTD_NFLASH
50#include <nflash.h>
51#endif
52
53int nvram_space = 0x10000;
54
55/* Temp buffer to hold the nvram transfered romboot CFE */
56char __initdata ram_nvram_buf[MAX_NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
57
58/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
59static char nvram_buf[MAX_NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
60static bool nvram_inram = FALSE;
61
62#ifdef MODULE
63
64#define early_nvram_get(name) nvram_get(name)
65
66#else /* !MODULE */
67
68static char *early_nvram_get(const char *name);
69
70/* Global SB handle */
71extern si_t *bcm947xx_sih;
72extern spinlock_t bcm947xx_sih_lock;
73
74/* Convenience */
75#define sih bcm947xx_sih
76#define sih_lock bcm947xx_sih_lock
77#define KB * 1024
78#define MB * 1024 * 1024
79
80#ifndef MAX_MTD_DEVICES
81#define MAX_MTD_DEVICES 32
82#endif
83
84
85void *MMALLOC(size_t size)
86{
87        void *ptr = kmalloc(size, GFP_ATOMIC);
88        if (!ptr)
89                ptr = vmalloc(size);
90        return ptr;
91}
92
93void MMFREE(void *ptr)
94{
95        if (is_vmalloc_addr(ptr))
96                vfree(ptr);
97        else
98                kfree(ptr);
99}
100
101static struct resource norflash_region = {
102        .name = "norflash",
103        .start = 0x1E000000,
104        .end =  0x1FFFFFFF,
105        .flags = IORESOURCE_MEM,
106};
107
108static int remap_cfe=0;
109#ifdef CONFIG_MTD_NFLASH
110static unsigned char nflash_nvh[MAX_NVRAM_SPACE];
111
112static struct nvram_header *
113BCMINITFN(nand_find_nvram)(hndnand_t *nfl, uint32 off)
114{
115        int blocksize = nfl->blocksize;
116        unsigned char *buf = nflash_nvh;
117        int rlen = sizeof(nflash_nvh);
118        int len;
119
120        for (; off < NFL_BOOT_SIZE; off += blocksize) {
121                if (hndnand_checkbadb(nfl, off) != 0)
122                        continue;
123
124                len = blocksize;
125                if (len >= rlen)
126                        len = rlen;
127
128                if (hndnand_read(nfl, off, len, buf) == 0)
129                        break;
130
131                buf += len;
132                rlen -= len;
133                if (rlen == 0)
134                        return (struct nvram_header *)nflash_nvh;
135        }
136
137        return NULL;
138}
139#endif /* CONFIG_MTD_NFLASH */
140
141/* Probe for NVRAM header */
142static int
143early_nvram_init(void)
144{
145        struct nvram_header *header;
146        int i;
147        u32 *src, *dst;
148#ifdef CONFIG_MTD_NFLASH
149        hndnand_t *nfl_info = NULL;
150        uint32 blocksize;
151#endif
152        char *nvram_space_str;
153        int bootdev;
154        uint32 flash_base;
155        uint32 lim = SI_FLASH_WINDOW;
156        uint32 off;
157        hndsflash_t *sfl_info;
158
159        header = (struct nvram_header *)ram_nvram_buf;
160        if (header->magic == NVRAM_MAGIC) {
161                if (nvram_calc_crc(header) == (uint8)header->crc_ver_init) {
162                        nvram_inram = TRUE;
163                        goto found;
164                }
165        }
166        bootdev = soc_boot_dev((void *)sih);
167#ifdef CONFIG_MTD_NFLASH
168        if (bootdev == SOC_BOOTDEV_NANDFLASH) {
169                if ((nfl_info = hndnand_init(sih)) == NULL)
170                        return -1;
171                flash_base = nfl_info->base;
172                blocksize = nfl_info->blocksize;
173                off = blocksize;
174                for (; off < NFL_BOOT_SIZE; off += blocksize) {
175                        if (hndnand_checkbadb(nfl_info, off) != 0)
176                                continue;
177                        header = (struct nvram_header *)(flash_base + off);
178                        if (header->magic != NVRAM_MAGIC)
179                                continue;
180
181                        /* Read into the nand_nvram */
182                        if ((header = nand_find_nvram(nfl_info, off)) == NULL)
183                                continue;
184                        if (nvram_calc_crc(header) == (uint8)header->crc_ver_init)
185                        {
186                                printk(KERN_INFO "found nand nvram at %X\n",off);
187                                goto found;
188                        }
189                }
190        }
191        else
192#endif
193        if (bootdev == SOC_BOOTDEV_SFLASH ||
194            bootdev == SOC_BOOTDEV_ROM) {
195                /* Boot from SFLASH or ROM */
196                if ((sfl_info = hndsflash_init(sih)) == NULL)
197                        return -1;
198
199                lim = sfl_info->size;
200
201                BUG_ON(request_resource(&iomem_resource, &norflash_region));
202       
203                flash_base = sfl_info->base;
204       
205                BUG_ON(IS_ERR_OR_NULL((void *)flash_base));
206               
207                off = FLASH_MIN;
208                while (off <= lim) {
209                        /* Windowed flash access */
210                        header = (struct nvram_header *)(flash_base + off - (nvram_space*2));
211                        if (header->magic == NVRAM_MAGIC)
212                                if (nvram_calc_crc(header) == (uint8)header->crc_ver_init) {
213                                        printk(KERN_INFO "found remapped nvram on sflash\n");
214                                        remap_cfe=0;
215                                        goto found;
216                                }
217
218                        header = (struct nvram_header *)(flash_base + off - nvram_space);
219                        if (header->magic == NVRAM_MAGIC)
220                                if (nvram_calc_crc(header) == (uint8)header->crc_ver_init) {
221                                        printk(KERN_INFO "found cfe nvram on sflash\n");
222                                        remap_cfe=1;
223                                        goto found;
224                                }
225                       
226                        off += 0x10000;
227                }
228        }
229        else {
230                /* This is the case bootdev == SOC_BOOTDEV_PFLASH, not applied on NorthStar */
231                ASSERT(0);
232        }
233
234        /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
235        header = (struct nvram_header *)(flash_base + 4 KB);
236        if (header->magic == NVRAM_MAGIC)
237                if (nvram_calc_crc(header) == (uint8)header->crc_ver_init) {
238                        goto found;
239                }
240
241        header = (struct nvram_header *)(flash_base + 1 KB);
242        if (header->magic == NVRAM_MAGIC)
243                if (nvram_calc_crc(header) == (uint8)header->crc_ver_init) {
244                        goto found;
245                }
246
247        return -1;
248
249found:
250        src = (u32 *)header;
251        dst = (u32 *)nvram_buf;
252        for (i = 0; i < sizeof(struct nvram_header); i += 4)
253                *dst++ = *src++;
254        for (; i < header->len && i < MAX_NVRAM_SPACE; i += 4)
255                *dst++ = ltoh32(*src++);
256
257        nvram_space_str = early_nvram_get("nvram_space");
258        if (nvram_space_str)
259                nvram_space = bcm_strtoul(nvram_space_str, NULL, 0);
260
261        return 0;
262}
263
264/* Early (before mm or mtd) read-only access to NVRAM */
265static char *
266early_nvram_get(const char *name)
267{
268        char *var, *value, *end, *eq;
269
270        if (!name)
271                return NULL;
272
273        /* Too early? */
274        if (sih == NULL)
275                return NULL;
276
277        if (!nvram_buf[0])
278                if (early_nvram_init() != 0) {
279                        printk("early_nvram_get: Failed reading nvram var %s\n", name);
280                        return NULL;
281                }
282
283        /* Look for name=value and return value */
284        var = &nvram_buf[sizeof(struct nvram_header)];
285        end = nvram_buf + sizeof(nvram_buf) - 2;
286        end[0] = end[1] = '\0';
287        for (; *var; var = value + strlen(value) + 1) {
288                if (!(eq = strchr(var, '=')))
289                        break;
290                value = eq + 1;
291                if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
292                        return value;
293        }
294
295        return NULL;
296}
297
298static int
299early_nvram_getall(char *buf, int count)
300{
301        char *var, *end;
302        int len = 0;
303
304        /* Too early? */
305        if (sih == NULL)
306                return -1;
307
308        if (!nvram_buf[0])
309                if (early_nvram_init() != 0) {
310                        printk("early_nvram_getall: Failed reading nvram var\n");
311                        return -1;
312                }
313
314        bzero(buf, count);
315
316        /* Write name=value\0 ... \0\0 */
317        var = &nvram_buf[sizeof(struct nvram_header)];
318        end = nvram_buf + sizeof(nvram_buf) - 2;
319        end[0] = end[1] = '\0';
320        for (; *var; var += strlen(var) + 1) {
321                if ((count - len) <= (strlen(var) + 1))
322                        break;
323                len += sprintf(buf + len, "%s", var) + 1;
324        }
325
326        return 0;
327}
328#endif /* !MODULE */
329
330extern char * _nvram_get(const char *name);
331extern int _nvram_set(const char *name, const char *value);
332extern int _nvram_unset(const char *name);
333extern int _nvram_getall(char *buf, int count);
334extern int _nvram_commit(struct nvram_header *header);
335extern int _nvram_init(si_t *sih);
336extern void _nvram_exit(void);
337
338/* Globals */
339DEFINE_SPINLOCK(nvram_lock);
340static struct mutex nvram_sem;
341static unsigned long nvram_offset = 0;
342static int nvram_major = -1;
343static struct class *nvram_class = NULL;
344static struct mtd_info *nvram_mtd = NULL;
345
346int
347_nvram_read(char *buf)
348{
349        struct nvram_header *header = (struct nvram_header *) buf;
350        size_t len;
351        int offset = 0;
352
353        if (nvram_mtd) {
354#ifdef CONFIG_MTD_NFLASH
355                if (nvram_mtd->type == MTD_NANDFLASH)
356                        offset = 0;
357                else
358#endif
359                        offset = nvram_mtd->size - nvram_space;
360        }
361        printk(KERN_INFO "read %d bytes to offset %d\n",nvram_space, offset);
362        if (nvram_inram || !nvram_mtd ||
363            mtd_read(nvram_mtd, offset, nvram_space, &len, buf) ||
364            len != nvram_space ||
365            header->magic != NVRAM_MAGIC) {
366                /* Maybe we can recover some data from early initialization */
367                if (nvram_inram)
368                        printk("Sourcing NVRAM from ram\n");
369                memcpy(buf, nvram_buf, nvram_space);
370        }
371
372        return 0;
373}
374
375struct nvram_tuple *
376_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
377{
378        if ((nvram_offset + strlen(value) + 1) > nvram_space)
379                return NULL;
380
381        if (!t) {
382                if (!(t = MMALLOC(sizeof(struct nvram_tuple) + strlen(name) + 1)))
383                        return NULL;
384
385                /* Copy name */
386                t->name = (char *) &t[1];
387                strcpy(t->name, name);
388
389                t->value = NULL;
390        }
391
392        /* Copy value */
393        if (t->value == NULL || strlen(t->value) < strlen(value)) {
394                /* Alloc value space */
395                t->value = &nvram_buf[nvram_offset];
396                strcpy(t->value, value);
397                nvram_offset += strlen(value) + 1;
398        } else if( 0 != strcmp(t->value, value)) {
399                /* In place */
400                strcpy(t->value, value);
401        }
402
403        return t;
404}
405
406void
407_nvram_free(struct nvram_tuple *t)
408{
409        if (!t) {
410                nvram_offset = 0;
411                memset( nvram_buf, 0, sizeof(nvram_buf) );
412        } else {
413                MMFREE(t);
414        }
415}
416
417int
418nvram_init(void *sih)
419{
420        return 0;
421}
422
423int
424nvram_set(const char *name, const char *value)
425{
426        unsigned long flags;
427        int ret;
428        struct nvram_header *header;
429
430        spin_lock_irqsave(&nvram_lock, flags);
431        if ((ret = _nvram_set(name, value))) {
432                printk( KERN_INFO "nvram: consolidating space!\n");
433                /* Consolidate space and try again */
434                if ((header = MMALLOC(nvram_space))) {
435                        if (_nvram_commit(header) == 0)
436                                ret = _nvram_set(name, value);
437                        MMFREE(header);
438                }
439        }
440        spin_unlock_irqrestore(&nvram_lock, flags);
441
442        return ret;
443}
444
445char *
446real_nvram_get(const char *name)
447{
448        unsigned long flags;
449        char *value;
450
451        spin_lock_irqsave(&nvram_lock, flags);
452        value = _nvram_get(name);
453        spin_unlock_irqrestore(&nvram_lock, flags);
454
455        return value;
456}
457
458char *
459nvram_get(const char *name)
460{
461        if (nvram_major >= 0)
462                return real_nvram_get(name);
463        else
464                return early_nvram_get(name);
465}
466
467int
468nvram_unset(const char *name)
469{
470        unsigned long flags;
471        int ret;
472
473        spin_lock_irqsave(&nvram_lock, flags);
474        ret = _nvram_unset(name);
475        spin_unlock_irqrestore(&nvram_lock, flags);
476
477        return ret;
478}
479
480static void
481erase_callback(struct erase_info *done)
482{
483        wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
484        wake_up(wait_q);
485}
486
487#ifdef CONFIG_MTD_NFLASH
488int
489nvram_nflash_commit(void)
490{
491        char *buf;
492        size_t len;
493        unsigned int i;
494        int ret;
495        struct nvram_header *header;
496        unsigned long flags;
497        u_int32_t offset;
498
499        if (!(buf = MMALLOC(nvram_space))) {
500                printk(KERN_WARNING "nvram_commit: out of memory\n");
501                return -ENOMEM;
502        }
503
504        mutex_lock(&nvram_sem);
505
506        offset = 0;
507        header = (struct nvram_header *)buf;
508        header->magic = NVRAM_MAGIC;
509        /* reset MAGIC before we regenerate the NVRAM,
510         * otherwise we'll have an incorrect CRC
511         */
512        /* Regenerate NVRAM */
513        spin_lock_irqsave(&nvram_lock, flags);
514        ret = _nvram_commit(header);
515        spin_unlock_irqrestore(&nvram_lock, flags);
516        if (ret)
517                goto done;
518
519        /* Write partition up to end of data area */
520        i = header->len;
521        ret = mtd_write(nvram_mtd, offset, i, &len, buf);
522        if (ret || len != i) {
523                printk(KERN_WARNING "nvram_commit: write error\n");
524                ret = -EIO;
525                goto done;
526        }
527
528done:
529        mutex_unlock(&nvram_sem);
530        MMFREE(buf);
531        return ret;
532}
533#endif
534
535int
536nvram_commit(void)
537{
538        char *buf;
539        size_t erasesize, len, magic_len;
540        unsigned int i;
541        int ret;
542        struct nvram_header *header;
543        unsigned long flags;
544        u_int32_t offset;
545        DECLARE_WAITQUEUE(wait, current);
546        wait_queue_head_t wait_q;
547        struct erase_info erase;
548        u_int32_t magic_offset = 0; /* Offset for writing MAGIC # */
549
550        if (!nvram_mtd) {
551                printk(KERN_ERR "nvram_commit: NVRAM not found\n");
552                return -ENODEV;
553        }
554
555        if (in_interrupt()) {
556                printk(KERN_WARNING "nvram_commit: not committing in interrupt\n");
557                return -EINVAL;
558        }
559
560#ifdef CONFIG_MTD_NFLASH
561        if (nvram_mtd->type == MTD_NANDFLASH)
562                return nvram_nflash_commit();
563#endif
564        /* Backup sector blocks to be erased */
565        erasesize = ROUNDUP(nvram_space, nvram_mtd->erasesize);
566        if (!(buf = MMALLOC(erasesize))) {
567                printk(KERN_WARNING "nvram_commit: out of memory\n");
568                return -ENOMEM;
569        }
570
571        mutex_lock(&nvram_sem);
572
573        if ((i = erasesize - nvram_space) > 0) {
574                offset = nvram_mtd->size - erasesize;
575                len = 0;
576                ret = mtd_read(nvram_mtd, offset, i, &len, buf);
577                if (ret || len != i) {
578                        printk(KERN_ERR "nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
579                        ret = -EIO;
580                        goto done;
581                }
582                header = (struct nvram_header *)(buf + i);
583                magic_offset = i + ((void *)&header->magic - (void *)header);
584        } else {
585                offset = nvram_mtd->size - nvram_space;
586                header = (struct nvram_header *)buf;
587                magic_offset = ((void *)&header->magic - (void *)header);
588        }
589
590        /* clear the existing magic # to mark the NVRAM as unusable
591         * we can pull MAGIC bits low without erase
592         */
593        header->magic = NVRAM_CLEAR_MAGIC; /* All zeros magic */
594        /* Unlock sector blocks */
595        mtd_unlock(nvram_mtd, offset, nvram_mtd->erasesize);
596        ret = mtd_write(nvram_mtd, offset + magic_offset, sizeof(header->magic),
597                &magic_len, (char *)&header->magic);
598        if (ret || magic_len != sizeof(header->magic)) {
599                printk(KERN_ERR "nvram_commit: clear MAGIC error\n");
600                ret = -EIO;
601                goto done;
602        }
603
604        header->magic = NVRAM_MAGIC;
605        /* reset MAGIC before we regenerate the NVRAM,
606         * otherwise we'll have an incorrect CRC
607         */
608        /* Regenerate NVRAM */
609        spin_lock_irqsave(&nvram_lock, flags);
610        ret = _nvram_commit(header);
611        spin_unlock_irqrestore(&nvram_lock, flags);
612        if (ret)
613                goto done;
614
615        /* Erase sector blocks */
616        init_waitqueue_head(&wait_q);
617        for (; offset < nvram_mtd->size - nvram_space + header->len;
618                offset += nvram_mtd->erasesize) {
619
620                erase.mtd = nvram_mtd;
621                erase.addr = offset;
622                erase.len = nvram_mtd->erasesize;
623                erase.callback = erase_callback;
624                erase.priv = (u_long) &wait_q;
625
626                set_current_state(TASK_INTERRUPTIBLE);
627                add_wait_queue(&wait_q, &wait);
628
629                /* Unlock sector blocks */
630                mtd_unlock(nvram_mtd, offset, nvram_mtd->erasesize);
631
632                if ((ret = mtd_erase(nvram_mtd, &erase))) {
633                        set_current_state(TASK_RUNNING);
634                        remove_wait_queue(&wait_q, &wait);
635                        printk(KERN_ERR "nvram_commit: erase error\n");
636                        goto done;
637                }
638
639                /* Wait for erase to finish */
640                schedule();
641                remove_wait_queue(&wait_q, &wait);
642        }
643
644        /* Write partition up to end of data area */
645        header->magic = NVRAM_INVALID_MAGIC; /* All ones magic */
646        offset = nvram_mtd->size - erasesize;
647        i = erasesize - nvram_space + header->len;
648        ret = mtd_write(nvram_mtd, offset, i, &len, buf);
649        if (ret || len != i) {
650                printk(KERN_ERR "nvram_commit: write error\n");
651                ret = -EIO;
652                goto done;
653        }
654
655        /* Now mark the NVRAM in flash as "valid" by setting the correct
656         * MAGIC #
657         */
658        header->magic = NVRAM_MAGIC;
659        ret = mtd_write(nvram_mtd, offset + magic_offset, sizeof(header->magic),
660                &magic_len, (char *)&header->magic);
661        if (ret || magic_len != sizeof(header->magic)) {
662                printk(KERN_ERR "nvram_commit: write MAGIC error\n");
663                ret = -EIO;
664                goto done;
665        }
666
667        offset = nvram_mtd->size - erasesize;
668        ret = mtd_read(nvram_mtd, offset, 4, &len, buf);
669
670done:
671        mutex_unlock(&nvram_sem);
672        MMFREE(buf);
673        return ret;
674}
675
676int
677nvram_getall(char *buf, int count)
678{
679        unsigned long flags;
680        int ret;
681
682        spin_lock_irqsave(&nvram_lock, flags);
683        if (nvram_major >= 0)
684                ret = _nvram_getall(buf, count);
685        else
686                ret = early_nvram_getall(buf, count);
687        spin_unlock_irqrestore(&nvram_lock, flags);
688
689        return ret;
690}
691
692EXPORT_SYMBOL(nvram_init);
693EXPORT_SYMBOL(nvram_get);
694EXPORT_SYMBOL(nvram_getall);
695EXPORT_SYMBOL(nvram_set);
696EXPORT_SYMBOL(nvram_unset);
697EXPORT_SYMBOL(nvram_commit);
698
699/* User mode interface below */
700
701static ssize_t
702dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
703{
704        char tmp[100], *name = tmp, *value;
705        ssize_t ret;
706        unsigned long off;
707
708        if ((count+1) > sizeof(tmp)) {
709                if (!(name = MMALLOC(count+1)))
710                        return -ENOMEM;
711        }
712
713        if (copy_from_user(name, buf, count)) {
714                ret = -EFAULT;
715                goto done;
716        }
717        name[count] = '\0';
718
719        if (*name == '\0') {
720                /* Get all variables */
721                ret = nvram_getall(name, count);
722                if (ret == 0) {
723                        if (copy_to_user(buf, name, count)) {
724                                ret = -EFAULT;
725                                goto done;
726                        }
727                        ret = count;
728                }
729        } else {
730                if (!(value = nvram_get(name))) {
731                        ret = 0;
732                        goto done;
733                }
734
735                /* Provide the offset into mmap() space */
736                off = (unsigned long) value - (unsigned long) nvram_buf;
737
738                if (copy_to_user(buf, &off, ret = sizeof(off))) {
739                        ret = -EFAULT;
740                        goto done;
741                }
742        }
743#ifdef  _DEPRECATED
744        flush_cache_all();
745#endif
746done:
747        if (name != tmp)
748                MMFREE(name);
749
750        return ret;
751}
752
753static ssize_t
754dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
755{
756        char tmp[100], *name = tmp, *value;
757        ssize_t ret;
758
759        if (count >= sizeof(tmp)) {
760                if (!(name = MMALLOC(count+1)))
761                        return -ENOMEM;
762        }
763
764        if (copy_from_user(name, buf, count)) {
765                ret = -EFAULT;
766                goto done;
767        }
768        name[ count ] = '\0';
769        value = name;
770        name = strsep(&value, "=");
771        if (value)
772                ret = nvram_set(name, value) ;
773        else
774                ret = nvram_unset(name) ;
775
776        if( 0 == ret )
777                ret = count;
778done:
779        if (name != tmp)
780                MMFREE(name);
781
782        return ret;
783}
784
785#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
786static int
787#else
788static long
789#endif
790dev_nvram_ioctl(
791#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
792        struct inode *inode,
793#endif
794        struct file *file,
795        unsigned int cmd,
796        unsigned long arg)
797{
798        if (cmd != NVRAM_MAGIC)
799                return -EINVAL;
800        return nvram_commit();
801}
802
803static int
804dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
805{
806        unsigned long offset = virt_to_phys(nvram_buf);
807        if (remap_pfn_range(vma,vma->vm_start, offset>>PAGE_SHIFT, vma->vm_end-vma->vm_start,
808                             vma->vm_page_prot))
809                {
810                return -EAGAIN;
811                }
812
813        return 0;
814}
815
816static int
817dev_nvram_open(struct inode *inode, struct file * file)
818{
819        return 0;
820}
821
822static int
823dev_nvram_release(struct inode *inode, struct file * file)
824{
825        return 0;
826}
827
828static struct file_operations dev_nvram_fops = {
829        owner:          THIS_MODULE,
830        open:           dev_nvram_open,
831        release:        dev_nvram_release,
832        read:           dev_nvram_read,
833        write:          dev_nvram_write,
834#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
835        ioctl:          dev_nvram_ioctl,
836#else
837        unlocked_ioctl: dev_nvram_ioctl,
838#endif
839        mmap:           dev_nvram_mmap
840};
841
842static void
843dev_nvram_exit(void)
844{
845        int order = 0;
846        struct page *page, *end;
847
848        if (nvram_class) {
849#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
850                class_device_destroy(nvram_class, MKDEV(nvram_major, 0));
851#else /* 2.6.36 and up */
852                device_destroy(nvram_class, MKDEV(nvram_major, 0));
853#endif
854                class_destroy(nvram_class);
855        }
856
857        if (nvram_major >= 0)
858                unregister_chrdev(nvram_major, "nvram");
859
860        if (nvram_mtd)
861                put_mtd_device(nvram_mtd);
862
863        while ((PAGE_SIZE << order) < MAX_NVRAM_SPACE)
864                order++;
865        end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
866        for (page = virt_to_page(nvram_buf); page <= end; page++)
867                ClearPageReserved(page);
868
869        _nvram_exit();
870}
871
872static int
873dev_nvram_init(void)
874{
875        int order = 0, ret = 0;
876        struct page *page, *end;
877        osl_t *osh;
878        struct mtd_info *nvram_mtd_cfe = NULL;
879        struct mtd_info *nvram_mtd_temp = NULL;
880        DECLARE_WAITQUEUE(wait, current);
881        wait_queue_head_t wait_q;
882        struct erase_info erase;
883        struct nvram_header *header;
884        u32 *src, *dst;
885#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
886        unsigned int i;
887#endif
888
889        /* Allocate and reserve memory to mmap() */
890        while ((PAGE_SIZE << order) < nvram_space)
891                order++;
892        end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
893        for (page = virt_to_page(nvram_buf); page <= end; page++) {
894                SetPageReserved(page);
895        }
896
897#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
898        /* Find associated MTD device */
899        for (i = 0; i < MAX_MTD_DEVICES; i++) {
900                nvram_mtd_temp = get_mtd_device(NULL, i);
901                if (!IS_ERR(nvram_mtd_temp)) {
902                        if (!strcmp(nvram_mtd_temp->name, "nvram_cfe")) {
903                                nvram_mtd_cfe = nvram_mtd_temp;
904                                printk(KERN_EMERG "found cfe nvram\n");
905                                continue;
906                        }
907                        if (!strcmp(nvram_mtd_temp->name, "nvram") && nvram_mtd_temp->size >= nvram_space) {
908                                nvram_mtd = nvram_mtd_temp;
909                                continue;
910                        }
911                        put_mtd_device(nvram_mtd_temp);
912                }
913        }
914
915        if (nvram_mtd_cfe != NULL && remap_cfe && nvram_space != 0x20000) {
916                printk(KERN_INFO "check if nvram copy is required CFE Size is %d\n", NVRAM_SPACE);
917                int len;
918                char *buf = MMALLOC(NVRAM_SPACE);
919                if (buf == NULL) {
920                        printk(KERN_ERR "mem allocation error");
921                        goto done_nofree;
922                }
923                mtd_read(nvram_mtd, nvram_mtd->erasesize - NVRAM_SPACE,NVRAM_SPACE, &len, buf);
924                header = (struct nvram_header *)buf;
925                len = 0;
926                printk(KERN_INFO "nvram copy magic is %X\n", header->magic);
927                if (header->magic != NVRAM_MAGIC) {
928                        printk(KERN_EMERG "copy cfe nvram to base nvram\n");
929                        len = 0;
930                        memset(buf, 0, NVRAM_SPACE);
931                        mtd_read(nvram_mtd_cfe, nvram_mtd_cfe->erasesize - NVRAM_SPACE, NVRAM_SPACE, &len, buf + nvram_mtd->erasesize - NVRAM_SPACE);
932                        put_mtd_device(nvram_mtd_cfe);
933                        mtd_unlock(nvram_mtd, 0, nvram_mtd->erasesize);
934                        init_waitqueue_head(&wait_q);
935                        erase.mtd = nvram_mtd;
936                        erase.addr = 0;
937                        erase.len = nvram_mtd->erasesize;
938                        erase.callback = erase_callback;
939                        erase.priv = (u_long) & wait_q;
940                        set_current_state(TASK_INTERRUPTIBLE);
941                        add_wait_queue(&wait_q, &wait);
942                        if ((ret = mtd_erase(nvram_mtd, &erase))) {
943                                set_current_state(TASK_RUNNING);
944                                remove_wait_queue(&wait_q, &wait);
945                                printk("nvram_commit: erase error\n");
946                                goto done;
947                        }
948                        /* Wait for erase to finish */
949                        schedule();
950                        remove_wait_queue(&wait_q, &wait);
951                        len = 0;
952                        printk(KERN_INFO "remap nvram %d\n", header->len);
953
954                        src = (u32 *)buf + nvram_mtd->erasesize - NVRAM_SPACE;
955                        dst = (u32 *)nvram_buf;
956                        for (i = 0; i < sizeof(struct nvram_header); i += 4)
957                                *dst++ = *src++;
958                        for (; i < header->len && i < NVRAM_SPACE; i += 4)
959                                *dst++ = ltoh32(*src++);
960
961                        mtd_write(nvram_mtd, nvram_mtd->erasesize - NVRAM_SPACE, NVRAM_SPACE, &len, buf);
962
963                      done:;
964                        MMFREE(buf);
965                      done_nofree:;
966                }
967        }
968
969
970#endif
971
972        /* Initialize hash table lock */
973        spin_lock_init(&nvram_lock);
974
975        /* Initialize commit semaphore */
976        mutex_init(&nvram_sem);
977
978        /* Register char device */
979        if ((nvram_major = register_chrdev(229, "nvram", &dev_nvram_fops)) < 0) {
980                ret = nvram_major;
981                goto err;
982        }
983
984        if (si_osh(sih) == NULL) {
985                osh = osl_attach(NULL, SI_BUS, FALSE);
986                if (osh == NULL) {
987                        printk("Error allocating osh\n");
988                        unregister_chrdev(nvram_major, "nvram");
989                        goto err;
990                }
991                si_setosh(sih, osh);
992        }
993
994        /* Initialize hash table */
995        _nvram_init(sih);
996
997        /* Create /dev/nvram handle */
998        nvram_class = class_create(THIS_MODULE, "nvram");
999        if (IS_ERR(nvram_class)) {
1000                printk("Error creating nvram class\n");
1001                goto err;
1002        }
1003
1004        /* Add the device nvram0 */
1005#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
1006        class_device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram");
1007#else /* Linux 2.6.36 and above */
1008        device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram");
1009#endif  /* Linux 2.6.36 */
1010
1011        return 0;
1012
1013err:
1014        dev_nvram_exit();
1015        return ret;
1016}
1017
1018int nvram_match(char *name, char *match)
1019{
1020        const char *value = nvram_get(name);
1021        return (value && !strcmp(value, match));
1022}
1023
1024
1025char *nvram_safe_get(const char *name)
1026{
1027        return nvram_get(name) ? : "";
1028}
1029
1030
1031/*
1032* This is not a module, and is not unloadable.
1033* Also, this module must not be initialized before
1034* the Flash MTD partitions have been set up, in case
1035* the contents are stored in Flash.
1036* Thus, late_initcall() macro is used to insert this
1037* device driver initialization later.
1038* An alternative solution would be to initialize
1039* inside the xx_open() call.
1040* -LR
1041*/
1042late_initcall(dev_nvram_init);
Note: See TracBrowser for help on using the repository browser.