Path: blob/master/arch/powerpc/platforms/pseries/nvram.c
10818 views
/*1* c 2001 PPC 64 Team, IBM Corp2*3* This program is free software; you can redistribute it and/or4* modify it under the terms of the GNU General Public License5* as published by the Free Software Foundation; either version6* 2 of the License, or (at your option) any later version.7*8* /dev/nvram driver for PPC649*10* This perhaps should live in drivers/char11*/121314#include <linux/types.h>15#include <linux/errno.h>16#include <linux/init.h>17#include <linux/spinlock.h>18#include <linux/slab.h>19#include <linux/kmsg_dump.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>2526/* Max bytes to read/write in one go */27#define NVRW_CNT 0x202829static unsigned int nvram_size;30static int nvram_fetch, nvram_store;31static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */32static DEFINE_SPINLOCK(nvram_lock);3334struct err_log_info {35int error_type;36unsigned int seq_num;37};3839struct nvram_os_partition {40const char *name;41int req_size; /* desired size, in bytes */42int min_size; /* minimum acceptable size (0 means req_size) */43long size; /* size of data portion (excluding err_log_info) */44long index; /* offset of data portion of partition */45};4647static struct nvram_os_partition rtas_log_partition = {48.name = "ibm,rtas-log",49.req_size = 2079,50.min_size = 1055,51.index = -152};5354static struct nvram_os_partition oops_log_partition = {55.name = "lnx,oops-log",56.req_size = 4000,57.min_size = 2000,58.index = -159};6061static const char *pseries_nvram_os_partitions[] = {62"ibm,rtas-log",63"lnx,oops-log",64NULL65};6667static void oops_to_nvram(struct kmsg_dumper *dumper,68enum kmsg_dump_reason reason,69const char *old_msgs, unsigned long old_len,70const char *new_msgs, unsigned long new_len);7172static struct kmsg_dumper nvram_kmsg_dumper = {73.dump = oops_to_nvram74};7576/* See clobbering_unread_rtas_event() */77#define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */78static unsigned long last_unread_rtas_event; /* timestamp */7980/* We preallocate oops_buf during init to avoid kmalloc during oops/panic. */81static char *oops_buf;8283static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)84{85unsigned int i;86unsigned long len;87int done;88unsigned long flags;89char *p = buf;909192if (nvram_size == 0 || nvram_fetch == RTAS_UNKNOWN_SERVICE)93return -ENODEV;9495if (*index >= nvram_size)96return 0;9798i = *index;99if (i + count > nvram_size)100count = nvram_size - i;101102spin_lock_irqsave(&nvram_lock, flags);103104for (; count != 0; count -= len) {105len = count;106if (len > NVRW_CNT)107len = NVRW_CNT;108109if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf),110len) != 0) || len != done) {111spin_unlock_irqrestore(&nvram_lock, flags);112return -EIO;113}114115memcpy(p, nvram_buf, len);116117p += len;118i += len;119}120121spin_unlock_irqrestore(&nvram_lock, flags);122123*index = i;124return p - buf;125}126127static ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index)128{129unsigned int i;130unsigned long len;131int done;132unsigned long flags;133const char *p = buf;134135if (nvram_size == 0 || nvram_store == RTAS_UNKNOWN_SERVICE)136return -ENODEV;137138if (*index >= nvram_size)139return 0;140141i = *index;142if (i + count > nvram_size)143count = nvram_size - i;144145spin_lock_irqsave(&nvram_lock, flags);146147for (; count != 0; count -= len) {148len = count;149if (len > NVRW_CNT)150len = NVRW_CNT;151152memcpy(nvram_buf, p, len);153154if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf),155len) != 0) || len != done) {156spin_unlock_irqrestore(&nvram_lock, flags);157return -EIO;158}159160p += len;161i += len;162}163spin_unlock_irqrestore(&nvram_lock, flags);164165*index = i;166return p - buf;167}168169static ssize_t pSeries_nvram_get_size(void)170{171return nvram_size ? nvram_size : -ENODEV;172}173174175/* nvram_write_os_partition, nvram_write_error_log176*177* We need to buffer the error logs into nvram to ensure that we have178* the failure information to decode. If we have a severe error there179* is no way to guarantee that the OS or the machine is in a state to180* get back to user land and write the error to disk. For example if181* the SCSI device driver causes a Machine Check by writing to a bad182* IO address, there is no way of guaranteeing that the device driver183* is in any state that is would also be able to write the error data184* captured to disk, thus we buffer it in NVRAM for analysis on the185* next boot.186*187* In NVRAM the partition containing the error log buffer will looks like:188* Header (in bytes):189* +-----------+----------+--------+------------+------------------+190* | signature | checksum | length | name | data |191* |0 |1 |2 3|4 15|16 length-1|192* +-----------+----------+--------+------------+------------------+193*194* The 'data' section would look like (in bytes):195* +--------------+------------+-----------------------------------+196* | event_logged | sequence # | error log |197* |0 3|4 7|8 error_log_size-1|198* +--------------+------------+-----------------------------------+199*200* event_logged: 0 if event has not been logged to syslog, 1 if it has201* sequence #: The unique sequence # for each event. (until it wraps)202* error log: The error log from event_scan203*/204int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,205int length, unsigned int err_type, unsigned int error_log_cnt)206{207int rc;208loff_t tmp_index;209struct err_log_info info;210211if (part->index == -1) {212return -ESPIPE;213}214215if (length > part->size) {216length = part->size;217}218219info.error_type = err_type;220info.seq_num = error_log_cnt;221222tmp_index = part->index;223224rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);225if (rc <= 0) {226pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);227return rc;228}229230rc = ppc_md.nvram_write(buff, length, &tmp_index);231if (rc <= 0) {232pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);233return rc;234}235236return 0;237}238239int nvram_write_error_log(char * buff, int length,240unsigned int err_type, unsigned int error_log_cnt)241{242int rc = nvram_write_os_partition(&rtas_log_partition, buff, length,243err_type, error_log_cnt);244if (!rc)245last_unread_rtas_event = get_seconds();246return rc;247}248249/* nvram_read_error_log250*251* Reads nvram for error log for at most 'length'252*/253int nvram_read_error_log(char * buff, int length,254unsigned int * err_type, unsigned int * error_log_cnt)255{256int rc;257loff_t tmp_index;258struct err_log_info info;259260if (rtas_log_partition.index == -1)261return -1;262263if (length > rtas_log_partition.size)264length = rtas_log_partition.size;265266tmp_index = rtas_log_partition.index;267268rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);269if (rc <= 0) {270printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);271return rc;272}273274rc = ppc_md.nvram_read(buff, length, &tmp_index);275if (rc <= 0) {276printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);277return rc;278}279280*error_log_cnt = info.seq_num;281*err_type = info.error_type;282283return 0;284}285286/* This doesn't actually zero anything, but it sets the event_logged287* word to tell that this event is safely in syslog.288*/289int nvram_clear_error_log(void)290{291loff_t tmp_index;292int clear_word = ERR_FLAG_ALREADY_LOGGED;293int rc;294295if (rtas_log_partition.index == -1)296return -1;297298tmp_index = rtas_log_partition.index;299300rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);301if (rc <= 0) {302printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);303return rc;304}305last_unread_rtas_event = 0;306307return 0;308}309310/* pseries_nvram_init_os_partition311*312* This sets up a partition with an "OS" signature.313*314* The general strategy is the following:315* 1.) If a partition with the indicated name already exists...316* - If it's large enough, use it.317* - Otherwise, recycle it and keep going.318* 2.) Search for a free partition that is large enough.319* 3.) If there's not a free partition large enough, recycle any obsolete320* OS partitions and try again.321* 4.) Will first try getting a chunk that will satisfy the requested size.322* 5.) If a chunk of the requested size cannot be allocated, then try finding323* a chunk that will satisfy the minum needed.324*325* Returns 0 on success, else -1.326*/327static int __init pseries_nvram_init_os_partition(struct nvram_os_partition328*part)329{330loff_t p;331int size;332333/* Scan nvram for partitions */334nvram_scan_partitions();335336/* Look for ours */337p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);338339/* Found one but too small, remove it */340if (p && size < part->min_size) {341pr_info("nvram: Found too small %s partition,"342" removing it...\n", part->name);343nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);344p = 0;345}346347/* Create one if we didn't find */348if (!p) {349p = nvram_create_partition(part->name, NVRAM_SIG_OS,350part->req_size, part->min_size);351if (p == -ENOSPC) {352pr_info("nvram: No room to create %s partition, "353"deleting any obsolete OS partitions...\n",354part->name);355nvram_remove_partition(NULL, NVRAM_SIG_OS,356pseries_nvram_os_partitions);357p = nvram_create_partition(part->name, NVRAM_SIG_OS,358part->req_size, part->min_size);359}360}361362if (p <= 0) {363pr_err("nvram: Failed to find or create %s"364" partition, err %d\n", part->name, (int)p);365return -1;366}367368part->index = p;369part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);370371return 0;372}373374static void __init nvram_init_oops_partition(int rtas_partition_exists)375{376int rc;377378rc = pseries_nvram_init_os_partition(&oops_log_partition);379if (rc != 0) {380if (!rtas_partition_exists)381return;382pr_notice("nvram: Using %s partition to log both"383" RTAS errors and oops/panic reports\n",384rtas_log_partition.name);385memcpy(&oops_log_partition, &rtas_log_partition,386sizeof(rtas_log_partition));387}388oops_buf = kmalloc(oops_log_partition.size, GFP_KERNEL);389rc = kmsg_dump_register(&nvram_kmsg_dumper);390if (rc != 0) {391pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);392kfree(oops_buf);393return;394}395}396397static int __init pseries_nvram_init_log_partitions(void)398{399int rc;400401rc = pseries_nvram_init_os_partition(&rtas_log_partition);402nvram_init_oops_partition(rc == 0);403return 0;404}405machine_arch_initcall(pseries, pseries_nvram_init_log_partitions);406407int __init pSeries_nvram_init(void)408{409struct device_node *nvram;410const unsigned int *nbytes_p;411unsigned int proplen;412413nvram = of_find_node_by_type(NULL, "nvram");414if (nvram == NULL)415return -ENODEV;416417nbytes_p = of_get_property(nvram, "#bytes", &proplen);418if (nbytes_p == NULL || proplen != sizeof(unsigned int)) {419of_node_put(nvram);420return -EIO;421}422423nvram_size = *nbytes_p;424425nvram_fetch = rtas_token("nvram-fetch");426nvram_store = rtas_token("nvram-store");427printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);428of_node_put(nvram);429430ppc_md.nvram_read = pSeries_nvram_read;431ppc_md.nvram_write = pSeries_nvram_write;432ppc_md.nvram_size = pSeries_nvram_get_size;433434return 0;435}436437/*438* Try to capture the last capture_len bytes of the printk buffer. Return439* the amount actually captured.440*/441static size_t capture_last_msgs(const char *old_msgs, size_t old_len,442const char *new_msgs, size_t new_len,443char *captured, size_t capture_len)444{445if (new_len >= capture_len) {446memcpy(captured, new_msgs + (new_len - capture_len),447capture_len);448return capture_len;449} else {450/* Grab the end of old_msgs. */451size_t old_tail_len = min(old_len, capture_len - new_len);452memcpy(captured, old_msgs + (old_len - old_tail_len),453old_tail_len);454memcpy(captured + old_tail_len, new_msgs, new_len);455return old_tail_len + new_len;456}457}458459/*460* Are we using the ibm,rtas-log for oops/panic reports? And if so,461* would logging this oops/panic overwrite an RTAS event that rtas_errd462* hasn't had a chance to read and process? Return 1 if so, else 0.463*464* We assume that if rtas_errd hasn't read the RTAS event in465* NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.466*/467static int clobbering_unread_rtas_event(void)468{469return (oops_log_partition.index == rtas_log_partition.index470&& last_unread_rtas_event471&& get_seconds() - last_unread_rtas_event <=472NVRAM_RTAS_READ_TIMEOUT);473}474475/* our kmsg_dump callback */476static void oops_to_nvram(struct kmsg_dumper *dumper,477enum kmsg_dump_reason reason,478const char *old_msgs, unsigned long old_len,479const char *new_msgs, unsigned long new_len)480{481static unsigned int oops_count = 0;482static bool panicking = false;483size_t text_len;484485switch (reason) {486case KMSG_DUMP_RESTART:487case KMSG_DUMP_HALT:488case KMSG_DUMP_POWEROFF:489/* These are almost always orderly shutdowns. */490return;491case KMSG_DUMP_OOPS:492case KMSG_DUMP_KEXEC:493break;494case KMSG_DUMP_PANIC:495panicking = true;496break;497case KMSG_DUMP_EMERG:498if (panicking)499/* Panic report already captured. */500return;501break;502default:503pr_err("%s: ignoring unrecognized KMSG_DUMP_* reason %d\n",504__FUNCTION__, (int) reason);505return;506}507508if (clobbering_unread_rtas_event())509return;510511text_len = capture_last_msgs(old_msgs, old_len, new_msgs, new_len,512oops_buf, oops_log_partition.size);513(void) nvram_write_os_partition(&oops_log_partition, oops_buf,514(int) text_len, ERR_TYPE_KERNEL_PANIC, ++oops_count);515}516517518