memory-lowpower.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #define pr_fmt(fmt) "memory-lowpower: " fmt
  2. #define CONFIG_MTK_MEMORY_LOWPOWER_DEBUG
  3. #include <linux/types.h>
  4. #include <linux/of.h>
  5. #include <linux/of_reserved_mem.h>
  6. #include <linux/printk.h>
  7. #include <linux/cma.h>
  8. #include <linux/debugfs.h>
  9. #include <linux/stat.h>
  10. #include <linux/seq_file.h>
  11. #include <linux/uaccess.h>
  12. #include <linux/init.h>
  13. #include <linux/mutex.h>
  14. #include <asm/page.h>
  15. #include <asm-generic/memory_model.h>
  16. /* Memory lowpower private header file */
  17. #include "internal.h"
  18. static struct cma *cma;
  19. static struct page *cma_pages;
  20. static DEFINE_MUTEX(memory_lowpower_mutex);
  21. /*
  22. * memory_lowpower_cma_base - query the cma's base
  23. */
  24. phys_addr_t memory_lowpower_cma_base(void)
  25. {
  26. return cma_get_base(cma);
  27. }
  28. /*
  29. * memory_lowpower_cma_size - query the cma's size
  30. */
  31. unsigned long memory_lowpower_cma_size(void)
  32. {
  33. return cma_get_size(cma);
  34. }
  35. /*
  36. * get_memory_lowpwer_cma_aligned - allocate aligned cma memory belongs to lowpower cma
  37. * @count: Requested number of pages.
  38. * @align: Requested alignment of pages (in PAGE_SIZE order).
  39. * @pages: Pointer indicates allocated cma buffer.
  40. * It returns 0 is success, otherwise returns -1
  41. */
  42. int get_memory_lowpower_cma_aligned(int count, unsigned int align, struct page **pages)
  43. {
  44. int ret = 0;
  45. mutex_lock(&memory_lowpower_mutex);
  46. *pages = cma_alloc(cma, count, align);
  47. if (*pages == NULL) {
  48. pr_alert("lowpower cma allocation failed\n");
  49. ret = -1;
  50. }
  51. mutex_unlock(&memory_lowpower_mutex);
  52. return ret;
  53. }
  54. /*
  55. * put_memory_lowpwer_cma_aligned - free aligned cma memory belongs to lowpower cma
  56. * @count: Requested number of pages.
  57. * @pages: Pointer indicates allocated cma buffer.
  58. * It returns 0 is success, otherwise returns -ENOMEM
  59. */
  60. int put_memory_lowpower_cma_aligned(int count, struct page *pages)
  61. {
  62. int ret;
  63. mutex_lock(&memory_lowpower_mutex);
  64. if (pages) {
  65. ret = cma_release(cma, pages, count);
  66. if (!ret) {
  67. pr_err("%s incorrect pages: %p(%lx)\n",
  68. __func__,
  69. pages, page_to_pfn(pages));
  70. return -EINVAL;
  71. }
  72. }
  73. mutex_unlock(&memory_lowpower_mutex);
  74. return 0;
  75. }
  76. /*
  77. * get_memory_lowpwer_cma - allocate all cma memory belongs to lowpower cma
  78. *
  79. */
  80. int get_memory_lowpower_cma(void)
  81. {
  82. int count = cma_get_size(cma) >> PAGE_SHIFT;
  83. if (cma_pages) {
  84. pr_alert("cma already collected\n");
  85. goto out;
  86. }
  87. mutex_lock(&memory_lowpower_mutex);
  88. cma_pages = cma_alloc(cma, count, 0);
  89. if (cma_pages)
  90. pr_debug("%s:%d ok\n", __func__, __LINE__);
  91. else
  92. pr_alert("lowpower cma allocation failed\n");
  93. mutex_unlock(&memory_lowpower_mutex);
  94. out:
  95. return 0;
  96. }
  97. /*
  98. * put_memory_lowpwer_cma - free all cma memory belongs to lowpower cma
  99. *
  100. * It returns 0 is success, otherwise returns -ENOMEM
  101. */
  102. int put_memory_lowpower_cma(void)
  103. {
  104. int ret;
  105. int count = cma_get_size(cma) >> PAGE_SHIFT;
  106. mutex_lock(&memory_lowpower_mutex);
  107. if (cma_pages) {
  108. ret = cma_release(cma, cma_pages, count);
  109. if (!ret) {
  110. pr_err("%s incorrect pages: %p(%lx)\n",
  111. __func__,
  112. cma_pages, page_to_pfn(cma_pages));
  113. return -EINVAL;
  114. }
  115. cma_pages = 0;
  116. }
  117. mutex_unlock(&memory_lowpower_mutex);
  118. return 0;
  119. }
  120. static int memory_lowpower_init(struct reserved_mem *rmem)
  121. {
  122. int ret;
  123. pr_debug("%s, name: %s, base: 0x%pa, size: 0x%pa\n",
  124. __func__, rmem->name,
  125. &rmem->base, &rmem->size);
  126. /* init cma area */
  127. ret = cma_init_reserved_mem(rmem->base, rmem->size , 0, &cma);
  128. if (ret) {
  129. pr_err("%s cma failed, ret: %d\n", __func__, ret);
  130. return 1;
  131. }
  132. return 0;
  133. }
  134. RESERVEDMEM_OF_DECLARE(memory_lowpower, "mediatek,memory-lowpower",
  135. memory_lowpower_init);
  136. #ifdef CONFIG_MTK_MEMORY_LOWPOWER_DEBUG
  137. static int memory_lowpower_show(struct seq_file *m, void *v)
  138. {
  139. phys_addr_t cma_base = cma_get_base(cma);
  140. phys_addr_t cma_end = cma_base + cma_get_size(cma);
  141. mutex_lock(&memory_lowpower_mutex);
  142. if (cma_pages)
  143. seq_printf(m, "cma collected cma_pages: %p\n", cma_pages);
  144. else
  145. seq_puts(m, "cma freed NULL\n");
  146. mutex_unlock(&memory_lowpower_mutex);
  147. seq_printf(m, "cma info: [%pa-%pa] (0x%lx)\n",
  148. &cma_base, &cma_end,
  149. cma_get_size(cma));
  150. return 0;
  151. }
  152. static int memory_lowpower_open(struct inode *inode, struct file *file)
  153. {
  154. return single_open(file, &memory_lowpower_show, NULL);
  155. }
  156. static ssize_t memory_lowpower_write(struct file *file, const char __user *buffer,
  157. size_t count, loff_t *ppos)
  158. {
  159. static char state;
  160. if (count > 0) {
  161. if (get_user(state, buffer))
  162. return -EFAULT;
  163. state -= '0';
  164. pr_alert("%s state = %d\n", __func__, state);
  165. if (state) {
  166. /* collect cma */
  167. get_memory_lowpower_cma();
  168. } else {
  169. /* undo collection */
  170. put_memory_lowpower_cma();
  171. }
  172. }
  173. return count;
  174. }
  175. static const struct file_operations memory_lowpower_fops = {
  176. .open = memory_lowpower_open,
  177. .write = memory_lowpower_write,
  178. .read = seq_read,
  179. .release = single_release,
  180. };
  181. static int __init memory_lowpower_debug_init(void)
  182. {
  183. struct dentry *dentry;
  184. if (!cma) {
  185. pr_err("memory-lowpower cma is not inited\n");
  186. return 1;
  187. }
  188. dentry = debugfs_create_file("memory-lowpower", S_IRUGO, NULL, NULL,
  189. &memory_lowpower_fops);
  190. if (!dentry)
  191. pr_warn("Failed to create debugfs memory_lowpower_debug_init file\n");
  192. return 0;
  193. }
  194. late_initcall(memory_lowpower_debug_init);
  195. #endif /* CONFIG_MTK_MEMORY_LOWPOWER_DEBUG */