iosm_ipc_trace.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020-2021 Intel Corporation.
  4. */
  5. #include <linux/wwan.h>
  6. #include "iosm_ipc_trace.h"
  7. /* sub buffer size and number of sub buffer */
  8. #define IOSM_TRC_SUB_BUFF_SIZE 131072
  9. #define IOSM_TRC_N_SUB_BUFF 32
  10. #define IOSM_TRC_FILE_PERM 0600
  11. #define IOSM_TRC_DEBUGFS_TRACE "trace"
  12. #define IOSM_TRC_DEBUGFS_TRACE_CTRL "trace_ctrl"
  13. /**
  14. * ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer
  15. * @ipc_imem: Pointer to iosm_imem structure
  16. * @skb: Pointer to struct sk_buff
  17. */
  18. void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
  19. {
  20. struct iosm_trace *ipc_trace = ipc_imem->trace;
  21. if (ipc_trace->ipc_rchan)
  22. relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
  23. dev_kfree_skb(skb);
  24. }
  25. /* Creates relay file in debugfs. */
  26. static struct dentry *
  27. ipc_trace_create_buf_file_handler(const char *filename,
  28. struct dentry *parent,
  29. umode_t mode,
  30. struct rchan_buf *buf,
  31. int *is_global)
  32. {
  33. *is_global = 1;
  34. return debugfs_create_file(filename, mode, parent, buf,
  35. &relay_file_operations);
  36. }
  37. /* Removes relay file from debugfs. */
  38. static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
  39. {
  40. debugfs_remove(dentry);
  41. return 0;
  42. }
  43. static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
  44. void *prev_subbuf,
  45. size_t prev_padding)
  46. {
  47. if (relay_buf_full(buf)) {
  48. pr_err_ratelimited("Relay_buf full dropping traces");
  49. return 0;
  50. }
  51. return 1;
  52. }
  53. /* Relay interface callbacks */
  54. static struct rchan_callbacks relay_callbacks = {
  55. .subbuf_start = ipc_trace_subbuf_start_handler,
  56. .create_buf_file = ipc_trace_create_buf_file_handler,
  57. .remove_buf_file = ipc_trace_remove_buf_file_handler,
  58. };
  59. /* Copy the trace control mode to user buffer */
  60. static ssize_t ipc_trace_ctrl_file_read(struct file *filp, char __user *buffer,
  61. size_t count, loff_t *ppos)
  62. {
  63. struct iosm_trace *ipc_trace = filp->private_data;
  64. char buf[16];
  65. int len;
  66. mutex_lock(&ipc_trace->trc_mutex);
  67. len = snprintf(buf, sizeof(buf), "%d\n", ipc_trace->mode);
  68. mutex_unlock(&ipc_trace->trc_mutex);
  69. return simple_read_from_buffer(buffer, count, ppos, buf, len);
  70. }
  71. /* Open and close the trace channel depending on user input */
  72. static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
  73. const char __user *buffer,
  74. size_t count, loff_t *ppos)
  75. {
  76. struct iosm_trace *ipc_trace = filp->private_data;
  77. unsigned long val;
  78. int ret;
  79. ret = kstrtoul_from_user(buffer, count, 10, &val);
  80. if (ret)
  81. return ret;
  82. mutex_lock(&ipc_trace->trc_mutex);
  83. if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) {
  84. ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem,
  85. ipc_trace->chl_id,
  86. IPC_HP_CDEV_OPEN);
  87. if (!ipc_trace->channel) {
  88. ret = -EIO;
  89. goto unlock;
  90. }
  91. ipc_trace->mode = TRACE_ENABLE;
  92. } else if (val == TRACE_DISABLE && ipc_trace->mode != TRACE_DISABLE) {
  93. ipc_trace->mode = TRACE_DISABLE;
  94. /* close trace channel */
  95. ipc_imem_sys_port_close(ipc_trace->ipc_imem,
  96. ipc_trace->channel);
  97. relay_flush(ipc_trace->ipc_rchan);
  98. }
  99. ret = count;
  100. unlock:
  101. mutex_unlock(&ipc_trace->trc_mutex);
  102. return ret;
  103. }
  104. static const struct file_operations ipc_trace_fops = {
  105. .open = simple_open,
  106. .write = ipc_trace_ctrl_file_write,
  107. .read = ipc_trace_ctrl_file_read,
  108. };
  109. /**
  110. * ipc_trace_init - Create trace interface & debugfs entries
  111. * @ipc_imem: Pointer to iosm_imem structure
  112. *
  113. * Returns: Pointer to trace instance on success else NULL
  114. */
  115. struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
  116. {
  117. struct ipc_chnl_cfg chnl_cfg = { 0 };
  118. struct iosm_trace *ipc_trace;
  119. ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
  120. ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
  121. IRQ_MOD_OFF);
  122. ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
  123. if (!ipc_trace)
  124. return NULL;
  125. ipc_trace->mode = TRACE_DISABLE;
  126. ipc_trace->dev = ipc_imem->dev;
  127. ipc_trace->ipc_imem = ipc_imem;
  128. ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3;
  129. mutex_init(&ipc_trace->trc_mutex);
  130. ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
  131. IOSM_TRC_FILE_PERM,
  132. ipc_imem->debugfs_dir,
  133. ipc_trace, &ipc_trace_fops);
  134. ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
  135. ipc_imem->debugfs_dir,
  136. IOSM_TRC_SUB_BUFF_SIZE,
  137. IOSM_TRC_N_SUB_BUFF,
  138. &relay_callbacks, NULL);
  139. return ipc_trace;
  140. }
  141. /**
  142. * ipc_trace_deinit - Closing relayfs, removing debugfs entries
  143. * @ipc_trace: Pointer to the iosm_trace data struct
  144. */
  145. void ipc_trace_deinit(struct iosm_trace *ipc_trace)
  146. {
  147. if (!ipc_trace)
  148. return;
  149. debugfs_remove(ipc_trace->ctrl_file);
  150. relay_close(ipc_trace->ipc_rchan);
  151. mutex_destroy(&ipc_trace->trc_mutex);
  152. kfree(ipc_trace);
  153. }