qdf_debugfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. /*
  2. * Copyright (c) 2017-2021 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. /**
  19. * DOC: qdf_debugfs
  20. * This file provides QDF debug file system APIs
  21. */
  22. #include <qdf_debugfs.h>
  23. #include <i_qdf_debugfs.h>
  24. #include <qdf_mem.h>
  25. #include <qdf_trace.h>
  26. #include <qdf_module.h>
  27. /* A private structure definition to qdf sequence */
  28. struct qdf_debugfs_seq_priv {
  29. bool stop;
  30. };
  31. /* entry for root debugfs directory*/
  32. static qdf_dentry_t qdf_debugfs_root;
  33. QDF_STATUS qdf_debugfs_init(void)
  34. {
  35. qdf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
  36. if (!qdf_debugfs_root)
  37. return QDF_STATUS_E_FAILURE;
  38. return QDF_STATUS_SUCCESS;
  39. }
  40. qdf_export_symbol(qdf_debugfs_init);
  41. void qdf_debugfs_exit(void)
  42. {
  43. if (!qdf_debugfs_root)
  44. return;
  45. debugfs_remove_recursive(qdf_debugfs_root);
  46. qdf_debugfs_root = NULL;
  47. }
  48. qdf_export_symbol(qdf_debugfs_exit);
  49. qdf_dentry_t qdf_debugfs_get_root(void)
  50. {
  51. return qdf_debugfs_root;
  52. }
  53. qdf_export_symbol(qdf_debugfs_get_root);
  54. umode_t qdf_debugfs_get_filemode(uint16_t mode)
  55. {
  56. umode_t ret = 0;
  57. if (mode & QDF_FILE_USR_READ)
  58. ret |= 0400;
  59. if (mode & QDF_FILE_USR_WRITE)
  60. ret |= 0200;
  61. if (mode & QDF_FILE_GRP_READ)
  62. ret |= 0040;
  63. if (mode & QDF_FILE_GRP_WRITE)
  64. ret |= 0020;
  65. if (mode & QDF_FILE_OTH_READ)
  66. ret |= 0004;
  67. if (mode & QDF_FILE_OTH_WRITE)
  68. ret |= 0002;
  69. return ret;
  70. }
  71. /**
  72. * ---------------------- Implementation note ---------------------------------
  73. *
  74. * A read in debugfs file triggers seq_read() which calls seq_read api. A
  75. * sequence begins with the call of the function start(). If the return is a non
  76. * NULL value, the function next() is called. This function is an iterator, the
  77. * goal is to go though all the data. Each time next() is called, the function
  78. * show() is also called. It writes data values in the buffer read by the user.
  79. * The function next() is called until it returns NULL. The sequence ends when
  80. * next() returns NULL, then the function stop() is called.
  81. *
  82. * NOTE: When a sequence is finished, another one starts. That means that
  83. * at the end of function stop(), the function start() is called again. This
  84. * loop finishes when the function start() returns NULL.
  85. * ----------------------------------------------------------------------------
  86. */
  87. /* .seq_start() */
  88. static void *qdf_debugfs_seq_start(struct seq_file *seq, loff_t *pos)
  89. {
  90. struct qdf_debugfs_seq_priv *priv;
  91. priv = qdf_mem_malloc(sizeof(*priv));
  92. if (!priv)
  93. return NULL;
  94. priv->stop = false;
  95. return priv;
  96. }
  97. /* .seq_next() */
  98. static void *qdf_debugfs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  99. {
  100. struct qdf_debugfs_seq_priv *priv = v;
  101. if (priv)
  102. ++*pos;
  103. if (priv && priv->stop) {
  104. qdf_mem_free(priv);
  105. priv = NULL;
  106. }
  107. return priv;
  108. }
  109. /* .seq_stop() */
  110. static void qdf_debugfs_seq_stop(struct seq_file *seq, void *v)
  111. {
  112. qdf_mem_free(v);
  113. }
  114. /* .seq_show() */
  115. static int qdf_debugfs_seq_show(struct seq_file *seq, void *v)
  116. {
  117. struct qdf_debugfs_seq_priv *priv = v;
  118. struct qdf_debugfs_fops *fops;
  119. QDF_STATUS status;
  120. fops = seq->private;
  121. if (fops && fops->show) {
  122. status = fops->show(seq, fops->priv);
  123. if (priv && (status != QDF_STATUS_E_AGAIN))
  124. priv->stop = true;
  125. }
  126. return 0;
  127. }
  128. void qdf_debugfs_printf(qdf_debugfs_file_t file, const char *f, ...)
  129. {
  130. va_list args;
  131. va_start(args, f);
  132. seq_vprintf(file, f, args);
  133. va_end(args);
  134. }
  135. qdf_export_symbol(qdf_debugfs_printf);
  136. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
  137. void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf,
  138. qdf_size_t len, int rowsize, int groupsize)
  139. {
  140. seq_hex_dump(file, "", DUMP_PREFIX_OFFSET, rowsize, groupsize, buf, len,
  141. false);
  142. }
  143. qdf_export_symbol(qdf_debugfs_hexdump);
  144. #else
  145. void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf,
  146. qdf_size_t len, int rowsize, int groupsize)
  147. {
  148. char *dst;
  149. size_t dstlen, readlen, remaining = len;
  150. int prefix = 0;
  151. size_t commitlen;
  152. while (remaining > 0 && (file->size > file->count)) {
  153. seq_printf(file, "%.8x: ", prefix);
  154. readlen = qdf_min(remaining, (qdf_size_t)rowsize);
  155. dstlen = seq_get_buf(file, &dst);
  156. hex_dump_to_buffer(buf, readlen, rowsize, groupsize, dst,
  157. dstlen, false);
  158. commitlen = strnlen(dst, dstlen);
  159. seq_commit(file, commitlen);
  160. seq_putc(file, '\n');
  161. remaining = (remaining > rowsize) ? remaining - rowsize : 0;
  162. buf += readlen;
  163. prefix += rowsize;
  164. }
  165. }
  166. qdf_export_symbol(qdf_debugfs_hexdump);
  167. #endif
  168. bool qdf_debugfs_overflow(qdf_debugfs_file_t file)
  169. {
  170. return seq_has_overflowed(file);
  171. }
  172. qdf_export_symbol(qdf_debugfs_overflow);
  173. void qdf_debugfs_write(qdf_debugfs_file_t file, const uint8_t *buf,
  174. qdf_size_t len)
  175. {
  176. seq_write(file, buf, len);
  177. }
  178. /* sequential file operation table */
  179. static const struct seq_operations __qdf_debugfs_seq_ops = {
  180. .start = qdf_debugfs_seq_start,
  181. .next = qdf_debugfs_seq_next,
  182. .stop = qdf_debugfs_seq_stop,
  183. .show = qdf_debugfs_seq_show,
  184. };
  185. /* .open() */
  186. static int qdf_seq_open(struct inode *inode, struct file *file)
  187. {
  188. void *private = inode->i_private;
  189. struct seq_file *seq;
  190. int rc;
  191. /**
  192. * Note: seq_open() will allocate a struct seq_file and store its
  193. * pointer in @file->private_data. It warns if private_data is not NULL.
  194. */
  195. rc = seq_open(file, &__qdf_debugfs_seq_ops);
  196. if (rc == 0) {
  197. seq = file->private_data;
  198. seq->private = private;
  199. }
  200. return rc;
  201. }
  202. /* .write() */
  203. static ssize_t qdf_seq_write(struct file *filp, const char __user *ubuf,
  204. size_t len, loff_t *ppos)
  205. {
  206. struct qdf_debugfs_fops *fops;
  207. struct seq_file *seq;
  208. u8 *buf;
  209. ssize_t rc = 0;
  210. if (len == 0)
  211. return 0;
  212. seq = filp->private_data;
  213. fops = seq->private;
  214. if (fops && fops->write) {
  215. buf = qdf_mem_malloc(len + 1);
  216. if (buf) {
  217. buf[len] = '\0';
  218. rc = simple_write_to_buffer(buf, len, ppos, ubuf, len);
  219. fops->write(fops->priv, buf, len + 1);
  220. qdf_mem_free(buf);
  221. }
  222. }
  223. return rc;
  224. }
  225. /* debugfs file operation table */
  226. static const struct file_operations __qdf_debugfs_fops = {
  227. .owner = THIS_MODULE,
  228. .open = qdf_seq_open,
  229. .read = seq_read,
  230. .llseek = seq_lseek,
  231. .release = seq_release,
  232. .write = qdf_seq_write,
  233. };
  234. qdf_dentry_t qdf_debugfs_create_dir(const char *name, qdf_dentry_t parent)
  235. {
  236. qdf_dentry_t dir;
  237. if (!name)
  238. return NULL;
  239. if (!parent)
  240. parent = qdf_debugfs_get_root();
  241. dir = debugfs_create_dir(name, parent);
  242. if (IS_ERR_OR_NULL(dir)) {
  243. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  244. "%s creation failed", name);
  245. dir = NULL;
  246. }
  247. return dir;
  248. }
  249. qdf_export_symbol(qdf_debugfs_create_dir);
  250. qdf_dentry_t qdf_debugfs_create_file(const char *name, uint16_t mode,
  251. qdf_dentry_t parent,
  252. struct qdf_debugfs_fops *fops)
  253. {
  254. qdf_dentry_t file;
  255. umode_t filemode;
  256. if (!name || !fops)
  257. return NULL;
  258. if (!parent)
  259. parent = qdf_debugfs_get_root();
  260. filemode = qdf_debugfs_get_filemode(mode);
  261. file = debugfs_create_file(name, filemode, parent, fops,
  262. &__qdf_debugfs_fops);
  263. if (IS_ERR_OR_NULL(file)) {
  264. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  265. "%s creation failed 0x%pK", name, file);
  266. file = NULL;
  267. }
  268. return file;
  269. }
  270. qdf_export_symbol(qdf_debugfs_create_file);
  271. void qdf_debugfs_create_u8(const char *name, uint16_t mode,
  272. qdf_dentry_t parent, u8 *value)
  273. {
  274. umode_t filemode;
  275. if (!name)
  276. return;
  277. if (!parent)
  278. parent = qdf_debugfs_get_root();
  279. filemode = qdf_debugfs_get_filemode(mode);
  280. debugfs_create_u8(name, filemode, parent, value);
  281. }
  282. void qdf_debugfs_create_u16(const char *name, uint16_t mode,
  283. qdf_dentry_t parent, u16 *value)
  284. {
  285. umode_t filemode;
  286. if (!name)
  287. return;
  288. if (!parent)
  289. parent = qdf_debugfs_get_root();
  290. filemode = qdf_debugfs_get_filemode(mode);
  291. debugfs_create_u16(name, filemode, parent, value);
  292. }
  293. qdf_export_symbol(qdf_debugfs_create_u16);
  294. void qdf_debugfs_create_u32(const char *name,
  295. uint16_t mode,
  296. qdf_dentry_t parent, u32 *value)
  297. {
  298. umode_t filemode;
  299. if (!name)
  300. return;
  301. if (!parent)
  302. parent = qdf_debugfs_get_root();
  303. filemode = qdf_debugfs_get_filemode(mode);
  304. debugfs_create_u32(name, filemode, parent, value);
  305. }
  306. qdf_export_symbol(qdf_debugfs_create_u32);
  307. void qdf_debugfs_create_u64(const char *name, uint16_t mode,
  308. qdf_dentry_t parent, u64 *value)
  309. {
  310. umode_t filemode;
  311. if (!name)
  312. return;
  313. if (!parent)
  314. parent = qdf_debugfs_get_root();
  315. filemode = qdf_debugfs_get_filemode(mode);
  316. debugfs_create_u64(name, filemode, parent, value);
  317. }
  318. qdf_export_symbol(qdf_debugfs_create_u64);
  319. void qdf_debugfs_create_atomic(const char *name, uint16_t mode,
  320. qdf_dentry_t parent, qdf_atomic_t *value)
  321. {
  322. umode_t filemode;
  323. if (!name)
  324. return;
  325. if (!parent)
  326. parent = qdf_debugfs_get_root();
  327. filemode = qdf_debugfs_get_filemode(mode);
  328. debugfs_create_atomic_t(name, filemode, parent, value);
  329. }
  330. qdf_export_symbol(qdf_debugfs_create_atomic);
  331. static int qdf_debugfs_string_show(struct seq_file *seq, void *pos)
  332. {
  333. char *str = seq->private;
  334. seq_puts(seq, str);
  335. seq_putc(seq, '\n');
  336. return 0;
  337. }
  338. static int qdf_debugfs_string_open(struct inode *inode, struct file *file)
  339. {
  340. return single_open(file, qdf_debugfs_string_show, inode->i_private);
  341. }
  342. static const struct file_operations qdf_string_fops = {
  343. .owner = THIS_MODULE,
  344. .open = qdf_debugfs_string_open,
  345. .read = seq_read,
  346. .llseek = seq_lseek,
  347. .release = single_release
  348. };
  349. qdf_dentry_t qdf_debugfs_create_string(const char *name, uint16_t mode,
  350. qdf_dentry_t parent, char *str)
  351. {
  352. umode_t filemode;
  353. if (!name)
  354. return NULL;
  355. if (!parent)
  356. parent = qdf_debugfs_get_root();
  357. filemode = qdf_debugfs_get_filemode(mode);
  358. return debugfs_create_file(name, filemode, parent, str,
  359. &qdf_string_fops);
  360. }
  361. qdf_export_symbol(qdf_debugfs_create_string);
  362. void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d)
  363. {
  364. debugfs_remove_recursive(d);
  365. }
  366. qdf_export_symbol(qdf_debugfs_remove_dir_recursive);
  367. void qdf_debugfs_remove_dir(qdf_dentry_t d)
  368. {
  369. debugfs_remove(d);
  370. }
  371. qdf_export_symbol(qdf_debugfs_remove_dir);
  372. void qdf_debugfs_remove_file(qdf_dentry_t d)
  373. {
  374. debugfs_remove(d);
  375. }
  376. qdf_export_symbol(qdf_debugfs_remove_file);
  377. static int qdf_debugfs_single_show(struct seq_file *seq, void *v)
  378. {
  379. struct qdf_debugfs_fops *fops = seq->private;
  380. if (fops && fops->show)
  381. fops->show(seq, fops->priv);
  382. return 0;
  383. }
  384. /* .open() */
  385. static int qdf_debugfs_single_open(struct inode *inode, struct file *file)
  386. {
  387. return single_open(file, qdf_debugfs_single_show,
  388. inode->i_private);
  389. }
  390. /* File operations for the simplified version */
  391. static const struct file_operations qdf_debugfs_fops_simple = {
  392. .owner = THIS_MODULE,
  393. .open = qdf_debugfs_single_open,
  394. .release = single_release,
  395. .read = seq_read,
  396. .llseek = seq_lseek,
  397. };
  398. qdf_dentry_t qdf_debugfs_create_file_simplified(
  399. const char *name, uint16_t mode,
  400. qdf_dentry_t parent, struct qdf_debugfs_fops *fops)
  401. {
  402. qdf_dentry_t file;
  403. umode_t filemode;
  404. if (!name || !fops)
  405. return NULL;
  406. if (!parent)
  407. parent = qdf_debugfs_get_root();
  408. filemode = qdf_debugfs_get_filemode(mode);
  409. file = debugfs_create_file(name, filemode, parent, fops,
  410. &qdf_debugfs_fops_simple);
  411. if (IS_ERR_OR_NULL(file)) {
  412. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  413. "%s creation failed 0x%pK", name, file);
  414. file = NULL;
  415. }
  416. return file;
  417. }
  418. qdf_export_symbol(qdf_debugfs_create_file_simplified);
  419. int qdf_debugfs_printer(void *priv, const char *fmt, ...)
  420. {
  421. struct seq_file *file = priv;
  422. va_list args;
  423. va_start(args, fmt);
  424. seq_vprintf(file, fmt, args);
  425. seq_puts(file, "\n");
  426. va_end(args);
  427. return 0;
  428. }
  429. qdf_export_symbol(qdf_debugfs_printer);
  430. qdf_dentry_t qdf_debugfs_create_blob(const char *name, umode_t mode,
  431. qdf_dentry_t parent,
  432. qdf_debugfs_blob_wrap_t blob)
  433. {
  434. return debugfs_create_blob(name, mode, parent, blob);
  435. }
  436. qdf_export_symbol(qdf_debugfs_create_blob);
  437. qdf_dentry_t qdf_debugfs_create_entry(const char *name, uint16_t mode,
  438. qdf_dentry_t parent,
  439. qdf_entry_t data,
  440. const qdf_file_ops_t fops)
  441. {
  442. qdf_dentry_t file;
  443. umode_t filemode;
  444. if (!name || !fops)
  445. return NULL;
  446. if (!parent)
  447. parent = qdf_debugfs_get_root();
  448. filemode = qdf_debugfs_get_filemode(mode);
  449. file = debugfs_create_file(name, filemode, parent, data, fops);
  450. if (IS_ERR_OR_NULL(file)) {
  451. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  452. "%s creation failed 0x%pK", name, file);
  453. file = NULL;
  454. }
  455. return file;
  456. }
  457. qdf_export_symbol(qdf_debugfs_create_entry);