msm_cache_dump.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/init.h>
  16. #include <linux/io.h>
  17. #include <linux/delay.h>
  18. #include <linux/workqueue.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/pm.h>
  21. #include <linux/memory_alloc.h>
  22. #include <linux/notifier.h>
  23. #include <linux/of.h>
  24. #include <linux/of_device.h>
  25. #include <linux/dma-mapping.h>
  26. #include <mach/scm.h>
  27. #include <mach/msm_cache_dump.h>
  28. #include <mach/msm_iomap.h>
  29. #include <mach/msm_memory_dump.h>
  30. #define L2_DUMP_OFFSET 0x14
  31. static dma_addr_t msm_cache_dump_addr;
  32. static void *msm_cache_dump_vaddr;
  33. /*
  34. * These should not actually be dereferenced. There's no
  35. * need for a virtual mapping, but the physical address is
  36. * necessary.
  37. */
  38. static struct l1_cache_dump *l1_dump;
  39. static struct l2_cache_dump *l2_dump;
  40. static int use_imem_dump_offset;
  41. static int msm_cache_dump_panic(struct notifier_block *this,
  42. unsigned long event, void *ptr)
  43. {
  44. #ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
  45. /*
  46. * Clear the bootloader magic so the dumps aren't overwritten
  47. */
  48. if (use_imem_dump_offset)
  49. __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
  50. scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
  51. scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
  52. #endif
  53. return 0;
  54. }
  55. static struct notifier_block msm_cache_dump_blk = {
  56. .notifier_call = msm_cache_dump_panic,
  57. /*
  58. * higher priority to ensure this runs before another panic handler
  59. * flushes the caches.
  60. */
  61. .priority = 1,
  62. };
  63. static int msm_cache_dump_probe(struct platform_device *pdev)
  64. {
  65. struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
  66. struct msm_client_dump l1_dump_entry, l2_dump_entry;
  67. int ret;
  68. struct {
  69. unsigned long buf;
  70. unsigned long size;
  71. } l1_cache_data;
  72. u32 l1_size, l2_size;
  73. unsigned long total_size;
  74. if (pdev->dev.of_node) {
  75. ret = of_property_read_u32(pdev->dev.of_node,
  76. "qcom,l1-dump-size", &l1_size);
  77. if (ret)
  78. return ret;
  79. ret = of_property_read_u32(pdev->dev.of_node,
  80. "qcom,l2-dump-size", &l2_size);
  81. if (ret)
  82. return ret;
  83. use_imem_dump_offset = of_property_read_bool(pdev->dev.of_node,
  84. "qcom,use-imem-dump-offset");
  85. } else {
  86. l1_size = d->l1_size;
  87. l2_size = d->l2_size;
  88. /* Non-DT targets assume the IMEM dump offset shall be used */
  89. use_imem_dump_offset = 1;
  90. };
  91. total_size = l1_size + l2_size;
  92. msm_cache_dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev,
  93. total_size, &msm_cache_dump_addr,
  94. GFP_KERNEL);
  95. if (!msm_cache_dump_vaddr) {
  96. pr_err("%s: Could not get memory for cache dumping\n",
  97. __func__);
  98. return -ENOMEM;
  99. }
  100. memset(msm_cache_dump_vaddr, 0xFF, total_size);
  101. /* Clean caches before sending buffer to TZ */
  102. clean_caches((unsigned long) msm_cache_dump_vaddr, total_size,
  103. msm_cache_dump_addr);
  104. l1_cache_data.buf = msm_cache_dump_addr;
  105. l1_cache_data.size = l1_size;
  106. ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
  107. &l1_cache_data, sizeof(l1_cache_data), NULL, 0);
  108. if (ret)
  109. pr_err("%s: could not register L1 buffer ret = %d.\n",
  110. __func__, ret);
  111. l1_dump = (struct l1_cache_dump *)(uint32_t)msm_cache_dump_addr;
  112. l2_dump = (struct l2_cache_dump *)(uint32_t)(msm_cache_dump_addr
  113. + l1_size);
  114. #if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
  115. l1_cache_data.buf = msm_cache_dump_addr + l1_size;
  116. l1_cache_data.size = l2_size;
  117. ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
  118. &l1_cache_data, sizeof(l1_cache_data), NULL, 0);
  119. if (ret)
  120. pr_err("%s: could not register L2 buffer ret = %d.\n",
  121. __func__, ret);
  122. #endif
  123. if (use_imem_dump_offset)
  124. __raw_writel(msm_cache_dump_addr + l1_size,
  125. MSM_IMEM_BASE + L2_DUMP_OFFSET);
  126. else {
  127. l1_dump_entry.id = MSM_L1_CACHE;
  128. l1_dump_entry.start_addr = msm_cache_dump_addr;
  129. l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1;
  130. l2_dump_entry.id = MSM_L2_CACHE;
  131. l2_dump_entry.start_addr = msm_cache_dump_addr + l1_size;
  132. l2_dump_entry.end_addr = l2_dump_entry.start_addr + l2_size - 1;
  133. ret = msm_dump_table_register(&l1_dump_entry);
  134. if (ret)
  135. pr_err("Could not register L1 dump area: %d\n", ret);
  136. ret = msm_dump_table_register(&l2_dump_entry);
  137. if (ret)
  138. pr_err("Could not register L2 dump area: %d\n", ret);
  139. }
  140. atomic_notifier_chain_register(&panic_notifier_list,
  141. &msm_cache_dump_blk);
  142. return 0;
  143. }
  144. static int msm_cache_dump_remove(struct platform_device *pdev)
  145. {
  146. atomic_notifier_chain_unregister(&panic_notifier_list,
  147. &msm_cache_dump_blk);
  148. return 0;
  149. }
  150. static struct of_device_id cache_dump_match_table[] = {
  151. { .compatible = "qcom,cache_dump", },
  152. {}
  153. };
  154. EXPORT_COMPAT("qcom,cache_dump");
  155. static struct platform_driver msm_cache_dump_driver = {
  156. .remove = __devexit_p(msm_cache_dump_remove),
  157. .driver = {
  158. .name = "msm_cache_dump",
  159. .owner = THIS_MODULE,
  160. .of_match_table = cache_dump_match_table,
  161. },
  162. };
  163. static int __init msm_cache_dump_init(void)
  164. {
  165. return platform_driver_probe(&msm_cache_dump_driver,
  166. msm_cache_dump_probe);
  167. }
  168. static void __exit msm_cache_dump_exit(void)
  169. {
  170. platform_driver_unregister(&msm_cache_dump_driver);
  171. }
  172. late_initcall(msm_cache_dump_init);
  173. module_exit(msm_cache_dump_exit)