linux/arch/powerpc/platforms/pseries/nvram.c
<<
>>
Prefs
   1/*
   2 *  c 2001 PPC 64 Team, IBM Corp
   3 *
   4 *      This program is free software; you can redistribute it and/or
   5 *      modify it under the terms of the GNU General Public License
   6 *      as published by the Free Software Foundation; either version
   7 *      2 of the License, or (at your option) any later version.
   8 *
   9 * /dev/nvram driver for PPC64
  10 *
  11 * This perhaps should live in drivers/char
  12 */
  13
  14
  15#include <linux/types.h>
  16#include <linux/errno.h>
  17#include <linux/init.h>
  18#include <linux/slab.h>
  19#include <linux/spinlock.h>
  20#include <asm/uaccess.h>
  21#include <asm/nvram.h>
  22#include <asm/rtas.h>
  23#include <asm/prom.h>
  24#include <asm/machdep.h>
  25
  26static unsigned int nvram_size;
  27static int nvram_fetch, nvram_store;
  28static char nvram_buf[NVRW_CNT];        /* assume this is in the first 4GB */
  29static DEFINE_SPINLOCK(nvram_lock);
  30
  31
  32static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
  33{
  34        unsigned int i;
  35        unsigned long len;
  36        int done;
  37        unsigned long flags;
  38        char *p = buf;
  39
  40
  41        if (nvram_size == 0 || nvram_fetch == RTAS_UNKNOWN_SERVICE)
  42                return -ENODEV;
  43
  44        if (*index >= nvram_size)
  45                return 0;
  46
  47        i = *index;
  48        if (i + count > nvram_size)
  49                count = nvram_size - i;
  50
  51        spin_lock_irqsave(&nvram_lock, flags);
  52
  53        for (; count != 0; count -= len) {
  54                len = count;
  55                if (len > NVRW_CNT)
  56                        len = NVRW_CNT;
  57                
  58                if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf),
  59                               len) != 0) || len != done) {
  60                        spin_unlock_irqrestore(&nvram_lock, flags);
  61                        return -EIO;
  62                }
  63                
  64                memcpy(p, nvram_buf, len);
  65
  66                p += len;
  67                i += len;
  68        }
  69
  70        spin_unlock_irqrestore(&nvram_lock, flags);
  71        
  72        *index = i;
  73        return p - buf;
  74}
  75
  76static ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index)
  77{
  78        unsigned int i;
  79        unsigned long len;
  80        int done;
  81        unsigned long flags;
  82        const char *p = buf;
  83
  84        if (nvram_size == 0 || nvram_store == RTAS_UNKNOWN_SERVICE)
  85                return -ENODEV;
  86
  87        if (*index >= nvram_size)
  88                return 0;
  89
  90        i = *index;
  91        if (i + count > nvram_size)
  92                count = nvram_size - i;
  93
  94        spin_lock_irqsave(&nvram_lock, flags);
  95
  96        for (; count != 0; count -= len) {
  97                len = count;
  98                if (len > NVRW_CNT)
  99                        len = NVRW_CNT;
 100
 101                memcpy(nvram_buf, p, len);
 102
 103                if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf),
 104                               len) != 0) || len != done) {
 105                        spin_unlock_irqrestore(&nvram_lock, flags);
 106                        return -EIO;
 107                }
 108                
 109                p += len;
 110                i += len;
 111        }
 112        spin_unlock_irqrestore(&nvram_lock, flags);
 113        
 114        *index = i;
 115        return p - buf;
 116}
 117
 118static ssize_t pSeries_nvram_get_size(void)
 119{
 120        return nvram_size ? nvram_size : -ENODEV;
 121}
 122
 123int __init pSeries_nvram_init(void)
 124{
 125        struct device_node *nvram;
 126        const unsigned int *nbytes_p;
 127        unsigned int proplen;
 128
 129        nvram = of_find_node_by_type(NULL, "nvram");
 130        if (nvram == NULL)
 131                return -ENODEV;
 132
 133        nbytes_p = of_get_property(nvram, "#bytes", &proplen);
 134        if (nbytes_p == NULL || proplen != sizeof(unsigned int)) {
 135                of_node_put(nvram);
 136                return -EIO;
 137        }
 138
 139        nvram_size = *nbytes_p;
 140
 141        nvram_fetch = rtas_token("nvram-fetch");
 142        nvram_store = rtas_token("nvram-store");
 143        printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);
 144        of_node_put(nvram);
 145
 146        ppc_md.nvram_read       = pSeries_nvram_read;
 147        ppc_md.nvram_write      = pSeries_nvram_write;
 148        ppc_md.nvram_size       = pSeries_nvram_get_size;
 149
 150        return 0;
 151}
 152