[PATCH] powerpc/powernv: Map OPAL msglog in IOREMAP area
Christophe Leroy
christophe.leroy at csgroup.eu
Thu Jul 7 19:27:47 AEST 2022
Hi
Le 16/03/2017 à 07:17, Gavin Shan a écrit :
> With OPAL msglog driver, there are two interfaces to retrieve the
> firmware (skiboot) logs: /sys/firmware/opal/msglog and xmon "do"
> command. The memory console header (descritpor) and output buffer
> are resident in memory blocks whose addresses are greater than
> 0x30000000. The memory blocks needn't be necessarily visible to
> kernel. For example when the memory visible to kernel is limited
> by "mem=768M" in bootargs. In this case, reading the memory console
> header (descriptor) and its output buffer directly causes kernel
> crash as the memory blocks aren't mapped in the linear area as the
> driver assumed.
>
> This reworks the driver to map the memory console header (descitpor)
> and its output buffer as readonly in IOREMAP area as Michael Ellerman
> suggested before. Also, the memory console descriptor are readed into
> local descriptor so that we needn't care about its endian (big or little)
> afterwards, until we need update the output position when dumping the
> messages in the output buffer.
>
> Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
This patch badly conflits when applying.
If it's still applicable, could you rebase and resubmit ?
Thanks
Christophe
> ---
> arch/powerpc/platforms/powernv/opal-msglog.c | 81 ++++++++++++++++++----------
> 1 file changed, 54 insertions(+), 27 deletions(-)
>
> diff --git a/arch/powerpc/platforms/powernv/opal-msglog.c b/arch/powerpc/platforms/powernv/opal-msglog.c
> index 7a9cde0..0f2167f 100644
> --- a/arch/powerpc/platforms/powernv/opal-msglog.c
> +++ b/arch/powerpc/platforms/powernv/opal-msglog.c
> @@ -18,38 +18,46 @@
>
> /* OPAL in-memory console. Defined in OPAL source at core/console.c */
> struct memcons {
> - __be64 magic;
> + unsigned long magic;
> #define MEMCONS_MAGIC 0x6630696567726173L
> - __be64 obuf_phys;
> - __be64 ibuf_phys;
> - __be32 obuf_size;
> - __be32 ibuf_size;
> - __be32 out_pos;
> + unsigned long obuf_phys;
> + unsigned long ibuf_phys;
> + unsigned int obuf_size;
> + unsigned int ibuf_size;
> + unsigned int out_pos;
> #define MEMCONS_OUT_POS_WRAP 0x80000000u
> #define MEMCONS_OUT_POS_MASK 0x00ffffffu
> - __be32 in_prod;
> - __be32 in_cons;
> + unsigned int in_prod;
> + unsigned int in_cons;
> };
>
> -static struct memcons *opal_memcons = NULL;
> +static struct memcons opal_memcons;
> +static void __iomem *opal_memcons_virt;
> +static void __iomem *opal_memcons_obuf;
> +
> +#define OPAL_MEMCONS_GET_FIELD(field, accessor, converter, tmp) \
> + tmp = accessor(opal_memcons_virt + \
> + offsetof(struct memcons, field)); \
> + opal_memcons.field = converter(tmp)
>
> ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
> {
> - const char *conbuf;
> + char *conbuf;
> ssize_t ret;
> size_t first_read = 0;
> - uint32_t out_pos, avail;
> + uint32_t out_pos, avail, val32;
>
> - if (!opal_memcons)
> + if (!opal_memcons_obuf)
> return -ENODEV;
>
> - out_pos = be32_to_cpu(ACCESS_ONCE(opal_memcons->out_pos));
> + OPAL_MEMCONS_GET_FIELD(out_pos, __raw_readl, be32_to_cpu, val32);
> + out_pos = opal_memcons.out_pos;
>
> /* Now we've read out_pos, put a barrier in before reading the new
> * data it points to in conbuf. */
> smp_rmb();
>
> - conbuf = phys_to_virt(be64_to_cpu(opal_memcons->obuf_phys));
> + conbuf = opal_memcons_obuf;
>
> /* When the buffer has wrapped, read from the out_pos marker to the end
> * of the buffer, and then read the remaining data as in the un-wrapped
> @@ -57,7 +65,7 @@ ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
> if (out_pos & MEMCONS_OUT_POS_WRAP) {
>
> out_pos &= MEMCONS_OUT_POS_MASK;
> - avail = be32_to_cpu(opal_memcons->obuf_size) - out_pos;
> + avail = opal_memcons.obuf_size - out_pos;
>
> ret = memory_read_from_buffer(to, count, &pos,
> conbuf + out_pos, avail);
> @@ -75,7 +83,7 @@ ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
> }
>
> /* Sanity check. The firmware should not do this to us. */
> - if (out_pos > be32_to_cpu(opal_memcons->obuf_size)) {
> + if (out_pos > opal_memcons.obuf_size) {
> pr_err("OPAL: memory console corruption. Aborting read.\n");
> return -EINVAL;
> }
> @@ -104,35 +112,54 @@ static struct bin_attribute opal_msglog_attr = {
>
> void __init opal_msglog_init(void)
> {
> - u64 mcaddr;
> - struct memcons *mc;
> + u64 val64;
> + u32 val32;
>
> - if (of_property_read_u64(opal_node, "ibm,opal-memcons", &mcaddr)) {
> + if (of_property_read_u64(opal_node, "ibm,opal-memcons", &val64)) {
> pr_warn("OPAL: Property ibm,opal-memcons not found, no message log\n");
> return;
> }
>
> - mc = phys_to_virt(mcaddr);
> - if (!mc) {
> + opal_memcons_virt = ioremap_prot(val64, sizeof(opal_memcons),
> + (_PAGE_BASE | _PAGE_KERNEL_RO));
> + if (!opal_memcons_virt) {
> pr_warn("OPAL: memory console address is invalid\n");
> return;
> }
>
> - if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
> + OPAL_MEMCONS_GET_FIELD(magic, __raw_readq, be64_to_cpu, val64);
> + OPAL_MEMCONS_GET_FIELD(obuf_phys, __raw_readq, be64_to_cpu, val64);
> + OPAL_MEMCONS_GET_FIELD(ibuf_phys, __raw_readq, be64_to_cpu, val64);
> + OPAL_MEMCONS_GET_FIELD(obuf_size, __raw_readl, be32_to_cpu, val64);
> + OPAL_MEMCONS_GET_FIELD(ibuf_size, __raw_readl, be32_to_cpu, val32);
> + OPAL_MEMCONS_GET_FIELD(out_pos, __raw_readl, be32_to_cpu, val32);
> + OPAL_MEMCONS_GET_FIELD(in_prod, __raw_readl, be32_to_cpu, val32);
> + OPAL_MEMCONS_GET_FIELD(in_cons, __raw_readl, be32_to_cpu, val32);
> +
> + if (opal_memcons.magic != MEMCONS_MAGIC) {
> pr_warn("OPAL: memory console version is invalid\n");
> + iounmap(opal_memcons_virt);
> return;
> }
>
> - /* Report maximum size */
> - opal_msglog_attr.size = be32_to_cpu(mc->ibuf_size) +
> - be32_to_cpu(mc->obuf_size);
> + opal_memcons_obuf = ioremap_prot(opal_memcons.obuf_phys,
> + opal_memcons.obuf_size,
> + (_PAGE_BASE | _PAGE_KERNEL_RO));
> + if (!opal_memcons_obuf) {
> + pr_warn("OPAL: Fail mapping output buffer (0x%lx, 0x%x)\n",
> + opal_memcons.obuf_phys, opal_memcons.obuf_size);
> + iounmap(opal_memcons_virt);
> + return;
> + }
>
> - opal_memcons = mc;
> + /* Report maximum size */
> + opal_msglog_attr.size = opal_memcons.ibuf_size +
> + opal_memcons.obuf_size;
> }
>
> void __init opal_msglog_sysfs_init(void)
> {
> - if (!opal_memcons) {
> + if (!opal_memcons_obuf) {
> pr_warn("OPAL: message log initialisation failed, not creating sysfs entry\n");
> return;
> }
More information about the Linuxppc-dev
mailing list