ath_procfs.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for
  5. * any purpose with or without fee is hereby granted, provided that the
  6. * above copyright notice and this permission notice appear in all
  7. * copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  10. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  11. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  12. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  13. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  14. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  16. * PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #if defined(CONFIG_ATH_PROCFS_DIAG_SUPPORT)
  19. #include <linux/module.h> /* Specifically, a module */
  20. #include <linux/kernel.h> /* We're doing kernel work */
  21. #include <linux/version.h> /* We're doing kernel work */
  22. #include <linux/proc_fs.h> /* Necessary because we use the proc fs */
  23. #include <linux/uaccess.h> /* for copy_from_user */
  24. #include "hif.h"
  25. #include "hif_main.h"
  26. #if defined(HIF_USB)
  27. #include "if_usb.h"
  28. #endif
  29. #if defined(HIF_SDIO)
  30. #include "if_sdio.h"
  31. #endif
  32. #include "hif_debug.h"
  33. #include "pld_common.h"
  34. #include "target_type.h"
  35. #define PROCFS_NAME "athdiagpfs"
  36. #ifdef MULTI_IF_NAME
  37. #define PROCFS_DIR "cld" MULTI_IF_NAME
  38. #else
  39. #define PROCFS_DIR "cld"
  40. #endif
  41. /**
  42. * This structure hold information about the /proc file
  43. *
  44. */
  45. static struct proc_dir_entry *proc_file, *proc_dir;
  46. static void *get_hif_hdl_from_file(struct file *file)
  47. {
  48. struct hif_opaque_softc *scn;
  49. scn = (struct hif_opaque_softc *)PDE_DATA(file_inode(file));
  50. return (void *)scn;
  51. }
  52. static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
  53. size_t count, loff_t *pos)
  54. {
  55. hif_handle_t hif_hdl;
  56. int rv;
  57. uint8_t *read_buffer = NULL;
  58. struct hif_softc *scn;
  59. uint32_t offset = 0, memtype = 0;
  60. struct hif_target_info *tgt_info;
  61. hif_hdl = get_hif_hdl_from_file(file);
  62. scn = HIF_GET_SOFTC(hif_hdl);
  63. if (scn->bus_ops.hif_addr_in_boundary(hif_hdl, (uint32_t)(*pos)))
  64. return -EINVAL;
  65. read_buffer = qdf_mem_malloc(count);
  66. if (!read_buffer)
  67. return -ENOMEM;
  68. HIF_DBG("rd buff 0x%pK cnt %zu offset 0x%x buf 0x%pK",
  69. read_buffer, count, (int)*pos, buf);
  70. tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
  71. if ((scn->bus_type == QDF_BUS_TYPE_SNOC) ||
  72. (scn->bus_type == QDF_BUS_TYPE_PCI &&
  73. ((tgt_info->target_type == TARGET_TYPE_QCA6290) ||
  74. (tgt_info->target_type == TARGET_TYPE_QCA6390) ||
  75. (tgt_info->target_type == TARGET_TYPE_QCA6490) ||
  76. (tgt_info->target_type == TARGET_TYPE_QCA8074) ||
  77. (tgt_info->target_type == TARGET_TYPE_QCA8074V2) ||
  78. (tgt_info->target_type == TARGET_TYPE_QCN9000) ||
  79. (tgt_info->target_type == TARGET_TYPE_QCA5018) ||
  80. (tgt_info->target_type == TARGET_TYPE_QCA6018))) ||
  81. (scn->bus_type == QDF_BUS_TYPE_IPCI &&
  82. (tgt_info->target_type == TARGET_TYPE_QCA6750)) ||
  83. ((scn->bus_type == QDF_BUS_TYPE_USB) &&
  84. (tgt_info->target_type == TARGET_TYPE_QCN7605))) {
  85. memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
  86. offset = (uint32_t)(*pos) & 0xffffff;
  87. HIF_DBG("%s: offset 0x%x memtype 0x%x, datalen %zu\n",
  88. __func__, offset, memtype, count);
  89. rv = pld_athdiag_read(scn->qdf_dev->dev,
  90. offset, memtype, count,
  91. (uint8_t *)read_buffer);
  92. goto out;
  93. }
  94. if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
  95. /* reading a word? */
  96. rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos),
  97. (uint32_t *)read_buffer);
  98. } else {
  99. rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos),
  100. (uint8_t *)read_buffer, count);
  101. }
  102. out:
  103. if (rv) {
  104. qdf_mem_free(read_buffer);
  105. return -EIO;
  106. }
  107. if (copy_to_user(buf, read_buffer, count)) {
  108. qdf_mem_free(read_buffer);
  109. HIF_ERROR("%s: copy_to_user error in /proc/%s",
  110. __func__, PROCFS_NAME);
  111. return -EFAULT;
  112. }
  113. qdf_mem_free(read_buffer);
  114. return count;
  115. }
  116. static ssize_t ath_procfs_diag_write(struct file *file,
  117. const char __user *buf,
  118. size_t count, loff_t *pos)
  119. {
  120. hif_handle_t hif_hdl;
  121. int rv;
  122. uint8_t *write_buffer = NULL;
  123. struct hif_softc *scn;
  124. uint32_t offset = 0, memtype = 0;
  125. struct hif_target_info *tgt_info;
  126. hif_hdl = get_hif_hdl_from_file(file);
  127. scn = HIF_GET_SOFTC(hif_hdl);
  128. if (scn->bus_ops.hif_addr_in_boundary(hif_hdl, (uint32_t)(*pos)))
  129. return -EINVAL;
  130. write_buffer = qdf_mem_malloc(count);
  131. if (!write_buffer)
  132. return -ENOMEM;
  133. if (copy_from_user(write_buffer, buf, count)) {
  134. qdf_mem_free(write_buffer);
  135. HIF_ERROR("%s: copy_to_user error in /proc/%s",
  136. __func__, PROCFS_NAME);
  137. return -EFAULT;
  138. }
  139. HIF_DBG("wr buff 0x%pK buf 0x%pK cnt %zu offset 0x%x value 0x%x",
  140. write_buffer, buf, count,
  141. (int)*pos, *((uint32_t *) write_buffer));
  142. tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
  143. if ((scn->bus_type == QDF_BUS_TYPE_SNOC) ||
  144. ((scn->bus_type == QDF_BUS_TYPE_PCI) &&
  145. ((tgt_info->target_type == TARGET_TYPE_QCA6290) ||
  146. (tgt_info->target_type == TARGET_TYPE_QCA6390) ||
  147. (tgt_info->target_type == TARGET_TYPE_QCA6490) ||
  148. (tgt_info->target_type == TARGET_TYPE_QCA8074) ||
  149. (tgt_info->target_type == TARGET_TYPE_QCA8074V2) ||
  150. (tgt_info->target_type == TARGET_TYPE_QCN9000) ||
  151. (tgt_info->target_type == TARGET_TYPE_QCA5018) ||
  152. (tgt_info->target_type == TARGET_TYPE_QCA6018))) ||
  153. (scn->bus_type == QDF_BUS_TYPE_IPCI &&
  154. (tgt_info->target_type == TARGET_TYPE_QCA6750)) ||
  155. ((scn->bus_type == QDF_BUS_TYPE_USB) &&
  156. (tgt_info->target_type == TARGET_TYPE_QCN7605))) {
  157. memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
  158. offset = (uint32_t)(*pos) & 0xffffff;
  159. HIF_DBG("%s: offset 0x%x memtype 0x%x, datalen %zu\n",
  160. __func__, offset, memtype, count);
  161. rv = pld_athdiag_write(scn->qdf_dev->dev,
  162. offset, memtype, count,
  163. (uint8_t *)write_buffer);
  164. goto out;
  165. }
  166. if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
  167. /* reading a word? */
  168. uint32_t value = *((uint32_t *)write_buffer);
  169. rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value);
  170. } else {
  171. rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos),
  172. (uint8_t *)write_buffer, count);
  173. }
  174. out:
  175. qdf_mem_free(write_buffer);
  176. if (rv == 0)
  177. return count;
  178. else
  179. return -EIO;
  180. }
  181. static const struct file_operations athdiag_fops = {
  182. .read = ath_procfs_diag_read,
  183. .write = ath_procfs_diag_write,
  184. };
  185. /*
  186. * This function is called when the module is loaded
  187. *
  188. */
  189. int athdiag_procfs_init(void *scn)
  190. {
  191. proc_dir = proc_mkdir(PROCFS_DIR, NULL);
  192. if (!proc_dir) {
  193. remove_proc_entry(PROCFS_DIR, NULL);
  194. HIF_ERROR("%s: Error: Could not initialize /proc/%s",
  195. __func__, PROCFS_DIR);
  196. return -ENOMEM;
  197. }
  198. proc_file = proc_create_data(PROCFS_NAME, 0600, proc_dir,
  199. &athdiag_fops, (void *)scn);
  200. if (!proc_file) {
  201. remove_proc_entry(PROCFS_NAME, proc_dir);
  202. HIF_ERROR("%s: Could not initialize /proc/%s",
  203. __func__, PROCFS_NAME);
  204. return -ENOMEM;
  205. }
  206. HIF_DBG("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME);
  207. return 0; /* everything is ok */
  208. }
  209. /*
  210. * This function is called when the module is unloaded
  211. *
  212. */
  213. void athdiag_procfs_remove(void)
  214. {
  215. if (proc_dir) {
  216. remove_proc_entry(PROCFS_NAME, proc_dir);
  217. HIF_DBG("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME);
  218. remove_proc_entry(PROCFS_DIR, NULL);
  219. HIF_DBG("/proc/%s removed", PROCFS_DIR);
  220. proc_dir = NULL;
  221. }
  222. }
  223. #else
  224. int athdiag_procfs_init(void *scn)
  225. {
  226. return 0;
  227. }
  228. void athdiag_procfs_remove(void) {}
  229. #endif