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