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/spinlock.h>
  19#include <linux/slab.h>
  20#include <linux/ctype.h>
  21#include <asm/uaccess.h>
  22#include <asm/nvram.h>
  23#include <asm/rtas.h>
  24#include <asm/prom.h>
  25#include <asm/machdep.h>
  26
  27/* Max bytes to read/write in one go */
  28#define NVRW_CNT 0x20
  29
  30static unsigned int nvram_size;
  31static int nvram_fetch, nvram_store;
  32static char nvram_buf[NVRW_CNT];        /* assume this is in the first 4GB */
  33static DEFINE_SPINLOCK(nvram_lock);
  34
  35/* See clobbering_unread_rtas_event() */
  36#define NVRAM_RTAS_READ_TIMEOUT 5               /* seconds */
  37static time64_t last_unread_rtas_event;         /* timestamp */
  38
  39#ifdef CONFIG_PSTORE
  40time64_t last_rtas_event;
  41#endif
  42
  43static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
  44{
  45        unsigned int i;
  46        unsigned long len;
  47        int done;
  48        unsigned long flags;
  49        char *p = buf;
  50
  51
  52        if (nvram_size == 0 || nvram_fetch == RTAS_UNKNOWN_SERVICE)
  53                return -ENODEV;
  54
  55        if (*index >= nvram_size)
  56                return 0;
  57
  58        i = *index;
  59        if (i + count > nvram_size)
  60                count = nvram_size - i;
  61
  62        spin_lock_irqsave(&nvram_lock, flags);
  63
  64        for (; count != 0; count -= len) {
  65                len = count;
  66                if (len > NVRW_CNT)
  67                        len = NVRW_CNT;
  68                
  69                if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf),
  70                               len) != 0) || len != done) {
  71                        spin_unlock_irqrestore(&nvram_lock, flags);
  72                        return -EIO;
  73                }
  74                
  75                memcpy(p, nvram_buf, len);
  76
  77                p += len;
  78                i += len;
  79        }
  80
  81        spin_unlock_irqrestore(&nvram_lock, flags);
  82        
  83        *index = i;
  84        return p - buf;
  85}
  86
  87static ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index)
  88{
  89        unsigned int i;
  90        unsigned long len;
  91        int done;
  92        unsigned long flags;
  93        const char *p = buf;
  94
  95        if (nvram_size == 0 || nvram_store == RTAS_UNKNOWN_SERVICE)
  96                return -ENODEV;
  97
  98        if (*index >= nvram_size)
  99                return 0;
 100
 101        i = *index;
 102        if (i + count > nvram_size)
 103                count = nvram_size - i;
 104
 105        spin_lock_irqsave(&nvram_lock, flags);
 106
 107        for (; count != 0; count -= len) {
 108                len = count;
 109                if (len > NVRW_CNT)
 110                        len = NVRW_CNT;
 111
 112                memcpy(nvram_buf, p, len);
 113
 114                if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf),
 115                               len) != 0) || len != done) {
 116                        spin_unlock_irqrestore(&nvram_lock, flags);
 117                        return -EIO;
 118                }
 119                
 120                p += len;
 121                i += len;
 122        }
 123        spin_unlock_irqrestore(&nvram_lock, flags);
 124        
 125        *index = i;
 126        return p - buf;
 127}
 128
 129static ssize_t pSeries_nvram_get_size(void)
 130{
 131        return nvram_size ? nvram_size : -ENODEV;
 132}
 133
 134/* nvram_write_error_log
 135 *
 136 * We need to buffer the error logs into nvram to ensure that we have
 137 * the failure information to decode.
 138 */
 139int nvram_write_error_log(char * buff, int length,
 140                          unsigned int err_type, unsigned int error_log_cnt)
 141{
 142        int rc = nvram_write_os_partition(&rtas_log_partition, buff, length,
 143                                                err_type, error_log_cnt);
 144        if (!rc) {
 145                last_unread_rtas_event = ktime_get_real_seconds();
 146#ifdef CONFIG_PSTORE
 147                last_rtas_event = ktime_get_real_seconds();
 148#endif
 149        }
 150
 151        return rc;
 152}
 153
 154/* nvram_read_error_log
 155 *
 156 * Reads nvram for error log for at most 'length'
 157 */
 158int nvram_read_error_log(char *buff, int length,
 159                        unsigned int *err_type, unsigned int *error_log_cnt)
 160{
 161        return nvram_read_partition(&rtas_log_partition, buff, length,
 162                                                err_type, error_log_cnt);
 163}
 164
 165/* This doesn't actually zero anything, but it sets the event_logged
 166 * word to tell that this event is safely in syslog.
 167 */
 168int nvram_clear_error_log(void)
 169{
 170        loff_t tmp_index;
 171        int clear_word = ERR_FLAG_ALREADY_LOGGED;
 172        int rc;
 173
 174        if (rtas_log_partition.index == -1)
 175                return -1;
 176
 177        tmp_index = rtas_log_partition.index;
 178        
 179        rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
 180        if (rc <= 0) {
 181                printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
 182                return rc;
 183        }
 184        last_unread_rtas_event = 0;
 185
 186        return 0;
 187}
 188
 189/*
 190 * Are we using the ibm,rtas-log for oops/panic reports?  And if so,
 191 * would logging this oops/panic overwrite an RTAS event that rtas_errd
 192 * hasn't had a chance to read and process?  Return 1 if so, else 0.
 193 *
 194 * We assume that if rtas_errd hasn't read the RTAS event in
 195 * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
 196 */
 197int clobbering_unread_rtas_event(void)
 198{
 199        return (oops_log_partition.index == rtas_log_partition.index
 200                && last_unread_rtas_event
 201                && ktime_get_real_seconds() - last_unread_rtas_event <=
 202                                                NVRAM_RTAS_READ_TIMEOUT);
 203}
 204
 205static int __init pseries_nvram_init_log_partitions(void)
 206{
 207        int rc;
 208
 209        /* Scan nvram for partitions */
 210        nvram_scan_partitions();
 211
 212        rc = nvram_init_os_partition(&rtas_log_partition);
 213        nvram_init_oops_partition(rc == 0);
 214        return 0;
 215}
 216machine_arch_initcall(pseries, pseries_nvram_init_log_partitions);
 217
 218int __init pSeries_nvram_init(void)
 219{
 220        struct device_node *nvram;
 221        const __be32 *nbytes_p;
 222        unsigned int proplen;
 223
 224        nvram = of_find_node_by_type(NULL, "nvram");
 225        if (nvram == NULL)
 226                return -ENODEV;
 227
 228        nbytes_p = of_get_property(nvram, "#bytes", &proplen);
 229        if (nbytes_p == NULL || proplen != sizeof(unsigned int)) {
 230                of_node_put(nvram);
 231                return -EIO;
 232        }
 233
 234        nvram_size = be32_to_cpup(nbytes_p);
 235
 236        nvram_fetch = rtas_token("nvram-fetch");
 237        nvram_store = rtas_token("nvram-store");
 238        printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);
 239        of_node_put(nvram);
 240
 241        ppc_md.nvram_read       = pSeries_nvram_read;
 242        ppc_md.nvram_write      = pSeries_nvram_write;
 243        ppc_md.nvram_size       = pSeries_nvram_get_size;
 244
 245        return 0;
 246}
 247
 248