linux_ac.c 27 KB

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