opal-nvram.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * PowerNV nvram code.
  3. *
  4. * Copyright 2011 IBM Corp.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #define DEBUG
  12. #include <linux/delay.h>
  13. #include <linux/kernel.h>
  14. #include <linux/init.h>
  15. #include <linux/of.h>
  16. #include <asm/opal.h>
  17. #include <asm/nvram.h>
  18. #include <asm/machdep.h>
  19. static unsigned int nvram_size;
  20. static ssize_t opal_nvram_size(void)
  21. {
  22. return nvram_size;
  23. }
  24. static ssize_t opal_nvram_read(char *buf, size_t count, loff_t *index)
  25. {
  26. s64 rc;
  27. int off;
  28. if (*index >= nvram_size)
  29. return 0;
  30. off = *index;
  31. if ((off + count) > nvram_size)
  32. count = nvram_size - off;
  33. rc = opal_read_nvram(__pa(buf), count, off);
  34. if (rc != OPAL_SUCCESS)
  35. return -EIO;
  36. *index += count;
  37. return count;
  38. }
  39. /*
  40. * This can be called in the panic path with interrupts off, so use
  41. * mdelay in that case.
  42. */
  43. static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index)
  44. {
  45. s64 rc = OPAL_BUSY;
  46. int off;
  47. if (*index >= nvram_size)
  48. return 0;
  49. off = *index;
  50. if ((off + count) > nvram_size)
  51. count = nvram_size - off;
  52. while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
  53. rc = opal_write_nvram(__pa(buf), count, off);
  54. if (rc == OPAL_BUSY_EVENT) {
  55. if (in_interrupt() || irqs_disabled())
  56. mdelay(OPAL_BUSY_DELAY_MS);
  57. else
  58. msleep(OPAL_BUSY_DELAY_MS);
  59. opal_poll_events(NULL);
  60. } else if (rc == OPAL_BUSY) {
  61. if (in_interrupt() || irqs_disabled())
  62. mdelay(OPAL_BUSY_DELAY_MS);
  63. else
  64. msleep(OPAL_BUSY_DELAY_MS);
  65. }
  66. }
  67. if (rc)
  68. return -EIO;
  69. *index += count;
  70. return count;
  71. }
  72. static int __init opal_nvram_init_log_partitions(void)
  73. {
  74. /* Scan nvram for partitions */
  75. nvram_scan_partitions();
  76. nvram_init_oops_partition(0);
  77. return 0;
  78. }
  79. machine_arch_initcall(powernv, opal_nvram_init_log_partitions);
  80. void __init opal_nvram_init(void)
  81. {
  82. struct device_node *np;
  83. const __be32 *nbytes_p;
  84. np = of_find_compatible_node(NULL, NULL, "ibm,opal-nvram");
  85. if (np == NULL)
  86. return;
  87. nbytes_p = of_get_property(np, "#bytes", NULL);
  88. if (!nbytes_p) {
  89. of_node_put(np);
  90. return;
  91. }
  92. nvram_size = be32_to_cpup(nbytes_p);
  93. pr_info("OPAL nvram setup, %u bytes\n", nvram_size);
  94. of_node_put(np);
  95. ppc_md.nvram_read = opal_nvram_read;
  96. ppc_md.nvram_write = opal_nvram_write;
  97. ppc_md.nvram_size = opal_nvram_size;
  98. }