Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PowerNV OPAL in-memory console interface
0004  *
0005  * Copyright 2014 IBM Corp.
0006  */
0007 
0008 #include <asm/io.h>
0009 #include <asm/opal.h>
0010 #include <linux/debugfs.h>
0011 #include <linux/of.h>
0012 #include <linux/types.h>
0013 #include <asm/barrier.h>
0014 
0015 #include "powernv.h"
0016 
0017 /* OPAL in-memory console. Defined in OPAL source at core/console.c */
0018 struct memcons {
0019     __be64 magic;
0020 #define MEMCONS_MAGIC   0x6630696567726173L
0021     __be64 obuf_phys;
0022     __be64 ibuf_phys;
0023     __be32 obuf_size;
0024     __be32 ibuf_size;
0025     __be32 out_pos;
0026 #define MEMCONS_OUT_POS_WRAP    0x80000000u
0027 #define MEMCONS_OUT_POS_MASK    0x00ffffffu
0028     __be32 in_prod;
0029     __be32 in_cons;
0030 };
0031 
0032 static struct memcons *opal_memcons = NULL;
0033 
0034 ssize_t memcons_copy(struct memcons *mc, char *to, loff_t pos, size_t count)
0035 {
0036     const char *conbuf;
0037     ssize_t ret;
0038     size_t first_read = 0;
0039     uint32_t out_pos, avail;
0040 
0041     if (!mc)
0042         return -ENODEV;
0043 
0044     out_pos = be32_to_cpu(READ_ONCE(mc->out_pos));
0045 
0046     /* Now we've read out_pos, put a barrier in before reading the new
0047      * data it points to in conbuf. */
0048     smp_rmb();
0049 
0050     conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys));
0051 
0052     /* When the buffer has wrapped, read from the out_pos marker to the end
0053      * of the buffer, and then read the remaining data as in the un-wrapped
0054      * case. */
0055     if (out_pos & MEMCONS_OUT_POS_WRAP) {
0056 
0057         out_pos &= MEMCONS_OUT_POS_MASK;
0058         avail = be32_to_cpu(mc->obuf_size) - out_pos;
0059 
0060         ret = memory_read_from_buffer(to, count, &pos,
0061                 conbuf + out_pos, avail);
0062 
0063         if (ret < 0)
0064             goto out;
0065 
0066         first_read = ret;
0067         to += first_read;
0068         count -= first_read;
0069         pos -= avail;
0070 
0071         if (count <= 0)
0072             goto out;
0073     }
0074 
0075     /* Sanity check. The firmware should not do this to us. */
0076     if (out_pos > be32_to_cpu(mc->obuf_size)) {
0077         pr_err("OPAL: memory console corruption. Aborting read.\n");
0078         return -EINVAL;
0079     }
0080 
0081     ret = memory_read_from_buffer(to, count, &pos, conbuf, out_pos);
0082 
0083     if (ret < 0)
0084         goto out;
0085 
0086     ret += first_read;
0087 out:
0088     return ret;
0089 }
0090 
0091 ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
0092 {
0093     return memcons_copy(opal_memcons, to, pos, count);
0094 }
0095 
0096 static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
0097                 struct bin_attribute *bin_attr, char *to,
0098                 loff_t pos, size_t count)
0099 {
0100     return opal_msglog_copy(to, pos, count);
0101 }
0102 
0103 static struct bin_attribute opal_msglog_attr = {
0104     .attr = {.name = "msglog", .mode = 0400},
0105     .read = opal_msglog_read
0106 };
0107 
0108 struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name)
0109 {
0110     u64 mcaddr;
0111     struct memcons *mc;
0112 
0113     if (of_property_read_u64(node, mc_prop_name, &mcaddr)) {
0114         pr_warn("%s property not found, no message log\n",
0115             mc_prop_name);
0116         goto out_err;
0117     }
0118 
0119     mc = phys_to_virt(mcaddr);
0120     if (!mc) {
0121         pr_warn("memory console address is invalid\n");
0122         goto out_err;
0123     }
0124 
0125     if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
0126         pr_warn("memory console version is invalid\n");
0127         goto out_err;
0128     }
0129 
0130     return mc;
0131 
0132 out_err:
0133     return NULL;
0134 }
0135 
0136 u32 __init memcons_get_size(struct memcons *mc)
0137 {
0138     return be32_to_cpu(mc->ibuf_size) + be32_to_cpu(mc->obuf_size);
0139 }
0140 
0141 void __init opal_msglog_init(void)
0142 {
0143     opal_memcons = memcons_init(opal_node, "ibm,opal-memcons");
0144     if (!opal_memcons) {
0145         pr_warn("OPAL: memcons failed to load from ibm,opal-memcons\n");
0146         return;
0147     }
0148 
0149     opal_msglog_attr.size = memcons_get_size(opal_memcons);
0150 }
0151 
0152 void __init opal_msglog_sysfs_init(void)
0153 {
0154     if (!opal_memcons) {
0155         pr_warn("OPAL: message log initialisation failed, not creating sysfs entry\n");
0156         return;
0157     }
0158 
0159     if (sysfs_create_bin_file(opal_kobj, &opal_msglog_attr) != 0)
0160         pr_warn("OPAL: sysfs file creation failed\n");
0161 }