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