opal-msglog.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * PowerNV OPAL in-memory console interface
  4. *
  5. * Copyright 2014 IBM Corp.
  6. */
  7. #include <asm/io.h>
  8. #include <asm/opal.h>
  9. #include <linux/debugfs.h>
  10. #include <linux/of.h>
  11. #include <linux/types.h>
  12. #include <asm/barrier.h>
  13. #include "powernv.h"
  14. /* OPAL in-memory console. Defined in OPAL source at core/console.c */
  15. struct memcons {
  16. __be64 magic;
  17. #define MEMCONS_MAGIC 0x6630696567726173L
  18. __be64 obuf_phys;
  19. __be64 ibuf_phys;
  20. __be32 obuf_size;
  21. __be32 ibuf_size;
  22. __be32 out_pos;
  23. #define MEMCONS_OUT_POS_WRAP 0x80000000u
  24. #define MEMCONS_OUT_POS_MASK 0x00ffffffu
  25. __be32 in_prod;
  26. __be32 in_cons;
  27. };
  28. static struct memcons *opal_memcons = NULL;
  29. ssize_t memcons_copy(struct memcons *mc, char *to, loff_t pos, size_t count)
  30. {
  31. const char *conbuf;
  32. ssize_t ret;
  33. size_t first_read = 0;
  34. uint32_t out_pos, avail;
  35. if (!mc)
  36. return -ENODEV;
  37. out_pos = be32_to_cpu(READ_ONCE(mc->out_pos));
  38. /* Now we've read out_pos, put a barrier in before reading the new
  39. * data it points to in conbuf. */
  40. smp_rmb();
  41. conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys));
  42. /* When the buffer has wrapped, read from the out_pos marker to the end
  43. * of the buffer, and then read the remaining data as in the un-wrapped
  44. * case. */
  45. if (out_pos & MEMCONS_OUT_POS_WRAP) {
  46. out_pos &= MEMCONS_OUT_POS_MASK;
  47. avail = be32_to_cpu(mc->obuf_size) - out_pos;
  48. ret = memory_read_from_buffer(to, count, &pos,
  49. conbuf + out_pos, avail);
  50. if (ret < 0)
  51. goto out;
  52. first_read = ret;
  53. to += first_read;
  54. count -= first_read;
  55. pos -= avail;
  56. if (count <= 0)
  57. goto out;
  58. }
  59. /* Sanity check. The firmware should not do this to us. */
  60. if (out_pos > be32_to_cpu(mc->obuf_size)) {
  61. pr_err("OPAL: memory console corruption. Aborting read.\n");
  62. return -EINVAL;
  63. }
  64. ret = memory_read_from_buffer(to, count, &pos, conbuf, out_pos);
  65. if (ret < 0)
  66. goto out;
  67. ret += first_read;
  68. out:
  69. return ret;
  70. }
  71. ssize_t opal_msglog_copy(char *to, loff_t pos, size_t count)
  72. {
  73. return memcons_copy(opal_memcons, to, pos, count);
  74. }
  75. static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
  76. struct bin_attribute *bin_attr, char *to,
  77. loff_t pos, size_t count)
  78. {
  79. return opal_msglog_copy(to, pos, count);
  80. }
  81. static struct bin_attribute opal_msglog_attr = {
  82. .attr = {.name = "msglog", .mode = 0400},
  83. .read = opal_msglog_read
  84. };
  85. struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name)
  86. {
  87. u64 mcaddr;
  88. struct memcons *mc;
  89. if (of_property_read_u64(node, mc_prop_name, &mcaddr)) {
  90. pr_warn("%s property not found, no message log\n",
  91. mc_prop_name);
  92. goto out_err;
  93. }
  94. mc = phys_to_virt(mcaddr);
  95. if (!mc) {
  96. pr_warn("memory console address is invalid\n");
  97. goto out_err;
  98. }
  99. if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
  100. pr_warn("memory console version is invalid\n");
  101. goto out_err;
  102. }
  103. return mc;
  104. out_err:
  105. return NULL;
  106. }
  107. u32 __init memcons_get_size(struct memcons *mc)
  108. {
  109. return be32_to_cpu(mc->ibuf_size) + be32_to_cpu(mc->obuf_size);
  110. }
  111. void __init opal_msglog_init(void)
  112. {
  113. opal_memcons = memcons_init(opal_node, "ibm,opal-memcons");
  114. if (!opal_memcons) {
  115. pr_warn("OPAL: memcons failed to load from ibm,opal-memcons\n");
  116. return;
  117. }
  118. opal_msglog_attr.size = memcons_get_size(opal_memcons);
  119. }
  120. void __init opal_msglog_sysfs_init(void)
  121. {
  122. if (!opal_memcons) {
  123. pr_warn("OPAL: message log initialisation failed, not creating sysfs entry\n");
  124. return;
  125. }
  126. if (sysfs_create_bin_file(opal_kobj, &opal_msglog_attr) != 0)
  127. pr_warn("OPAL: sysfs file creation failed\n");
  128. }