Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PowerNV nvram code.
0004  *
0005  * Copyright 2011 IBM Corp.
0006  */
0007 
0008 #define DEBUG
0009 
0010 #include <linux/delay.h>
0011 #include <linux/kernel.h>
0012 #include <linux/init.h>
0013 #include <linux/of.h>
0014 
0015 #include <asm/opal.h>
0016 #include <asm/nvram.h>
0017 #include <asm/machdep.h>
0018 
0019 static unsigned int nvram_size;
0020 
0021 static ssize_t opal_nvram_size(void)
0022 {
0023     return nvram_size;
0024 }
0025 
0026 static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index)
0027 {
0028     s64 rc;
0029     int off;
0030 
0031     if (*index >= nvram_size)
0032         return 0;
0033     off = *index;
0034     if ((off + count) > nvram_size)
0035         count = nvram_size - off;
0036     rc = opal_read_nvram(__pa(buf), count, off);
0037     if (rc != OPAL_SUCCESS)
0038         return -EIO;
0039     *index += count;
0040     return count;
0041 }
0042 
0043 /*
0044  * This can be called in the panic path with interrupts off, so use
0045  * mdelay in that case.
0046  */
0047 static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
0048 {
0049     s64 rc = OPAL_BUSY;
0050     int off;
0051 
0052     if (*index >= nvram_size)
0053         return 0;
0054     off = *index;
0055     if ((off + count) > nvram_size)
0056         count = nvram_size - off;
0057 
0058     while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
0059         rc = opal_write_nvram(__pa(buf), count, off);
0060         if (rc == OPAL_BUSY_EVENT) {
0061             if (in_interrupt() || irqs_disabled())
0062                 mdelay(OPAL_BUSY_DELAY_MS);
0063             else
0064                 msleep(OPAL_BUSY_DELAY_MS);
0065             opal_poll_events(NULL);
0066         } else if (rc == OPAL_BUSY) {
0067             if (in_interrupt() || irqs_disabled())
0068                 mdelay(OPAL_BUSY_DELAY_MS);
0069             else
0070                 msleep(OPAL_BUSY_DELAY_MS);
0071         }
0072     }
0073 
0074     if (rc)
0075         return -EIO;
0076 
0077     *index += count;
0078     return count;
0079 }
0080 
0081 static int __init opal_nvram_init_log_partitions(void)
0082 {
0083     /* Scan nvram for partitions */
0084     nvram_scan_partitions();
0085     nvram_init_oops_partition(0);
0086     return 0;
0087 }
0088 machine_arch_initcall(powernv, opal_nvram_init_log_partitions);
0089 
0090 void __init opal_nvram_init(void)
0091 {
0092     struct device_node *np;
0093     const __be32 *nbytes_p;
0094 
0095     np = of_find_compatible_node(NULL, NULL, "ibm,opal-nvram");
0096     if (np == NULL)
0097         return;
0098 
0099     nbytes_p = of_get_property(np, "#bytes", NULL);
0100     if (!nbytes_p) {
0101         of_node_put(np);
0102         return;
0103     }
0104     nvram_size = be32_to_cpup(nbytes_p);
0105 
0106     pr_info("OPAL nvram setup, %u bytes\n", nvram_size);
0107     of_node_put(np);
0108 
0109     ppc_md.nvram_read = opal_nvram_read;
0110     ppc_md.nvram_write = opal_nvram_write;
0111     ppc_md.nvram_size = opal_nvram_size;
0112 }
0113