vha_sc_dbg.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. *****************************************************************************
  3. * Copyright (c) Imagination Technologies Ltd.
  4. *
  5. * The contents of this file are subject to the MIT license as set out below.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of the
  26. * GNU General Public License Version 2 ("GPL")in which case the provisions of
  27. * GPL are applicable instead of those above.
  28. *
  29. * If you wish to allow use of your version of this file only under the terms
  30. * of GPL, and not to allow others to use your version of this file under the
  31. * terms of the MIT license, indicate your decision by deleting the provisions
  32. * above and replace them with the notice and other provisions required by GPL
  33. * as set out in the file called "GPLHEADER" included in this distribution. If
  34. * you do not delete the provisions above, a recipient may use your version of
  35. * this file under the terms of either the MIT license or GPL.
  36. *
  37. * This License is also included in this distribution in the file called
  38. * "MIT_COPYING".
  39. *
  40. *****************************************************************************/
  41. #include <linux/delay.h>
  42. #include <linux/slab.h>
  43. #include <linux/device.h>
  44. #include <linux/gfp.h>
  45. #include <linux/moduleparam.h>
  46. #include <linux/list.h>
  47. #include <linux/debugfs.h>
  48. #include <linux/uaccess.h>
  49. #include <uapi/vha.h>
  50. #include "vha_common.h"
  51. #include "vha_plat.h"
  52. #include "vha_io.h"
  53. #define VHA_MAX_NUM_SEGMENTS 10
  54. static bool generate_crcs_enable = true;
  55. module_param(generate_crcs_enable, bool, 0444);
  56. MODULE_PARM_DESC(generate_crcs_enable,
  57. "Enable generating safety CRCs");
  58. struct vha_sc_dbgfs_ctx {
  59. struct dentry *sc_debugfs_dir;
  60. struct dentry *crcs_dir;
  61. struct dentry *crcs_sub_dirs[VHA_MAX_NUM_SEGMENTS];
  62. uint32_t num_cores_used[VHA_MAX_NUM_SEGMENTS];
  63. uint32_t latest_crcs[VHA_MAX_NUM_SEGMENTS][VHA_NUM_CORES];
  64. uint8_t segment_crc_idx_to_use;
  65. uint8_t num_segments;
  66. };
  67. static ssize_t vha_bin_crcs_read(struct file *file, char __user *buf,
  68. size_t count, loff_t *ppos)
  69. {
  70. struct vha_dev *vha = file->private_data;
  71. uint32_t bin_crcs[VHA_MAX_NUM_SEGMENTS * VHA_MAX_CORES] = { 0 };
  72. struct vha_sc_dbgfs_ctx *ctx = (struct vha_sc_dbgfs_ctx *)vha->sc_dbgfs_ctx;
  73. size_t bytes = 0;
  74. uint32_t offset = 0;
  75. int i, j;
  76. if (*ppos)
  77. return 0;
  78. for (i = 0; i < ctx->num_segments; i++) {
  79. for (j = 0; j < ctx->num_cores_used[i]; j++) {
  80. bin_crcs[offset] = ctx->latest_crcs[i][j];
  81. offset++;
  82. }
  83. }
  84. if (copy_to_user(buf, bin_crcs, offset * sizeof(bin_crcs[0]))) {
  85. dev_err(vha->dev, "%s: bin_crcs read: copy to user failed\n",
  86. __func__);
  87. return -EFAULT;
  88. }
  89. if (count < offset)
  90. return -EINVAL;
  91. bytes = offset * sizeof(uint32_t);
  92. *ppos = bytes;
  93. return bytes;
  94. }
  95. static const struct file_operations vha_crcs_bin_fops = {
  96. .owner = THIS_MODULE,
  97. .open = simple_open,
  98. .read = vha_bin_crcs_read,
  99. };
  100. static ssize_t vha_crcs_reset_write(struct file *file, const char __user *buf,
  101. size_t count, loff_t *ppos)
  102. {
  103. struct vha_dev *vha = file->private_data;
  104. struct vha_sc_dbgfs_ctx *ctx = (struct vha_sc_dbgfs_ctx *)vha->sc_dbgfs_ctx;
  105. if (ctx->crcs_dir) {
  106. int i = 0;
  107. for (i = 0; i < VHA_MAX_NUM_SEGMENTS; i++)
  108. if (ctx->crcs_sub_dirs[i]) {
  109. debugfs_remove_recursive(ctx->crcs_sub_dirs[i]);
  110. ctx->crcs_sub_dirs[i] = NULL;
  111. }
  112. ctx->segment_crc_idx_to_use = 0;
  113. memset(ctx->latest_crcs, 0, sizeof(ctx->latest_crcs));
  114. memset(ctx->num_cores_used, 0, sizeof(ctx->num_cores_used));
  115. }
  116. return count;
  117. }
  118. static const struct file_operations vha_crcs_reset_fops = {
  119. .write = vha_crcs_reset_write,
  120. .open = simple_open,
  121. };
  122. void vha_update_crcs(struct vha_dev *vha, uint32_t crcs[VHA_NUM_CORES], int n) {
  123. struct vha_sc_dbgfs_ctx *ctx = (struct vha_sc_dbgfs_ctx *)vha->sc_dbgfs_ctx;
  124. if (ctx->crcs_dir && ctx->num_segments) {
  125. uint8_t i;
  126. uint8_t crc_idx = ctx->segment_crc_idx_to_use;
  127. char core_txt[7] = "core_x";
  128. if (crc_idx >= VHA_MAX_NUM_SEGMENTS) {
  129. dev_warn_once(vha->dev, "%s: unable to update crcs, too many segments\n", __func__);
  130. return;
  131. }
  132. if (ctx->crcs_sub_dirs[crc_idx] == NULL) {
  133. char dir_txt[10] = "segment_x";
  134. snprintf(dir_txt, sizeof(dir_txt), "segment_%d", crc_idx);
  135. ctx->crcs_sub_dirs[crc_idx] = debugfs_create_dir(dir_txt, ctx->crcs_dir);
  136. for (i = 0; i < n; i++) {
  137. snprintf(core_txt, sizeof(core_txt), "core_%d", i);
  138. debugfs_create_x32(core_txt, S_IRUGO, ctx->crcs_sub_dirs[crc_idx],
  139. &ctx->latest_crcs[crc_idx][i]);
  140. }
  141. }
  142. ctx->num_cores_used[crc_idx] = n;
  143. for (i = 0; i < n; i++)
  144. ctx->latest_crcs[crc_idx][i] = crcs[i];
  145. ctx->segment_crc_idx_to_use++;
  146. if (ctx->segment_crc_idx_to_use >= ctx->num_segments)
  147. ctx->segment_crc_idx_to_use = 0;
  148. }
  149. }
  150. void vha_sc_dbg_init(struct vha_dev *vha, struct dentry *debugfs_dir)
  151. {
  152. struct vha_sc_dbgfs_ctx *ctx = devm_kzalloc(vha->dev,
  153. sizeof(struct vha_sc_dbgfs_ctx), GFP_KERNEL);
  154. if (!ctx) {
  155. dev_err(vha->dev,
  156. "%s: Out of memory when creating debugfs context!\n",
  157. __func__);
  158. return;
  159. }
  160. /* Create userspace node */
  161. if (!debugfs_dir) {
  162. dev_warn(vha->dev,
  163. "%s: Probably debugfs not enabled in this kernel!\n",
  164. __func__);
  165. return;
  166. }
  167. #define VHA_DBGFS_CREATE_FILE_IN_DIR(_perm_, _name_, _fops_, dir) \
  168. { \
  169. if (!debugfs_create_file(_name_, \
  170. _perm_, ctx->dir, vha, \
  171. &vha_##_fops_##_fops)) { \
  172. dev_warn(vha->dev, \
  173. "%s: failed to create %s dbg file!\n", \
  174. __func__, _name_); \
  175. } \
  176. }
  177. #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
  178. #define CTX_DBGFS_CREATE_RW(_type_, _name_, _ctx_dev_member_, dir) \
  179. { \
  180. struct dentry *dentry; \
  181. debugfs_create_##_type_(_name_, \
  182. S_IWUSR|S_IRUGO, ctx->dir, \
  183. &ctx->_ctx_dev_member_); \
  184. dentry = debugfs_lookup(_name_, ctx->dir); \
  185. if (!dentry) { \
  186. dev_warn(vha->dev, \
  187. "%s: failed to create %s dbg file!\n", \
  188. __func__, _name_); \
  189. } else { \
  190. dput(dentry); \
  191. } \
  192. }
  193. #else
  194. #define CTX_DBGFS_CREATE_RW(_type_, _name_, _ctx_dev_member_, dir) \
  195. { \
  196. if (!debugfs_create_##_type_(_name_, \
  197. S_IWUSR|S_IRUGO, ctx->dir, \
  198. &ctx->_ctx_dev_member_)) { \
  199. dev_warn(vha->dev, \
  200. "%s: failed to create %s dbg file!\n", \
  201. __func__, _name_); \
  202. } \
  203. }
  204. #endif
  205. ctx->sc_debugfs_dir = debugfs_create_dir("sf_gen", debugfs_dir);
  206. CTX_DBGFS_CREATE_RW(u8, "num_segments", num_segments, sc_debugfs_dir);
  207. if (generate_crcs_enable) {
  208. ctx->crcs_dir = debugfs_create_dir("CRCs", ctx->sc_debugfs_dir);
  209. if (ctx->crcs_dir) {
  210. VHA_DBGFS_CREATE_FILE_IN_DIR(S_IWUSR, "crcs_reset", crcs_reset, crcs_dir);
  211. VHA_DBGFS_CREATE_FILE_IN_DIR(S_IRUGO, "crcs_bin", crcs_bin, crcs_dir);
  212. }
  213. }
  214. #undef VHA_DBGFS_CREATE_FILE_IN_DIR
  215. #undef CTX_DBGFS_CREATE_RW
  216. vha->sc_dbgfs_ctx = (void *)ctx;
  217. }
  218. void vha_sc_dbg_deinit(struct vha_dev *vha)
  219. {
  220. struct vha_sc_dbgfs_ctx *ctx =
  221. (struct vha_sc_dbgfs_ctx *)vha->sc_dbgfs_ctx;
  222. debugfs_remove_recursive(ctx->sc_debugfs_dir);
  223. }