nvs.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * nvs.c - Routines for saving and restoring ACPI NVS memory region
  4. *
  5. * Copyright (C) 2008-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
  6. */
  7. #include <linux/io.h>
  8. #include <linux/kernel.h>
  9. #include <linux/list.h>
  10. #include <linux/mm.h>
  11. #include <linux/slab.h>
  12. #include <linux/acpi.h>
  13. #include "internal.h"
  14. /* ACPI NVS regions, APEI may use it */
  15. struct nvs_region {
  16. __u64 phys_start;
  17. __u64 size;
  18. struct list_head node;
  19. };
  20. static LIST_HEAD(nvs_region_list);
  21. #ifdef CONFIG_ACPI_SLEEP
  22. static int suspend_nvs_register(unsigned long start, unsigned long size);
  23. #else
  24. static inline int suspend_nvs_register(unsigned long a, unsigned long b)
  25. {
  26. return 0;
  27. }
  28. #endif
  29. int acpi_nvs_register(__u64 start, __u64 size)
  30. {
  31. struct nvs_region *region;
  32. region = kmalloc(sizeof(*region), GFP_KERNEL);
  33. if (!region)
  34. return -ENOMEM;
  35. region->phys_start = start;
  36. region->size = size;
  37. list_add_tail(&region->node, &nvs_region_list);
  38. return suspend_nvs_register(start, size);
  39. }
  40. int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data),
  41. void *data)
  42. {
  43. int rc;
  44. struct nvs_region *region;
  45. list_for_each_entry(region, &nvs_region_list, node) {
  46. rc = func(region->phys_start, region->size, data);
  47. if (rc)
  48. return rc;
  49. }
  50. return 0;
  51. }
  52. #ifdef CONFIG_ACPI_SLEEP
  53. /*
  54. * Platforms, like ACPI, may want us to save some memory used by them during
  55. * suspend and to restore the contents of this memory during the subsequent
  56. * resume. The code below implements a mechanism allowing us to do that.
  57. */
  58. struct nvs_page {
  59. unsigned long phys_start;
  60. unsigned int size;
  61. void *kaddr;
  62. void *data;
  63. bool unmap;
  64. struct list_head node;
  65. };
  66. static LIST_HEAD(nvs_list);
  67. /**
  68. * suspend_nvs_register - register platform NVS memory region to save
  69. * @start - physical address of the region
  70. * @size - size of the region
  71. *
  72. * The NVS region need not be page-aligned (both ends) and we arrange
  73. * things so that the data from page-aligned addresses in this region will
  74. * be copied into separate RAM pages.
  75. */
  76. static int suspend_nvs_register(unsigned long start, unsigned long size)
  77. {
  78. struct nvs_page *entry, *next;
  79. pr_info("PM: Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n",
  80. start, start + size - 1, size);
  81. while (size > 0) {
  82. unsigned int nr_bytes;
  83. entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
  84. if (!entry)
  85. goto Error;
  86. list_add_tail(&entry->node, &nvs_list);
  87. entry->phys_start = start;
  88. nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
  89. entry->size = (size < nr_bytes) ? size : nr_bytes;
  90. start += entry->size;
  91. size -= entry->size;
  92. }
  93. return 0;
  94. Error:
  95. list_for_each_entry_safe(entry, next, &nvs_list, node) {
  96. list_del(&entry->node);
  97. kfree(entry);
  98. }
  99. return -ENOMEM;
  100. }
  101. /**
  102. * suspend_nvs_free - free data pages allocated for saving NVS regions
  103. */
  104. void suspend_nvs_free(void)
  105. {
  106. struct nvs_page *entry;
  107. list_for_each_entry(entry, &nvs_list, node)
  108. if (entry->data) {
  109. free_page((unsigned long)entry->data);
  110. entry->data = NULL;
  111. if (entry->kaddr) {
  112. if (entry->unmap) {
  113. iounmap(entry->kaddr);
  114. entry->unmap = false;
  115. } else {
  116. acpi_os_unmap_iomem(entry->kaddr,
  117. entry->size);
  118. }
  119. entry->kaddr = NULL;
  120. }
  121. }
  122. }
  123. /**
  124. * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
  125. */
  126. int suspend_nvs_alloc(void)
  127. {
  128. struct nvs_page *entry;
  129. list_for_each_entry(entry, &nvs_list, node) {
  130. entry->data = (void *)__get_free_page(GFP_KERNEL);
  131. if (!entry->data) {
  132. suspend_nvs_free();
  133. return -ENOMEM;
  134. }
  135. }
  136. return 0;
  137. }
  138. /**
  139. * suspend_nvs_save - save NVS memory regions
  140. */
  141. int suspend_nvs_save(void)
  142. {
  143. struct nvs_page *entry;
  144. printk(KERN_INFO "PM: Saving platform NVS memory\n");
  145. list_for_each_entry(entry, &nvs_list, node)
  146. if (entry->data) {
  147. unsigned long phys = entry->phys_start;
  148. unsigned int size = entry->size;
  149. entry->kaddr = acpi_os_get_iomem(phys, size);
  150. if (!entry->kaddr) {
  151. entry->kaddr = acpi_os_ioremap(phys, size);
  152. entry->unmap = !!entry->kaddr;
  153. }
  154. if (!entry->kaddr) {
  155. suspend_nvs_free();
  156. return -ENOMEM;
  157. }
  158. memcpy(entry->data, entry->kaddr, entry->size);
  159. }
  160. return 0;
  161. }
  162. /**
  163. * suspend_nvs_restore - restore NVS memory regions
  164. *
  165. * This function is going to be called with interrupts disabled, so it
  166. * cannot iounmap the virtual addresses used to access the NVS region.
  167. */
  168. void suspend_nvs_restore(void)
  169. {
  170. struct nvs_page *entry;
  171. printk(KERN_INFO "PM: Restoring platform NVS memory\n");
  172. list_for_each_entry(entry, &nvs_list, node)
  173. if (entry->data)
  174. memcpy(entry->kaddr, entry->data, entry->size);
  175. }
  176. #endif