linux_ac.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. /*
  2. * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for
  6. * any purpose with or without fee is hereby granted, provided that the
  7. * above copyright notice and this permission notice appear in all
  8. * copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  11. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  12. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  13. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  14. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  15. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  17. * PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. #ifndef REMOVE_PKT_LOG
  20. #ifndef EXPORT_SYMTAB
  21. #define EXPORT_SYMTAB
  22. #endif
  23. #ifndef __KERNEL__
  24. #define __KERNEL__
  25. #endif
  26. /*
  27. * Linux specific implementation of Pktlogs for 802.11ac
  28. */
  29. #include <linux/kernel.h>
  30. #include <linux/init.h>
  31. #include <linux/module.h>
  32. #include <linux/vmalloc.h>
  33. #include <linux/proc_fs.h>
  34. #include <pktlog_ac_i.h>
  35. #include <pktlog_ac_fmt.h>
  36. #include "i_host_diag_core_log.h"
  37. #include "host_diag_core_log.h"
  38. #include "ani_global.h"
  39. #define PKTLOG_DEVNAME_SIZE 32
  40. #define MAX_WLANDEV 1
  41. #ifdef MULTI_IF_NAME
  42. #define PKTLOG_PROC_DIR "ath_pktlog" MULTI_IF_NAME
  43. #else
  44. #define PKTLOG_PROC_DIR "ath_pktlog"
  45. #endif
  46. /* Permissions for creating proc entries */
  47. #define PKTLOG_PROC_PERM 0444
  48. #define PKTLOG_PROCSYS_DIR_PERM 0555
  49. #define PKTLOG_PROCSYS_PERM 0644
  50. #ifndef __MOD_INC_USE_COUNT
  51. #define PKTLOG_MOD_INC_USE_COUNT do { \
  52. if (!try_module_get(THIS_MODULE)) { \
  53. qdf_nofl_info("try_module_get failed"); \
  54. } } while (0)
  55. #define PKTLOG_MOD_DEC_USE_COUNT module_put(THIS_MODULE)
  56. #else
  57. #define PKTLOG_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
  58. #define PKTLOG_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
  59. #endif
  60. static struct ath_pktlog_info *g_pktlog_info;
  61. static struct proc_dir_entry *g_pktlog_pde;
  62. static DEFINE_MUTEX(proc_mutex);
  63. static int pktlog_attach(struct hif_opaque_softc *scn);
  64. static void pktlog_detach(struct hif_opaque_softc *scn);
  65. static int pktlog_open(struct inode *i, struct file *f);
  66. static int pktlog_release(struct inode *i, struct file *f);
  67. static ssize_t pktlog_read(struct file *file, char *buf, size_t nbytes,
  68. loff_t *ppos);
  69. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
  70. static const struct proc_ops pktlog_fops = {
  71. .proc_open = pktlog_open,
  72. .proc_release = pktlog_release,
  73. .proc_read = pktlog_read,
  74. .proc_lseek = default_llseek,
  75. };
  76. #else
  77. static struct file_operations pktlog_fops = {
  78. open: pktlog_open,
  79. release:pktlog_release,
  80. read : pktlog_read,
  81. };
  82. #endif
  83. void pktlog_disable_adapter_logging(struct hif_opaque_softc *scn)
  84. {
  85. struct pktlog_dev_t *pl_dev = get_pktlog_handle();
  86. if (pl_dev)
  87. pl_dev->pl_info->log_state = 0;
  88. }
  89. int pktlog_alloc_buf(struct hif_opaque_softc *scn)
  90. {
  91. uint32_t page_cnt;
  92. unsigned long vaddr;
  93. struct page *vpg;
  94. struct pktlog_dev_t *pl_dev;
  95. struct ath_pktlog_info *pl_info;
  96. struct ath_pktlog_buf *buffer;
  97. pl_dev = get_pktlog_handle();
  98. if (!pl_dev) {
  99. qdf_info(PKTLOG_TAG "pdev_txrx_handle->pl_dev is null");
  100. return -EINVAL;
  101. }
  102. pl_info = pl_dev->pl_info;
  103. page_cnt = (sizeof(*(pl_info->buf)) + pl_info->buf_size) / PAGE_SIZE;
  104. qdf_spin_lock_bh(&pl_info->log_lock);
  105. if (pl_info->buf) {
  106. qdf_spin_unlock_bh(&pl_info->log_lock);
  107. qdf_nofl_info(PKTLOG_TAG "Buffer is already in use");
  108. return -EINVAL;
  109. }
  110. qdf_spin_unlock_bh(&pl_info->log_lock);
  111. buffer = qdf_mem_valloc((page_cnt + 2) * PAGE_SIZE);
  112. if (!buffer) {
  113. return -ENOMEM;
  114. }
  115. buffer = (struct ath_pktlog_buf *)
  116. (((unsigned long)(buffer) + PAGE_SIZE - 1)
  117. & PAGE_MASK);
  118. for (vaddr = (unsigned long)(buffer);
  119. vaddr < ((unsigned long)(buffer) + (page_cnt * PAGE_SIZE));
  120. vaddr += PAGE_SIZE) {
  121. vpg = vmalloc_to_page((const void *)vaddr);
  122. SetPageReserved(vpg);
  123. }
  124. qdf_spin_lock_bh(&pl_info->log_lock);
  125. if (pl_info->buf)
  126. pktlog_release_buf(scn);
  127. pl_info->buf = buffer;
  128. qdf_spin_unlock_bh(&pl_info->log_lock);
  129. return 0;
  130. }
  131. void pktlog_release_buf(struct hif_opaque_softc *scn)
  132. {
  133. unsigned long page_cnt;
  134. unsigned long vaddr;
  135. struct page *vpg;
  136. struct pktlog_dev_t *pl_dev;
  137. struct ath_pktlog_info *pl_info;
  138. pl_dev = get_pktlog_handle();
  139. if (!pl_dev) {
  140. qdf_print("Invalid pl_dev handle");
  141. return;
  142. }
  143. if (!pl_dev->pl_info) {
  144. qdf_print("Invalid pl_dev handle");
  145. return;
  146. }
  147. pl_info = pl_dev->pl_info;
  148. page_cnt = ((sizeof(*(pl_info->buf)) + pl_info->buf_size) /
  149. PAGE_SIZE) + 1;
  150. for (vaddr = (unsigned long)(pl_info->buf);
  151. vaddr < (unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE);
  152. vaddr += PAGE_SIZE) {
  153. vpg = vmalloc_to_page((const void *)vaddr);
  154. ClearPageReserved(vpg);
  155. }
  156. qdf_mem_vfree(pl_info->buf);
  157. pl_info->buf = NULL;
  158. }
  159. static void pktlog_cleanup(struct ath_pktlog_info *pl_info)
  160. {
  161. pl_info->log_state = 0;
  162. PKTLOG_LOCK_DESTROY(pl_info);
  163. mutex_destroy(&pl_info->pktlog_mutex);
  164. }
  165. /* sysctl procfs handler to enable pktlog */
  166. static int
  167. qdf_sysctl_decl(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ppos)
  168. {
  169. int ret, enable;
  170. ol_ath_generic_softc_handle scn;
  171. struct pktlog_dev_t *pl_dev;
  172. mutex_lock(&proc_mutex);
  173. scn = (ol_ath_generic_softc_handle) ctl->extra1;
  174. if (!scn) {
  175. mutex_unlock(&proc_mutex);
  176. qdf_info("Invalid scn context");
  177. ASSERT(0);
  178. return -EINVAL;
  179. }
  180. pl_dev = get_pktlog_handle();
  181. if (!pl_dev) {
  182. mutex_unlock(&proc_mutex);
  183. qdf_info("Invalid pktlog context");
  184. ASSERT(0);
  185. return -ENODEV;
  186. }
  187. ctl->data = &enable;
  188. ctl->maxlen = sizeof(enable);
  189. if (write) {
  190. ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
  191. lenp, ppos);
  192. if (ret == 0) {
  193. ret = pl_dev->pl_funcs->pktlog_enable(
  194. (struct hif_opaque_softc *)scn, enable,
  195. cds_is_packet_log_enabled(), 0, 1);
  196. }
  197. else
  198. QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG,
  199. "Line:%d %s:proc_dointvec failed reason %d",
  200. __LINE__, __func__, ret);
  201. } else {
  202. ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
  203. lenp, ppos);
  204. if (ret)
  205. QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG,
  206. "Line:%d %s:proc_dointvec failed reason %d",
  207. __LINE__, __func__, ret);
  208. }
  209. ctl->data = NULL;
  210. ctl->maxlen = 0;
  211. mutex_unlock(&proc_mutex);
  212. return ret;
  213. }
  214. static int get_pktlog_bufsize(struct pktlog_dev_t *pl_dev)
  215. {
  216. return pl_dev->pl_info->buf_size;
  217. }
  218. /* sysctl procfs handler to set/get pktlog size */
  219. static int
  220. qdf_sysctl_decl(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ppos)
  221. {
  222. int ret, size;
  223. ol_ath_generic_softc_handle scn;
  224. struct pktlog_dev_t *pl_dev;
  225. mutex_lock(&proc_mutex);
  226. scn = (ol_ath_generic_softc_handle) ctl->extra1;
  227. if (!scn) {
  228. mutex_unlock(&proc_mutex);
  229. qdf_info("Invalid scn context");
  230. ASSERT(0);
  231. return -EINVAL;
  232. }
  233. pl_dev = get_pktlog_handle();
  234. if (!pl_dev) {
  235. mutex_unlock(&proc_mutex);
  236. qdf_info("Invalid pktlog handle");
  237. ASSERT(0);
  238. return -ENODEV;
  239. }
  240. ctl->data = &size;
  241. ctl->maxlen = sizeof(size);
  242. if (write) {
  243. ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
  244. lenp, ppos);
  245. if (ret == 0)
  246. ret = pl_dev->pl_funcs->pktlog_setsize(
  247. (struct hif_opaque_softc *)scn, size);
  248. } else {
  249. size = get_pktlog_bufsize(pl_dev);
  250. ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
  251. lenp, ppos);
  252. }
  253. ctl->data = NULL;
  254. ctl->maxlen = 0;
  255. mutex_unlock(&proc_mutex);
  256. return ret;
  257. }
  258. /* Register sysctl table */
  259. static int pktlog_sysctl_register(struct hif_opaque_softc *scn)
  260. {
  261. struct pktlog_dev_t *pl_dev = get_pktlog_handle();
  262. struct ath_pktlog_info_lnx *pl_info_lnx;
  263. char *proc_name;
  264. if (pl_dev) {
  265. pl_info_lnx = PL_INFO_LNX(pl_dev->pl_info);
  266. proc_name = pl_dev->name;
  267. } else {
  268. pl_info_lnx = PL_INFO_LNX(g_pktlog_info);
  269. proc_name = PKTLOG_PROC_SYSTEM;
  270. }
  271. /*
  272. * Setup the sysctl table for creating the following sysctl entries:
  273. * /proc/sys/PKTLOG_PROC_DIR/<adapter>/enable for enabling/disabling
  274. * pktlog
  275. * /proc/sys/PKTLOG_PROC_DIR/<adapter>/size for changing the buffer size
  276. */
  277. memset(pl_info_lnx->sysctls, 0, sizeof(pl_info_lnx->sysctls));
  278. pl_info_lnx->sysctls[0].procname = PKTLOG_PROC_DIR;
  279. pl_info_lnx->sysctls[0].mode = PKTLOG_PROCSYS_DIR_PERM;
  280. pl_info_lnx->sysctls[0].child = &pl_info_lnx->sysctls[2];
  281. /* [1] is NULL terminator */
  282. pl_info_lnx->sysctls[2].procname = proc_name;
  283. pl_info_lnx->sysctls[2].mode = PKTLOG_PROCSYS_DIR_PERM;
  284. pl_info_lnx->sysctls[2].child = &pl_info_lnx->sysctls[4];
  285. /* [3] is NULL terminator */
  286. pl_info_lnx->sysctls[4].procname = "enable";
  287. pl_info_lnx->sysctls[4].mode = PKTLOG_PROCSYS_PERM;
  288. pl_info_lnx->sysctls[4].proc_handler = ath_sysctl_pktlog_enable;
  289. pl_info_lnx->sysctls[4].extra1 = scn;
  290. pl_info_lnx->sysctls[5].procname = "size";
  291. pl_info_lnx->sysctls[5].mode = PKTLOG_PROCSYS_PERM;
  292. pl_info_lnx->sysctls[5].proc_handler = ath_sysctl_pktlog_size;
  293. pl_info_lnx->sysctls[5].extra1 = scn;
  294. pl_info_lnx->sysctls[6].procname = "options";
  295. pl_info_lnx->sysctls[6].mode = PKTLOG_PROCSYS_PERM;
  296. pl_info_lnx->sysctls[6].proc_handler = proc_dointvec;
  297. pl_info_lnx->sysctls[6].data = &pl_info_lnx->info.options;
  298. pl_info_lnx->sysctls[6].maxlen = sizeof(pl_info_lnx->info.options);
  299. pl_info_lnx->sysctls[7].procname = "sack_thr";
  300. pl_info_lnx->sysctls[7].mode = PKTLOG_PROCSYS_PERM;
  301. pl_info_lnx->sysctls[7].proc_handler = proc_dointvec;
  302. pl_info_lnx->sysctls[7].data = &pl_info_lnx->info.sack_thr;
  303. pl_info_lnx->sysctls[7].maxlen = sizeof(pl_info_lnx->info.sack_thr);
  304. pl_info_lnx->sysctls[8].procname = "tail_length";
  305. pl_info_lnx->sysctls[8].mode = PKTLOG_PROCSYS_PERM;
  306. pl_info_lnx->sysctls[8].proc_handler = proc_dointvec;
  307. pl_info_lnx->sysctls[8].data = &pl_info_lnx->info.tail_length;
  308. pl_info_lnx->sysctls[8].maxlen = sizeof(pl_info_lnx->info.tail_length);
  309. pl_info_lnx->sysctls[9].procname = "thruput_thresh";
  310. pl_info_lnx->sysctls[9].mode = PKTLOG_PROCSYS_PERM;
  311. pl_info_lnx->sysctls[9].proc_handler = proc_dointvec;
  312. pl_info_lnx->sysctls[9].data = &pl_info_lnx->info.thruput_thresh;
  313. pl_info_lnx->sysctls[9].maxlen =
  314. sizeof(pl_info_lnx->info.thruput_thresh);
  315. pl_info_lnx->sysctls[10].procname = "phyerr_thresh";
  316. pl_info_lnx->sysctls[10].mode = PKTLOG_PROCSYS_PERM;
  317. pl_info_lnx->sysctls[10].proc_handler = proc_dointvec;
  318. pl_info_lnx->sysctls[10].data = &pl_info_lnx->info.phyerr_thresh;
  319. pl_info_lnx->sysctls[10].maxlen =
  320. sizeof(pl_info_lnx->info.phyerr_thresh);
  321. pl_info_lnx->sysctls[11].procname = "per_thresh";
  322. pl_info_lnx->sysctls[11].mode = PKTLOG_PROCSYS_PERM;
  323. pl_info_lnx->sysctls[11].proc_handler = proc_dointvec;
  324. pl_info_lnx->sysctls[11].data = &pl_info_lnx->info.per_thresh;
  325. pl_info_lnx->sysctls[11].maxlen = sizeof(pl_info_lnx->info.per_thresh);
  326. pl_info_lnx->sysctls[12].procname = "trigger_interval";
  327. pl_info_lnx->sysctls[12].mode = PKTLOG_PROCSYS_PERM;
  328. pl_info_lnx->sysctls[12].proc_handler = proc_dointvec;
  329. pl_info_lnx->sysctls[12].data = &pl_info_lnx->info.trigger_interval;
  330. pl_info_lnx->sysctls[12].maxlen =
  331. sizeof(pl_info_lnx->info.trigger_interval);
  332. /* [13] is NULL terminator */
  333. /* and register everything */
  334. /* register_sysctl_table changed from 2.6.21 onwards */
  335. pl_info_lnx->sysctl_header =
  336. register_sysctl_table(pl_info_lnx->sysctls);
  337. if (!pl_info_lnx->sysctl_header) {
  338. qdf_nofl_info("%s: failed to register sysctls!", proc_name);
  339. return -EINVAL;
  340. }
  341. return 0;
  342. }
  343. /*
  344. * Initialize logging for system or adapter
  345. * Parameter scn should be NULL for system wide logging
  346. */
  347. static int pktlog_attach(struct hif_opaque_softc *scn)
  348. {
  349. struct pktlog_dev_t *pl_dev;
  350. struct ath_pktlog_info_lnx *pl_info_lnx;
  351. char *proc_name;
  352. struct proc_dir_entry *proc_entry;
  353. qdf_info("attach pktlog resources");
  354. /* Allocate pktlog dev for later use */
  355. pl_dev = get_pktlog_handle();
  356. if (pl_dev) {
  357. pl_info_lnx = kmalloc(sizeof(*pl_info_lnx), GFP_KERNEL);
  358. if (!pl_info_lnx) {
  359. QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
  360. "%s: Allocation failed for pl_info",
  361. __func__);
  362. goto attach_fail1;
  363. }
  364. pl_dev->pl_info = &pl_info_lnx->info;
  365. pl_dev->name = WLANDEV_BASENAME;
  366. proc_name = pl_dev->name;
  367. if (!pl_dev->pl_funcs)
  368. pl_dev->pl_funcs = &ol_pl_funcs;
  369. /*
  370. * Valid for both direct attach and offload architecture
  371. */
  372. pl_dev->pl_funcs->pktlog_init(scn);
  373. } else {
  374. qdf_err("pl_dev is NULL");
  375. return -EINVAL;
  376. }
  377. /*
  378. * initialize log info
  379. * might be good to move to pktlog_init
  380. */
  381. /* pl_dev->tgt_pktlog_alloced = false; */
  382. pl_info_lnx->proc_entry = NULL;
  383. pl_info_lnx->sysctl_header = NULL;
  384. proc_entry = proc_create_data(proc_name, PKTLOG_PROC_PERM,
  385. g_pktlog_pde, &pktlog_fops,
  386. &pl_info_lnx->info);
  387. if (!proc_entry) {
  388. qdf_info(PKTLOG_TAG "create_proc_entry failed for %s", proc_name);
  389. goto attach_fail1;
  390. }
  391. pl_info_lnx->proc_entry = proc_entry;
  392. if (pktlog_sysctl_register(scn)) {
  393. qdf_nofl_info(PKTLOG_TAG "sysctl register failed for %s",
  394. proc_name);
  395. goto attach_fail2;
  396. }
  397. return 0;
  398. attach_fail2:
  399. remove_proc_entry(proc_name, g_pktlog_pde);
  400. attach_fail1:
  401. if (pl_dev)
  402. kfree(pl_dev->pl_info);
  403. return -EINVAL;
  404. }
  405. static void pktlog_sysctl_unregister(struct pktlog_dev_t *pl_dev)
  406. {
  407. struct ath_pktlog_info_lnx *pl_info_lnx;
  408. if (!pl_dev) {
  409. qdf_info("Invalid pktlog context");
  410. ASSERT(0);
  411. return;
  412. }
  413. pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
  414. PL_INFO_LNX(g_pktlog_info);
  415. if (pl_info_lnx->sysctl_header) {
  416. unregister_sysctl_table(pl_info_lnx->sysctl_header);
  417. pl_info_lnx->sysctl_header = NULL;
  418. }
  419. }
  420. static void pktlog_detach(struct hif_opaque_softc *scn)
  421. {
  422. struct ath_pktlog_info *pl_info;
  423. struct pktlog_dev_t *pl_dev = get_pktlog_handle();
  424. qdf_info("detach pktlog resources");
  425. if (!pl_dev) {
  426. qdf_info("Invalid pktlog context");
  427. ASSERT(0);
  428. return;
  429. }
  430. pl_info = pl_dev->pl_info;
  431. if (!pl_info) {
  432. qdf_print("Invalid pktlog handle");
  433. ASSERT(0);
  434. return;
  435. }
  436. mutex_lock(&pl_info->pktlog_mutex);
  437. remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
  438. pktlog_sysctl_unregister(pl_dev);
  439. qdf_spin_lock_bh(&pl_info->log_lock);
  440. if (pl_info->buf) {
  441. pktlog_release_buf(scn);
  442. pl_dev->tgt_pktlog_alloced = false;
  443. }
  444. qdf_spin_unlock_bh(&pl_info->log_lock);
  445. mutex_unlock(&pl_info->pktlog_mutex);
  446. pktlog_cleanup(pl_info);
  447. if (pl_dev) {
  448. kfree(pl_info);
  449. pl_dev->pl_info = NULL;
  450. }
  451. }
  452. static int __pktlog_open(struct inode *i, struct file *f)
  453. {
  454. struct hif_opaque_softc *scn;
  455. struct pktlog_dev_t *pl_dev;
  456. struct ath_pktlog_info *pl_info;
  457. struct ath_pktlog_info_lnx *pl_info_lnx;
  458. int ret = 0;
  459. PKTLOG_MOD_INC_USE_COUNT;
  460. scn = cds_get_context(QDF_MODULE_ID_HIF);
  461. if (!scn) {
  462. qdf_print("Invalid scn context");
  463. ASSERT(0);
  464. return -EINVAL;
  465. }
  466. pl_dev = get_pktlog_handle();
  467. if (!pl_dev) {
  468. qdf_print("Invalid pktlog handle");
  469. ASSERT(0);
  470. return -ENODEV;
  471. }
  472. pl_info = pl_dev->pl_info;
  473. if (!pl_info) {
  474. qdf_err("pl_info NULL");
  475. return -EINVAL;
  476. }
  477. mutex_lock(&pl_info->pktlog_mutex);
  478. pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
  479. PL_INFO_LNX(g_pktlog_info);
  480. if (!pl_info_lnx->sysctl_header) {
  481. mutex_unlock(&pl_info->pktlog_mutex);
  482. qdf_print("pktlog sysctl is unergistered");
  483. ASSERT(0);
  484. return -EINVAL;
  485. }
  486. if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
  487. mutex_unlock(&pl_info->pktlog_mutex);
  488. qdf_print("plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
  489. pl_info->curr_pkt_state);
  490. return -EBUSY;
  491. }
  492. pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
  493. pl_info->init_saved_state = pl_info->log_state;
  494. if (!pl_info->log_state) {
  495. /* Pktlog is already disabled.
  496. * Proceed to read directly.
  497. */
  498. pl_info->curr_pkt_state =
  499. PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
  500. mutex_unlock(&pl_info->pktlog_mutex);
  501. return ret;
  502. }
  503. /* Disbable the pktlog internally. */
  504. ret = pl_dev->pl_funcs->pktlog_disable(scn);
  505. pl_info->log_state = 0;
  506. pl_info->curr_pkt_state =
  507. PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
  508. mutex_unlock(&pl_info->pktlog_mutex);
  509. return ret;
  510. }
  511. static int pktlog_open(struct inode *i, struct file *f)
  512. {
  513. struct qdf_op_sync *op_sync;
  514. int errno;
  515. errno = qdf_op_protect(&op_sync);
  516. if (errno)
  517. return errno;
  518. errno = __pktlog_open(i, f);
  519. qdf_op_unprotect(op_sync);
  520. return errno;
  521. }
  522. static int __pktlog_release(struct inode *i, struct file *f)
  523. {
  524. struct hif_opaque_softc *scn;
  525. struct pktlog_dev_t *pl_dev;
  526. struct ath_pktlog_info *pl_info;
  527. struct ath_pktlog_info_lnx *pl_info_lnx;
  528. int ret = 0;
  529. PKTLOG_MOD_DEC_USE_COUNT;
  530. scn = cds_get_context(QDF_MODULE_ID_HIF);
  531. if (!scn) {
  532. qdf_print("Invalid scn context");
  533. ASSERT(0);
  534. return -EINVAL;
  535. }
  536. pl_dev = get_pktlog_handle();
  537. if (!pl_dev) {
  538. qdf_print("Invalid pktlog handle");
  539. ASSERT(0);
  540. return -ENODEV;
  541. }
  542. pl_info = pl_dev->pl_info;
  543. if (!pl_info) {
  544. qdf_print("Invalid pktlog info");
  545. ASSERT(0);
  546. return -EINVAL;
  547. }
  548. mutex_lock(&pl_info->pktlog_mutex);
  549. pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
  550. PL_INFO_LNX(g_pktlog_info);
  551. if (!pl_info_lnx->sysctl_header) {
  552. pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
  553. mutex_unlock(&pl_info->pktlog_mutex);
  554. qdf_print("pktlog sysctl is unergistered");
  555. ASSERT(0);
  556. return -EINVAL;
  557. }
  558. pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE;
  559. /*clear pktlog buffer.*/
  560. pktlog_clearbuff(scn, true);
  561. pl_info->log_state = pl_info->init_saved_state;
  562. pl_info->init_saved_state = 0;
  563. /*Enable pktlog again*/
  564. ret = __pktlog_enable(
  565. (struct hif_opaque_softc *)scn, pl_info->log_state,
  566. cds_is_packet_log_enabled(), 0, 1);
  567. pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
  568. mutex_unlock(&pl_info->pktlog_mutex);
  569. if (ret != 0)
  570. qdf_print("pktlog cannot be enabled. ret value %d", ret);
  571. return ret;
  572. }
  573. static int pktlog_release(struct inode *i, struct file *f)
  574. {
  575. struct qdf_op_sync *op_sync;
  576. int errno;
  577. errno = qdf_op_protect(&op_sync);
  578. if (errno)
  579. return errno;
  580. errno = __pktlog_release(i, f);
  581. qdf_op_unprotect(op_sync);
  582. return errno;
  583. }
  584. #ifndef MIN
  585. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  586. #endif
  587. /**
  588. * pktlog_read_proc_entry() - This function is used to read data from the
  589. * proc entry into the readers buffer
  590. * @buf: Readers buffer
  591. * @nbytes: Number of bytes to read
  592. * @ppos: Offset within the drivers buffer
  593. * @pl_info: Packet log information pointer
  594. * @read_complete: Boolean value indication whether read is complete
  595. *
  596. * This function is used to read data from the proc entry into the readers
  597. * buffer. Its functionality is similar to 'pktlog_read' which does
  598. * copy to user to the user space buffer
  599. *
  600. * Return: Number of bytes read from the buffer
  601. *
  602. */
  603. ssize_t
  604. pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos,
  605. struct ath_pktlog_info *pl_info, bool *read_complete)
  606. {
  607. size_t bufhdr_size;
  608. size_t count = 0, ret_val = 0;
  609. int rem_len;
  610. int start_offset, end_offset;
  611. int fold_offset, ppos_data, cur_rd_offset, cur_wr_offset;
  612. struct ath_pktlog_buf *log_buf;
  613. qdf_spin_lock_bh(&pl_info->log_lock);
  614. log_buf = pl_info->buf;
  615. *read_complete = false;
  616. if (!log_buf) {
  617. *read_complete = true;
  618. qdf_spin_unlock_bh(&pl_info->log_lock);
  619. return 0;
  620. }
  621. if (*ppos == 0 && pl_info->log_state) {
  622. pl_info->saved_state = pl_info->log_state;
  623. pl_info->log_state = 0;
  624. }
  625. bufhdr_size = sizeof(log_buf->bufhdr);
  626. /* copy valid log entries from circular buffer into user space */
  627. rem_len = nbytes;
  628. count = 0;
  629. if (*ppos < bufhdr_size) {
  630. count = MIN((bufhdr_size - *ppos), rem_len);
  631. qdf_mem_copy(buf, ((char *)&log_buf->bufhdr) + *ppos,
  632. count);
  633. rem_len -= count;
  634. ret_val += count;
  635. }
  636. start_offset = log_buf->rd_offset;
  637. cur_wr_offset = log_buf->wr_offset;
  638. if ((rem_len == 0) || (start_offset < 0))
  639. goto rd_done;
  640. fold_offset = -1;
  641. cur_rd_offset = start_offset;
  642. /* Find the last offset and fold-offset if the buffer is folded */
  643. do {
  644. struct ath_pktlog_hdr *log_hdr;
  645. int log_data_offset;
  646. log_hdr = (struct ath_pktlog_hdr *) (log_buf->log_data +
  647. cur_rd_offset);
  648. log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
  649. if ((fold_offset == -1)
  650. && ((pl_info->buf_size - log_data_offset)
  651. <= log_hdr->size))
  652. fold_offset = log_data_offset - 1;
  653. PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size);
  654. if ((fold_offset == -1) && (cur_rd_offset == 0)
  655. && (cur_rd_offset != cur_wr_offset))
  656. fold_offset = log_data_offset + log_hdr->size - 1;
  657. end_offset = log_data_offset + log_hdr->size - 1;
  658. } while (cur_rd_offset != cur_wr_offset);
  659. ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
  660. if (fold_offset == -1) {
  661. if (ppos_data > end_offset)
  662. goto rd_done;
  663. count = MIN(rem_len, (end_offset - ppos_data + 1));
  664. qdf_mem_copy(buf + ret_val,
  665. log_buf->log_data + ppos_data,
  666. count);
  667. ret_val += count;
  668. rem_len -= count;
  669. } else {
  670. if (ppos_data <= fold_offset) {
  671. count = MIN(rem_len, (fold_offset - ppos_data + 1));
  672. qdf_mem_copy(buf + ret_val,
  673. log_buf->log_data + ppos_data,
  674. count);
  675. ret_val += count;
  676. rem_len -= count;
  677. }
  678. if (rem_len == 0)
  679. goto rd_done;
  680. ppos_data =
  681. *ppos + ret_val - (bufhdr_size +
  682. (fold_offset - start_offset + 1));
  683. if (ppos_data <= end_offset) {
  684. count = MIN(rem_len, (end_offset - ppos_data + 1));
  685. qdf_mem_copy(buf + ret_val,
  686. log_buf->log_data + ppos_data,
  687. count);
  688. ret_val += count;
  689. rem_len -= count;
  690. }
  691. }
  692. rd_done:
  693. if ((ret_val < nbytes) && pl_info->saved_state) {
  694. pl_info->log_state = pl_info->saved_state;
  695. pl_info->saved_state = 0;
  696. }
  697. *ppos += ret_val;
  698. if (ret_val == 0) {
  699. /* Write pointer might have been updated during the read.
  700. * So, if some data is written into, lets not reset the pointers
  701. * We can continue to read from the offset position
  702. */
  703. if (cur_wr_offset != log_buf->wr_offset) {
  704. *read_complete = false;
  705. } else {
  706. pl_info->buf->rd_offset = -1;
  707. pl_info->buf->wr_offset = 0;
  708. pl_info->buf->bytes_written = 0;
  709. pl_info->buf->offset = PKTLOG_READ_OFFSET;
  710. *read_complete = true;
  711. }
  712. }
  713. qdf_spin_unlock_bh(&pl_info->log_lock);
  714. return ret_val;
  715. }
  716. static ssize_t
  717. __pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
  718. {
  719. size_t bufhdr_size;
  720. size_t count = 0, ret_val = 0;
  721. int rem_len;
  722. int start_offset, end_offset;
  723. int fold_offset, ppos_data, cur_rd_offset;
  724. struct ath_pktlog_info *pl_info;
  725. struct ath_pktlog_buf *log_buf;
  726. pl_info = PDE_DATA(file->f_path.dentry->d_inode);
  727. if (!pl_info)
  728. return 0;
  729. qdf_spin_lock_bh(&pl_info->log_lock);
  730. log_buf = pl_info->buf;
  731. if (!log_buf) {
  732. qdf_spin_unlock_bh(&pl_info->log_lock);
  733. return 0;
  734. }
  735. if (pl_info->log_state) {
  736. /* Read is not allowed when write is going on
  737. * When issuing cat command, ensure to send
  738. * pktlog disable command first.
  739. */
  740. qdf_spin_unlock_bh(&pl_info->log_lock);
  741. return -EINVAL;
  742. }
  743. if (*ppos == 0 && pl_info->log_state) {
  744. pl_info->saved_state = pl_info->log_state;
  745. pl_info->log_state = 0;
  746. }
  747. bufhdr_size = sizeof(log_buf->bufhdr);
  748. /* copy valid log entries from circular buffer into user space */
  749. rem_len = nbytes;
  750. count = 0;
  751. if (*ppos < bufhdr_size) {
  752. count = QDF_MIN((bufhdr_size - *ppos), rem_len);
  753. qdf_spin_unlock_bh(&pl_info->log_lock);
  754. if (copy_to_user(buf, ((char *)&log_buf->bufhdr) + *ppos,
  755. count)) {
  756. return -EFAULT;
  757. }
  758. rem_len -= count;
  759. ret_val += count;
  760. qdf_spin_lock_bh(&pl_info->log_lock);
  761. }
  762. start_offset = log_buf->rd_offset;
  763. if ((rem_len == 0) || (start_offset < 0))
  764. goto rd_done;
  765. fold_offset = -1;
  766. cur_rd_offset = start_offset;
  767. /* Find the last offset and fold-offset if the buffer is folded */
  768. do {
  769. struct ath_pktlog_hdr *log_hdr;
  770. int log_data_offset;
  771. log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data +
  772. cur_rd_offset);
  773. log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
  774. if ((fold_offset == -1)
  775. && ((pl_info->buf_size - log_data_offset)
  776. <= log_hdr->size))
  777. fold_offset = log_data_offset - 1;
  778. PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size);
  779. if ((fold_offset == -1) && (cur_rd_offset == 0)
  780. && (cur_rd_offset != log_buf->wr_offset))
  781. fold_offset = log_data_offset + log_hdr->size - 1;
  782. end_offset = log_data_offset + log_hdr->size - 1;
  783. } while (cur_rd_offset != log_buf->wr_offset);
  784. ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
  785. if (fold_offset == -1) {
  786. if (ppos_data > end_offset)
  787. goto rd_done;
  788. count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
  789. qdf_spin_unlock_bh(&pl_info->log_lock);
  790. if (copy_to_user(buf + ret_val,
  791. log_buf->log_data + ppos_data, count)) {
  792. return -EFAULT;
  793. }
  794. ret_val += count;
  795. rem_len -= count;
  796. qdf_spin_lock_bh(&pl_info->log_lock);
  797. } else {
  798. if (ppos_data <= fold_offset) {
  799. count = QDF_MIN(rem_len, (fold_offset - ppos_data + 1));
  800. qdf_spin_unlock_bh(&pl_info->log_lock);
  801. if (copy_to_user(buf + ret_val,
  802. log_buf->log_data + ppos_data,
  803. count)) {
  804. return -EFAULT;
  805. }
  806. ret_val += count;
  807. rem_len -= count;
  808. qdf_spin_lock_bh(&pl_info->log_lock);
  809. }
  810. if (rem_len == 0)
  811. goto rd_done;
  812. ppos_data =
  813. *ppos + ret_val - (bufhdr_size +
  814. (fold_offset - start_offset + 1));
  815. if (ppos_data <= end_offset) {
  816. count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
  817. qdf_spin_unlock_bh(&pl_info->log_lock);
  818. if (copy_to_user(buf + ret_val,
  819. log_buf->log_data + ppos_data,
  820. count)) {
  821. return -EFAULT;
  822. }
  823. ret_val += count;
  824. rem_len -= count;
  825. qdf_spin_lock_bh(&pl_info->log_lock);
  826. }
  827. }
  828. rd_done:
  829. if ((ret_val < nbytes) && pl_info->saved_state) {
  830. pl_info->log_state = pl_info->saved_state;
  831. pl_info->saved_state = 0;
  832. }
  833. *ppos += ret_val;
  834. qdf_spin_unlock_bh(&pl_info->log_lock);
  835. return ret_val;
  836. }
  837. static ssize_t
  838. pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
  839. {
  840. struct ath_pktlog_info *info = PDE_DATA(file->f_path.dentry->d_inode);
  841. struct qdf_op_sync *op_sync;
  842. ssize_t err_size;
  843. if (!info)
  844. return 0;
  845. err_size = qdf_op_protect(&op_sync);
  846. if (err_size)
  847. return err_size;
  848. mutex_lock(&info->pktlog_mutex);
  849. err_size = __pktlog_read(file, buf, nbytes, ppos);
  850. mutex_unlock(&info->pktlog_mutex);
  851. qdf_op_unprotect(op_sync);
  852. return err_size;
  853. }
  854. int pktlogmod_init(void *context)
  855. {
  856. int ret;
  857. qdf_info("Initialize pkt_log module");
  858. /* create the proc directory entry */
  859. g_pktlog_pde = proc_mkdir(PKTLOG_PROC_DIR, NULL);
  860. if (!g_pktlog_pde) {
  861. qdf_info(PKTLOG_TAG "proc_mkdir failed");
  862. return -EPERM;
  863. }
  864. /* Attach packet log */
  865. ret = pktlog_attach((struct hif_opaque_softc *)context);
  866. /* If packet log init failed */
  867. if (ret) {
  868. qdf_err("pktlog_attach failed");
  869. goto attach_fail;
  870. }
  871. return ret;
  872. attach_fail:
  873. remove_proc_entry(PKTLOG_PROC_DIR, NULL);
  874. g_pktlog_pde = NULL;
  875. return ret;
  876. }
  877. void pktlogmod_exit(void *context)
  878. {
  879. qdf_info("pkt_log module cleanup");
  880. if (!g_pktlog_pde) {
  881. qdf_err("g_pktlog_pde is NULL");
  882. return;
  883. }
  884. pktlog_detach((struct hif_opaque_softc *)context);
  885. /*
  886. * pdev kill needs to be implemented
  887. */
  888. remove_proc_entry(PKTLOG_PROC_DIR, NULL);
  889. g_pktlog_pde = NULL;
  890. }
  891. #endif