exm_dlmalloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /* EXM */
  2. #include <linux/module.h>
  3. #include <linux/io.h>
  4. #include <linux/slab.h>
  5. #include <linux/exm_driver.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/vmalloc.h>
  8. #include <linux/mm.h>
  9. #include <linux/moduleparam.h>
  10. #include <asm/setup.h>
  11. #include "exm_dlmalloc.h"
  12. /* Ugly inclusion of C file so that bionic specific #defines configure dlmalloc.*/
  13. #include "malloc.c"
  14. #define DEV_DRV_NAME "mt-extmem"
  15. /* #define EXTMEM_DEBUG */
  16. #ifdef EXTMEM_DEBUG
  17. #define extmem_printk(fmt, args...) pr_debug(fmt, ## args)
  18. #else
  19. #define extmem_printk(...)
  20. #endif
  21. #define mspace void *
  22. static void *extmem_mspace;
  23. static void *extmem_mspace_base;
  24. static size_t extmem_mspace_size;
  25. #define EXTMEM_ALIGNMENT 0x02000000
  26. #ifdef CONFIG_OF
  27. #include <linux/of.h>
  28. #include <asm/setup.h>
  29. #include <linux/of_fdt.h>
  30. #include <linux/of_platform.h>
  31. #include <linux/of_reserved_mem.h>
  32. static phys_addr_t extmem_phys_base;
  33. static int extmem_scan_memory(unsigned long node, const char *uname, int depth, void *data)
  34. {
  35. struct mem_desc *mem_desc;
  36. /* We are scanning "memory" nodes only */
  37. const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
  38. if (type == NULL) {
  39. /*
  40. * The longtrail doesn't have a device_type on the
  41. * /memory node, so look for the node called /memory@0.
  42. */
  43. if (depth != 1 || strcmp(uname, "memory@0") != 0)
  44. return 0;
  45. } else if (strcmp(type, "memory") != 0) {
  46. return 0;
  47. }
  48. /* lca reserved memory */
  49. mem_desc = (struct mem_desc *)of_get_flat_dt_prop(node,
  50. "lca_reserved_mem", NULL);
  51. if (mem_desc && mem_desc->size) {
  52. extmem_phys_base = mem_desc->start;
  53. extmem_mspace_size = mem_desc->size;
  54. extmem_printk("extmem_scan_memory extmem_phys_base: 0x%p, extmem_mspace_size: 0x%zx\n",
  55. (void *)extmem_phys_base, extmem_mspace_size);
  56. }
  57. return node;
  58. }
  59. static int extmem_get_lca_reserved_mem(void)
  60. {
  61. int node;
  62. /* avoid double init */
  63. if (extmem_phys_base) {
  64. pr_err("extmem_phys_base exist: 0x%p\n", (void *)extmem_phys_base);
  65. return -1;
  66. }
  67. node = of_scan_flat_dt(extmem_scan_memory, NULL);
  68. return 0;
  69. }
  70. static void extmem_init(void)
  71. {
  72. if (extmem_mspace == NULL) {
  73. #ifdef CONFIG_ARM64
  74. size_t extmem_vmalloc_limit = (VMALLOC_TOTAL/3 + EXTMEM_ALIGNMENT - 1) & ~(EXTMEM_ALIGNMENT-1);
  75. #else
  76. size_t extmem_vmalloc_limit = ((VMALLOC_TOTAL>>1) - 1) & ~(EXTMEM_ALIGNMENT-1);
  77. #endif
  78. extmem_get_lca_reserved_mem();
  79. if (extmem_mspace_size > EXTMEM_ALIGNMENT)
  80. extmem_mspace_size -= EXTMEM_ALIGNMENT;
  81. if (extmem_mspace_size > extmem_vmalloc_limit) {
  82. pr_err("extmem_mspace_size: 0x%zx over limit: 0x%zx\n",
  83. extmem_mspace_size, extmem_vmalloc_limit);
  84. extmem_mspace_size = extmem_vmalloc_limit;
  85. }
  86. if (extmem_mspace_size <= 0) {
  87. pr_err("no extmem, need check config\n");
  88. BUG();
  89. }
  90. #ifdef CONFIG_ARM64
  91. extmem_mspace_base = (void *)ioremap_wc(extmem_phys_base, extmem_mspace_size);
  92. #else
  93. extmem_mspace_base = (void *)ioremap_cache(extmem_phys_base, extmem_mspace_size);
  94. #endif
  95. extmem_mspace = create_mspace_with_base(extmem_mspace_base, extmem_mspace_size, 1);
  96. extmem_printk("extmem_phys_base:0x%p,extmem_mspace_size: 0x%zx,extmem_mspace:0x%p\n",
  97. (void *)extmem_phys_base, extmem_mspace_size, extmem_mspace);
  98. extmem_printk("%s extmem current used: 0x%zx, peak used: 0x%zx\n",
  99. __func__, mspace_mem_used(extmem_mspace), mspace_mem_used_peak(extmem_mspace));
  100. }
  101. }
  102. #else
  103. static void extmem_init(void)
  104. {
  105. if (extmem_mspace == NULL) {
  106. if (extmem_mspace_size == 0) {
  107. size_t extmem_vmalloc_limit =
  108. (VMALLOC_TOTAL/3 + EXTMEM_ALIGNMENT - 1) & ~(EXTMEM_ALIGNMENT - 1);
  109. if (get_max_DRAM_size() < (CONFIG_MAX_DRAM_SIZE_SUPPORT + EXTMEM_ALIGNMENT)) {
  110. pr_err("no extmem, get_max_DRAM_size:0x%p,CONFIG_MAX_DRAM_SIZE_SUPPORT:0x%x,get_max_phys_addr:0x%p\n",
  111. (void *)get_max_DRAM_size(),
  112. CONFIG_MAX_DRAM_SIZE_SUPPORT,
  113. (void *)get_max_phys_addr());
  114. BUG();
  115. }
  116. extmem_mspace_size = get_max_DRAM_size() - CONFIG_MAX_DRAM_SIZE_SUPPORT - EXTMEM_ALIGNMENT;
  117. if (extmem_mspace_size > extmem_vmalloc_limit) {
  118. pr_err("extmem_mspace_size: 0x%zx over limit: 0x%zx\n",
  119. extmem_mspace_size, extmem_vmalloc_limit);
  120. extmem_mspace_size = extmem_vmalloc_limit;
  121. }
  122. }
  123. /* extmem_mspace_base = (void *)ioremap(get_max_phys_addr(), extmem_mspace_size);*/
  124. extmem_mspace_base = (void *)ioremap_cached(get_max_phys_addr(), extmem_mspace_size);
  125. extmem_mspace = create_mspace_with_base(extmem_mspace_base, extmem_mspace_size, 1);
  126. extmem_printk("get_max_DRAM_size:0x%x,CONFIG_MAX_DRAM_SIZE_SUPPORT:0x%x,get_max_phys_addr:0x%p,extmem_mspace:0x%p\n",
  127. get_max_DRAM_size(),
  128. CONFIG_MAX_DRAM_SIZE_SUPPORT,
  129. (void *)get_max_phys_addr(),
  130. extmem_mspace);
  131. }
  132. }
  133. #endif
  134. void *extmem_malloc(size_t bytes)
  135. {
  136. void *mem;
  137. extmem_init();
  138. mem = mspace_malloc(extmem_mspace, bytes);
  139. extmem_printk("%s mem:0x%p, size: 0x%zx\n", __func__, mem, bytes);
  140. extmem_printk("%s extmem current used: 0x%zx, peak used: 0x%zx\n",
  141. __func__, mspace_mem_used(extmem_mspace), mspace_mem_used_peak(extmem_mspace));
  142. return mem;
  143. }
  144. EXPORT_SYMBOL(extmem_malloc);
  145. void *extmem_malloc_page_align(size_t bytes)
  146. {
  147. void *mem;
  148. extmem_init();
  149. mem = mspace_memalign(extmem_mspace, 1<<PAGE_SHIFT, bytes);
  150. extmem_printk("%s mem:0x%p, size: 0x%zx\n", __func__, mem, bytes);
  151. extmem_printk("%s extmem current used: 0x%zx, peak used: 0x%zx\n",
  152. __func__, mspace_mem_used(extmem_mspace), mspace_mem_used_peak(extmem_mspace));
  153. return mem;
  154. }
  155. EXPORT_SYMBOL(extmem_malloc_page_align);
  156. void extmem_free(void *mem)
  157. {
  158. extmem_printk("%s addr:0x%p\n", __func__, mem);
  159. if (extmem_mspace != NULL) {
  160. mspace_free(extmem_mspace, mem);
  161. extmem_printk("%s extmem current used: 0x%zx, peak used: 0x%zx\n",
  162. __func__, mspace_mem_used(extmem_mspace), mspace_mem_used_peak(extmem_mspace));
  163. }
  164. }
  165. EXPORT_SYMBOL(extmem_free);
  166. static unsigned long get_phys_from_mspace(unsigned long va)
  167. {
  168. #ifdef CONFIG_OF
  169. extmem_printk("%s va: 0x%lx extmem_phys_base:0x%p extmem_mspace_base:0x%p\n",
  170. __func__, va, (void *)extmem_phys_base, extmem_mspace_base);
  171. return va - (unsigned long)extmem_mspace_base + extmem_phys_base;
  172. #else
  173. return va - (unsigned long)extmem_mspace_base + get_max_phys_addr();
  174. #endif
  175. }
  176. unsigned long get_virt_from_mspace(unsigned long pa)
  177. {
  178. #ifdef CONFIG_OF
  179. extmem_printk("%s pa:0x%lx extmem_phys_base:0x%p extmem_mspace_base:0x%p\n",
  180. __func__, pa, (void *)extmem_phys_base, extmem_mspace_base);
  181. return pa - extmem_phys_base + (unsigned long)extmem_mspace_base;
  182. #else
  183. return pa - get_max_phys_addr() + (unsigned long)extmem_mspace_base;
  184. #endif
  185. }
  186. EXPORT_SYMBOL(get_virt_from_mspace);
  187. static void extmem_vma_close(struct vm_area_struct *vma)
  188. {
  189. /* if (extmem_in_mspace(vma))*/
  190. extmem_free((void *)get_virt_from_mspace((vma->vm_pgoff << PAGE_SHIFT)));
  191. }
  192. static const struct vm_operations_struct exm_vm_ops = {
  193. .close = extmem_vma_close,
  194. };
  195. bool extmem_in_mspace(struct vm_area_struct *vma)
  196. {
  197. return vma->vm_ops == &exm_vm_ops;
  198. }
  199. EXPORT_SYMBOL(extmem_in_mspace);
  200. size_t extmem_get_mem_size(unsigned long pgoff)
  201. {
  202. void *va = (void *)get_virt_from_mspace(pgoff << PAGE_SHIFT);
  203. mchunkptr p = mem2chunk(va);
  204. size_t psize = chunksize(p) - TWO_SIZE_T_SIZES;
  205. extmem_printk("%s size: %zu\n", __func__, psize);
  206. return psize;
  207. }
  208. EXPORT_SYMBOL(extmem_get_mem_size);
  209. static int mtk_mspace_mmap_physical(struct exm_info *info, struct vm_area_struct *vma)
  210. {
  211. unsigned long size = vma->vm_end - vma->vm_start;
  212. void *va = NULL;
  213. unsigned long pa;
  214. int ret = -EINVAL;
  215. if ((vma->vm_flags & VM_SHARED) == 0)
  216. return -EINVAL;
  217. vma->vm_ops = &exm_vm_ops;
  218. va = extmem_malloc_page_align(size);
  219. if (!va) {
  220. pr_err("%s failed...\n", __func__);
  221. return -ENOMEM;
  222. }
  223. memset(va, 0, size);
  224. vma->vm_flags |= (VM_DONTCOPY | VM_DONTEXPAND);
  225. #if !defined(CONFIG_ARM64)
  226. vma->vm_page_prot = __pgprot_modify(vma->vm_page_prot, L_PTE_MT_MASK, L_PTE_MT_WRITEBACK);
  227. #endif
  228. pa = get_phys_from_mspace((unsigned long) va);
  229. ret = remap_pfn_range(vma,
  230. vma->vm_start,
  231. (pa >> PAGE_SHIFT),
  232. size,
  233. #if !defined(CONFIG_ARM64)
  234. vma->vm_page_prot);
  235. #else
  236. PAGE_SHARED);
  237. #endif
  238. extmem_printk("pa:0x%lx, va:0x%p,vma->vm_pgoff:0x%lx,vm_start:0x%lx, vm_end:0x%lx,vm_page_prot:0x%zx\n",
  239. pa, va,
  240. vma->vm_pgoff,
  241. vma->vm_start, vma->vm_end,
  242. (size_t)pgprot_val(vma->vm_page_prot));
  243. if (ret)
  244. pr_err("%s fail ret:%d\n", __func__, ret);
  245. return ret;
  246. }
  247. static int mt_mspace_probe(struct platform_device *dev)
  248. {
  249. /* struct resource *regs; */
  250. struct exm_info *info;
  251. extmem_printk("probing mt_mspace\n");
  252. info = kzalloc(sizeof(struct exm_info), GFP_KERNEL);
  253. if (!info)
  254. return -ENOMEM;
  255. extmem_init();
  256. #ifdef CONFIG_OF
  257. info->mem[0].addr = extmem_phys_base;
  258. #else
  259. info->mem[0].addr = get_max_phys_addr();
  260. #endif
  261. info->mem[0].size = extmem_mspace_size;
  262. info->mmap = mtk_mspace_mmap_physical;
  263. if (!info->mem[0].addr) {
  264. dev_err(&dev->dev, "Invalid memory resource\n");
  265. return -ENODEV;
  266. }
  267. info->version = "0.0.2";
  268. info->name = DEV_DRV_NAME;
  269. if (exm_register_device(&dev->dev, info)) {
  270. iounmap(info->mem[0].internal_addr);
  271. pr_err("exm_register failed\n");
  272. return -ENODEV;
  273. }
  274. platform_set_drvdata(dev, info);
  275. extmem_printk("probing mt_mspace success\n");
  276. return 0;
  277. }
  278. static int mt_mspace_remove(struct platform_device *dev)
  279. {
  280. struct exm_info *info = platform_get_drvdata(dev);
  281. exm_unregister_device(info);
  282. platform_set_drvdata(dev, NULL);
  283. iounmap(info->mem[0].internal_addr);
  284. kfree(info);
  285. return 0;
  286. }
  287. #ifdef CONFIG_OF
  288. static const struct of_device_id extmem_of_ids[] = {
  289. { .compatible = "mediatek,mt-extmem", },
  290. {}
  291. };
  292. #endif
  293. static struct platform_driver mt_mspace_driver = {
  294. .probe = mt_mspace_probe,
  295. .remove = mt_mspace_remove,
  296. .driver = {
  297. .name = DEV_DRV_NAME,
  298. #ifdef CONFIG_OF
  299. .of_match_table = of_match_ptr(extmem_of_ids),
  300. #endif
  301. },
  302. };
  303. static int __init mt_mspace_init(void)
  304. {
  305. extmem_printk("%s\n", __func__);
  306. return platform_driver_register(&mt_mspace_driver);
  307. }
  308. static void __exit mt_mspace_exit(void)
  309. {
  310. platform_driver_unregister(&mt_mspace_driver);
  311. }
  312. static size_t extmem_used; /* extmem current used */
  313. static size_t extmem_used_peak; /* extmem peak used */
  314. static int param_get_extmem_used(char *buffer, const struct kernel_param *kp)
  315. {
  316. int result = 0;
  317. extmem_used = mspace_mem_used(extmem_mspace);
  318. extmem_used_peak = mspace_mem_used_peak(extmem_mspace);
  319. result = sprintf(buffer, "current_used: %10zu bytes\npeak_used: %10zu bytes\n", extmem_used, extmem_used_peak);
  320. return result;
  321. }
  322. static const struct kernel_param_ops param_ops_extmem_used = {
  323. .set = param_set_uint,
  324. .get = param_get_extmem_used,
  325. };
  326. module_param_cb(mem_used, &param_ops_extmem_used, &extmem_used, 0644);
  327. module_init(mt_mspace_init);
  328. module_exit(mt_mspace_exit);
  329. MODULE_LICENSE("GPL");