wlan_logging_sock_svc.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  1. /*
  2. * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
  3. *
  4. * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  5. *
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for
  8. * any purpose with or without fee is hereby granted, provided that the
  9. * above copyright notice and this permission notice appear in all
  10. * copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  15. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  16. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  17. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19. * PERFORMANCE OF THIS SOFTWARE.
  20. */
  21. /*
  22. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. /******************************************************************************
  27. * wlan_logging_sock_svc.c
  28. *
  29. ******************************************************************************/
  30. #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
  31. #include <vmalloc.h>
  32. #ifdef CONFIG_MCL
  33. #include <cds_api.h>
  34. #include <host_diag_core_event.h>
  35. #include "cds_utils.h"
  36. #include "csr_api.h"
  37. #include "wlan_hdd_main.h"
  38. #include "wma.h"
  39. #include "ol_txrx_api.h"
  40. #include "pktlog_ac.h"
  41. #endif
  42. #include <wlan_logging_sock_svc.h>
  43. #include <kthread.h>
  44. #include <qdf_time.h>
  45. #include <qdf_trace.h>
  46. #include <qdf_mc_timer.h>
  47. #include <wlan_ptt_sock_svc.h>
  48. #include <host_diag_core_event.h>
  49. #include "host_diag_core_log.h"
  50. #ifdef CNSS_GENL
  51. #include <net/cnss_nl.h>
  52. #endif
  53. #define MAX_NUM_PKT_LOG 32
  54. #define ALLOWED_LOG_LEVELS_TO_CONSOLE(level) \
  55. ((QDF_TRACE_LEVEL_FATAL == (level)) || \
  56. (QDF_TRACE_LEVEL_ERROR == (level)) || \
  57. (QDF_TRACE_LEVEL_WARN == (level)) || \
  58. (QDF_TRACE_LEVEL_INFO == (level)))
  59. /**
  60. * struct tx_status - tx status
  61. * @tx_status_ok: successfully sent + acked
  62. * @tx_status_discard: discard - not sent (congestion control)
  63. * @tx_status_no_ack: no_ack - sent, but no ack
  64. * @tx_status_download_fail: download_fail -
  65. * the host could not deliver the tx frame to the target
  66. * @tx_status_peer_del: peer_del - tx completion for
  67. * alreay deleted peer used for HL case
  68. *
  69. * This enum has tx status types
  70. */
  71. enum tx_status {
  72. tx_status_ok,
  73. tx_status_discard,
  74. tx_status_no_ack,
  75. tx_status_download_fail,
  76. tx_status_peer_del,
  77. };
  78. #ifdef CONFIG_MCL
  79. static uint8_t gtx_count;
  80. static uint8_t grx_count;
  81. #endif
  82. #define LOGGING_TRACE(level, args ...) \
  83. QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args)
  84. /* Global variables */
  85. #define ANI_NL_MSG_LOG_TYPE 89
  86. #define ANI_NL_MSG_READY_IND_TYPE 90
  87. #ifndef MAX_LOGMSG_COUNT
  88. #define MAX_LOGMSG_COUNT 256
  89. #endif
  90. #define MAX_LOGMSG_LENGTH 2048
  91. #define MAX_SKBMSG_LENGTH 4096
  92. #define MAX_PKTSTATS_LENGTH 2048
  93. #define MAX_PKTSTATS_BUFF 16
  94. #define HOST_LOG_DRIVER_MSG 0x001
  95. #define HOST_LOG_PER_PKT_STATS 0x002
  96. #define HOST_LOG_FW_FLUSH_COMPLETE 0x003
  97. #define DIAG_TYPE_LOGS 1
  98. #define PTT_MSG_DIAG_CMDS_TYPE 0x5050
  99. struct log_msg {
  100. struct list_head node;
  101. unsigned int radio;
  102. unsigned int index;
  103. /* indicates the current filled log length in logbuf */
  104. unsigned int filled_length;
  105. /*
  106. * Buf to hold the log msg
  107. * tAniHdr + log
  108. */
  109. char logbuf[MAX_LOGMSG_LENGTH];
  110. };
  111. /**
  112. * struct packet_dump - This data structure contains the
  113. * Tx/Rx packet stats
  114. * @status: Status
  115. * @type: Type
  116. * @driver_ts: driver timestamp
  117. * @fw_ts: fw timestamp
  118. */
  119. struct packet_dump {
  120. unsigned char status;
  121. unsigned char type;
  122. uint32_t driver_ts;
  123. uint16_t fw_ts;
  124. } __attribute__((__packed__));
  125. /**
  126. * struct pkt_stats_msg - This data structure contains the
  127. * pkt stats node for link list
  128. * @node: LinkList node
  129. * @node: Pointer to skb
  130. */
  131. struct pkt_stats_msg {
  132. struct list_head node;
  133. struct sk_buff *skb;
  134. };
  135. struct wlan_logging {
  136. /* Log Fatal and ERROR to console */
  137. bool log_to_console;
  138. /* Number of buffers to be used for logging */
  139. uint32_t num_buf;
  140. uint32_t buffer_length;
  141. /* Lock to synchronize access to shared logging resource */
  142. spinlock_t spin_lock;
  143. /* Holds the free node which can be used for filling logs */
  144. struct list_head free_list;
  145. /* Holds the filled nodes which needs to be indicated to APP */
  146. struct list_head filled_list;
  147. /* Wait queue for Logger thread */
  148. wait_queue_head_t wait_queue;
  149. /* Logger thread */
  150. struct task_struct *thread;
  151. /* Logging thread sets this variable on exit */
  152. struct completion shutdown_comp;
  153. /* Indicates to logger thread to exit */
  154. bool exit;
  155. /* Holds number of dropped logs */
  156. unsigned int drop_count;
  157. /* current logbuf to which the log will be filled to */
  158. struct log_msg *pcur_node;
  159. /* Event flag used for wakeup and post indication*/
  160. unsigned long eventFlag;
  161. /* Indicates logger thread is activated */
  162. bool is_active;
  163. /* Flush completion check */
  164. bool is_flush_complete;
  165. /* paramaters for pkt stats */
  166. struct list_head pkt_stat_free_list;
  167. struct list_head pkt_stat_filled_list;
  168. struct pkt_stats_msg *pkt_stats_pcur_node;
  169. unsigned int pkt_stat_drop_cnt;
  170. spinlock_t pkt_stats_lock;
  171. unsigned int pkt_stats_msg_idx;
  172. };
  173. static struct wlan_logging gwlan_logging;
  174. static struct log_msg gplog_msg[MAX_LOGMSG_COUNT];
  175. static struct pkt_stats_msg *gpkt_stats_buffers;
  176. /* Need to call this with spin_lock acquired */
  177. static int wlan_queue_logmsg_for_app(void)
  178. {
  179. char *ptr;
  180. int ret = 0;
  181. ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
  182. ptr[gwlan_logging.pcur_node->filled_length] = '\0';
  183. *(unsigned short *)(gwlan_logging.pcur_node->logbuf) =
  184. ANI_NL_MSG_LOG_TYPE;
  185. *(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) =
  186. gwlan_logging.pcur_node->filled_length;
  187. list_add_tail(&gwlan_logging.pcur_node->node,
  188. &gwlan_logging.filled_list);
  189. if (!list_empty(&gwlan_logging.free_list)) {
  190. /* Get buffer from free list */
  191. gwlan_logging.pcur_node =
  192. (struct log_msg *)(gwlan_logging.free_list.next);
  193. list_del_init(gwlan_logging.free_list.next);
  194. } else if (!list_empty(&gwlan_logging.filled_list)) {
  195. /* Get buffer from filled list */
  196. /* This condition will drop the packet from being
  197. * indicated to app
  198. */
  199. gwlan_logging.pcur_node =
  200. (struct log_msg *)(gwlan_logging.filled_list.next);
  201. ++gwlan_logging.drop_count;
  202. list_del_init(gwlan_logging.filled_list.next);
  203. ret = 1;
  204. }
  205. /* Reset the current node values */
  206. gwlan_logging.pcur_node->filled_length = 0;
  207. return ret;
  208. }
  209. #ifdef QCA_WIFI_3_0_ADRASTEA
  210. /**
  211. * wlan_add_user_log_radio_time_stamp() - add radio, firmware timestamp and
  212. * time stamp in log buffer
  213. * @tbuf: Pointer to time stamp buffer
  214. * @tbuf_sz: Time buffer size
  215. * @ts: Time stamp value
  216. * @radoi: the radio index
  217. *
  218. * For adrastea time stamp is QTIMER raw tick which will be used by cnss_diag
  219. * to convert it into user visible time stamp. In adrstea FW also uses QTIMER
  220. * raw ticks which is needed to synchronize host and fw log time stamps
  221. *
  222. * Also add logcat timestamp so that driver logs and
  223. * logcat logs can be co-related
  224. *
  225. * For discrete solution e.g rome use system tick and convert it into
  226. * seconds.milli seconds
  227. *
  228. * Return: number of characters written in target buffer not including
  229. * trailing '/0'
  230. */
  231. static int wlan_add_user_log_radio_time_stamp(char *tbuf, size_t tbuf_sz,
  232. uint64_t ts, int radio)
  233. {
  234. int tlen;
  235. char time_buf[20];
  236. qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf));
  237. tlen = scnprintf(tbuf, tbuf_sz, "R%d: [%.16s][%llu] %s ", radio,
  238. ((in_irq() ? "irq" : in_softirq() ? "soft_irq" :
  239. current->comm)),
  240. ts, time_buf);
  241. return tlen;
  242. }
  243. #else
  244. /**
  245. * wlan_add_user_log_radio_time_stamp() - add radio, firmware timestamp and
  246. * logcat timestamp in log buffer
  247. * @tbuf: Pointer to time stamp buffer
  248. * @tbuf_sz: Time buffer size
  249. * @ts: Time stamp value
  250. * @radio: the radio index
  251. *
  252. * For adrastea time stamp QTIMER raw tick which will be used by cnss_diag
  253. * to convert it into user visible time stamp
  254. *
  255. * Also add logcat timestamp so that driver logs and
  256. * logcat logs can be co-related
  257. *
  258. * For discrete solution e.g rome use system tick and convert it into
  259. * seconds.milli seconds
  260. *
  261. * Return: number of characters written in target buffer not including
  262. * trailing '/0'
  263. */
  264. static int wlan_add_user_log_radio_time_stamp(char *tbuf, size_t tbuf_sz,
  265. uint64_t ts, int radio)
  266. {
  267. int tlen;
  268. uint32_t rem;
  269. char time_buf[20];
  270. qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf));
  271. rem = do_div(ts, QDF_MC_TIMER_TO_SEC_UNIT);
  272. tlen = scnprintf(tbuf, tbuf_sz, "R%d: [%.16s][%lu.%06lu] %s ", radio,
  273. ((in_irq() ? "irq" : in_softirq() ? "soft_irq" :
  274. current->comm)),
  275. (unsigned long) ts,
  276. (unsigned long)rem, time_buf);
  277. return tlen;
  278. }
  279. #endif
  280. #ifdef CONFIG_MCL
  281. static inline void print_to_console(char *tbuf, char *to_be_sent)
  282. {
  283. pr_err("%s %s\n", tbuf, to_be_sent);
  284. }
  285. #else
  286. #define print_to_console(str1, str2)
  287. #endif
  288. int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length)
  289. {
  290. /* Add the current time stamp */
  291. char *ptr;
  292. char tbuf[60];
  293. int tlen;
  294. int total_log_len;
  295. unsigned int *pfilled_length;
  296. bool wake_up_thread = false;
  297. unsigned long flags;
  298. uint64_t ts;
  299. int radio = 0;
  300. bool log_overflow = false;
  301. #ifdef CONFIG_MCL
  302. radio = cds_get_radio_index();
  303. #endif
  304. if (
  305. #ifdef CONFIG_MCL
  306. !cds_is_multicast_logging() ||
  307. #endif
  308. (radio == -EINVAL) ||
  309. (!gwlan_logging.is_active)) {
  310. /*
  311. * This is to make sure that we print the logs to kmsg console
  312. * when no logger app is running. This is also needed to
  313. * log the initial messages during loading of driver where even
  314. * if app is running it will not be able to
  315. * register with driver immediately and start logging all the
  316. * messages.
  317. */
  318. /*
  319. * R%d: if the radio index is invalid, just post the message
  320. * to console.
  321. * Also the radio index shouldn't happen to be EINVAL, but if
  322. * that happen just print it, so that the logging would be
  323. * aware the cnss_logger is somehow failed.
  324. */
  325. pr_info("R%d: %s\n", radio, to_be_sent);
  326. return 0;
  327. }
  328. ts = qdf_get_log_timestamp();
  329. tlen = wlan_add_user_log_radio_time_stamp(tbuf, sizeof(tbuf), ts,
  330. radio);
  331. /* 1+1 indicate '\n'+'\0' */
  332. total_log_len = length + tlen + 1 + 1;
  333. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  334. /* wlan logging svc resources are not yet initialized */
  335. if (!gwlan_logging.pcur_node) {
  336. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  337. return -EIO;
  338. }
  339. pfilled_length = &gwlan_logging.pcur_node->filled_length;
  340. /* Check if we can accomodate more log into current node/buffer */
  341. if ((MAX_LOGMSG_LENGTH <= (*pfilled_length + sizeof(tAniNlHdr))) ||
  342. ((MAX_LOGMSG_LENGTH - (*pfilled_length +
  343. sizeof(tAniNlHdr))) < total_log_len)) {
  344. wake_up_thread = true;
  345. wlan_queue_logmsg_for_app();
  346. pfilled_length = &gwlan_logging.pcur_node->filled_length;
  347. }
  348. ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
  349. /* Assumption here is that we receive logs which is always less than
  350. * MAX_LOGMSG_LENGTH, where we can accomodate the
  351. * tAniNlHdr + [context][timestamp] + log
  352. *
  353. * Continue and copy logs to the available length and discard the rest.
  354. */
  355. if (MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len)) {
  356. log_overflow = true;
  357. total_log_len = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - 2;
  358. }
  359. memcpy(&ptr[*pfilled_length], tbuf, tlen);
  360. memcpy(&ptr[*pfilled_length + tlen], to_be_sent,
  361. min(length, (total_log_len - tlen)));
  362. *pfilled_length += tlen + min(length, total_log_len - tlen);
  363. ptr[*pfilled_length] = '\n';
  364. *pfilled_length += 1;
  365. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  366. /*
  367. * QDF_ASSERT if complete log was not accomodated into
  368. * the available buffer.
  369. */
  370. QDF_ASSERT(!log_overflow);
  371. /* Wakeup logger thread */
  372. if ((true == wake_up_thread)) {
  373. set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  374. wake_up_interruptible(&gwlan_logging.wait_queue);
  375. }
  376. if (gwlan_logging.log_to_console
  377. && ALLOWED_LOG_LEVELS_TO_CONSOLE(log_level)) {
  378. print_to_console(tbuf, to_be_sent);
  379. }
  380. return 0;
  381. }
  382. /**
  383. * pkt_stats_fill_headers() - This function adds headers to skb
  384. * @skb: skb to which headers need to be added
  385. *
  386. * Return: 0 on success or Errno on failure
  387. */
  388. static int pkt_stats_fill_headers(struct sk_buff *skb)
  389. {
  390. struct host_log_pktlog_info cds_pktlog;
  391. int cds_pkt_size = sizeof(struct host_log_pktlog_info);
  392. tAniNlHdr msg_header;
  393. int extra_header_len, nl_payload_len;
  394. static int nlmsg_seq;
  395. int diag_type;
  396. qdf_mem_zero(&cds_pktlog, cds_pkt_size);
  397. cds_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C;
  398. cds_pktlog.buf_len = skb->len;
  399. cds_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++;
  400. #ifdef CONFIG_MCL
  401. host_diag_log_set_code(&cds_pktlog, LOG_WLAN_PKT_LOG_INFO_C);
  402. host_diag_log_set_length(&cds_pktlog.log_hdr, skb->len +
  403. cds_pkt_size);
  404. #endif
  405. if (unlikely(skb_headroom(skb) < cds_pkt_size)) {
  406. pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]",
  407. __LINE__, skb->head, skb->data, sizeof(msg_header));
  408. return -EIO;
  409. }
  410. qdf_mem_copy(skb_push(skb, cds_pkt_size),
  411. &cds_pktlog, cds_pkt_size);
  412. if (unlikely(skb_headroom(skb) < sizeof(int))) {
  413. pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]",
  414. __LINE__, skb->head, skb->data, sizeof(int));
  415. return -EIO;
  416. }
  417. diag_type = DIAG_TYPE_LOGS;
  418. qdf_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int));
  419. extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) +
  420. sizeof(struct nlmsghdr);
  421. nl_payload_len = extra_header_len + skb->len;
  422. msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC;
  423. msg_header.nlh.nlmsg_len = nl_payload_len;
  424. msg_header.nlh.nlmsg_flags = NLM_F_REQUEST;
  425. msg_header.nlh.nlmsg_pid = 0;
  426. msg_header.nlh.nlmsg_seq = nlmsg_seq++;
  427. msg_header.radio = 0;
  428. msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE;
  429. msg_header.wmsg.length = cpu_to_be16(skb->len);
  430. if (unlikely(skb_headroom(skb) < sizeof(msg_header))) {
  431. pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]",
  432. __LINE__, skb->head, skb->data, sizeof(msg_header));
  433. return -EIO;
  434. }
  435. qdf_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header,
  436. sizeof(msg_header));
  437. return 0;
  438. }
  439. /**
  440. * nl_srv_bcast_diag() - Wrapper to send bcast msgs to diag events mcast grp
  441. * @skb: sk buffer pointer
  442. *
  443. * Sends the bcast message to diag events multicast group with generic nl socket
  444. * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
  445. *
  446. * Return: zero on success, error code otherwise
  447. */
  448. static int nl_srv_bcast_diag(struct sk_buff *skb)
  449. {
  450. #ifdef CNSS_GENL
  451. return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
  452. #else
  453. return nl_srv_bcast(skb);
  454. #endif
  455. }
  456. /**
  457. * nl_srv_bcast_host_logs() - Wrapper to send bcast msgs to host logs mcast grp
  458. * @skb: sk buffer pointer
  459. *
  460. * Sends the bcast message to host logs multicast group with generic nl socket
  461. * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
  462. *
  463. * Return: zero on success, error code otherwise
  464. */
  465. static int nl_srv_bcast_host_logs(struct sk_buff *skb)
  466. {
  467. #ifdef CNSS_GENL
  468. return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
  469. #else
  470. return nl_srv_bcast(skb);
  471. #endif
  472. }
  473. /**
  474. * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per
  475. * packet statistics to the user
  476. *
  477. * This function is used to send the per packet statistics to the user
  478. *
  479. * Return: Success if the message is posted to user
  480. */
  481. int pktlog_send_per_pkt_stats_to_user(void)
  482. {
  483. int ret = -1;
  484. struct pkt_stats_msg *pstats_msg;
  485. unsigned long flags;
  486. struct sk_buff *skb_new = NULL;
  487. static int rate_limit;
  488. bool free_old_skb = false;
  489. while (!list_empty(&gwlan_logging.pkt_stat_filled_list)
  490. && !gwlan_logging.exit) {
  491. skb_new = dev_alloc_skb(MAX_SKBMSG_LENGTH);
  492. if (skb_new == NULL) {
  493. if (!rate_limit) {
  494. pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
  495. __func__, MAX_SKBMSG_LENGTH,
  496. gwlan_logging.drop_count);
  497. }
  498. rate_limit = 1;
  499. ret = -ENOMEM;
  500. break;
  501. }
  502. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  503. pstats_msg = (struct pkt_stats_msg *)
  504. (gwlan_logging.pkt_stat_filled_list.next);
  505. list_del_init(gwlan_logging.pkt_stat_filled_list.next);
  506. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  507. ret = pkt_stats_fill_headers(pstats_msg->skb);
  508. if (ret < 0) {
  509. pr_err("%s failed to fill headers %d\n", __func__, ret);
  510. free_old_skb = true;
  511. goto err;
  512. }
  513. ret = nl_srv_bcast_diag(pstats_msg->skb);
  514. if (ret < 0) {
  515. pr_info("%s: Send Failed %d drop_count = %u\n",
  516. __func__, ret,
  517. ++gwlan_logging.pkt_stat_drop_cnt);
  518. } else {
  519. ret = 0;
  520. }
  521. err:
  522. /*
  523. * Free old skb in case or error before assigning new skb
  524. * to the free list.
  525. */
  526. if (free_old_skb)
  527. dev_kfree_skb(pstats_msg->skb);
  528. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  529. pstats_msg->skb = skb_new;
  530. list_add_tail(&pstats_msg->node,
  531. &gwlan_logging.pkt_stat_free_list);
  532. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  533. ret = 0;
  534. }
  535. return ret;
  536. }
  537. static int send_filled_buffers_to_user(void)
  538. {
  539. int ret = -1;
  540. struct log_msg *plog_msg;
  541. int payload_len;
  542. int tot_msg_len;
  543. tAniNlHdr *wnl;
  544. struct sk_buff *skb = NULL;
  545. struct nlmsghdr *nlh;
  546. static int nlmsg_seq;
  547. unsigned long flags;
  548. static int rate_limit;
  549. while (!list_empty(&gwlan_logging.filled_list)
  550. && !gwlan_logging.exit) {
  551. skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
  552. if (skb == NULL) {
  553. if (!rate_limit) {
  554. pr_err
  555. ("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
  556. __func__, MAX_LOGMSG_LENGTH,
  557. gwlan_logging.drop_count);
  558. }
  559. rate_limit = 1;
  560. ret = -ENOMEM;
  561. break;
  562. }
  563. rate_limit = 0;
  564. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  565. plog_msg = (struct log_msg *)
  566. (gwlan_logging.filled_list.next);
  567. list_del_init(gwlan_logging.filled_list.next);
  568. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  569. /* 4 extra bytes for the radio idx */
  570. payload_len = plog_msg->filled_length +
  571. sizeof(wnl->radio) + sizeof(tAniHdr);
  572. tot_msg_len = NLMSG_SPACE(payload_len);
  573. nlh = nlmsg_put(skb, 0, nlmsg_seq++,
  574. ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST);
  575. if (NULL == nlh) {
  576. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  577. list_add_tail(&plog_msg->node,
  578. &gwlan_logging.free_list);
  579. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  580. pr_err("%s: drop_count = %u\n", __func__,
  581. ++gwlan_logging.drop_count);
  582. pr_err("%s: nlmsg_put() failed for msg size[%d]\n",
  583. __func__, tot_msg_len);
  584. dev_kfree_skb(skb);
  585. skb = NULL;
  586. ret = -EINVAL;
  587. continue;
  588. }
  589. wnl = (tAniNlHdr *) nlh;
  590. wnl->radio = plog_msg->radio;
  591. memcpy(&wnl->wmsg, plog_msg->logbuf,
  592. plog_msg->filled_length + sizeof(tAniHdr));
  593. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  594. list_add_tail(&plog_msg->node, &gwlan_logging.free_list);
  595. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  596. ret = nl_srv_bcast_host_logs(skb);
  597. /* print every 64th drop count */
  598. if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) {
  599. pr_err("%s: Send Failed %d drop_count = %u\n",
  600. __func__, ret, ++gwlan_logging.drop_count);
  601. }
  602. }
  603. return ret;
  604. }
  605. #ifdef FEATURE_WLAN_DIAG_SUPPORT
  606. /**
  607. * wlan_report_log_completion() - Report bug report completion to userspace
  608. * @is_fatal: Type of event, fatal or not
  609. * @indicator: Source of bug report, framework/host/firmware
  610. * @reason_code: Reason for triggering bug report
  611. * @ring_id: Ring id of logging entities
  612. *
  613. * This function is used to report the bug report completion to userspace
  614. *
  615. * Return: None
  616. */
  617. void wlan_report_log_completion(uint32_t is_fatal,
  618. uint32_t indicator,
  619. uint32_t reason_code,
  620. uint8_t ring_id)
  621. {
  622. WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
  623. struct host_event_wlan_log_complete);
  624. wlan_diag_event.is_fatal = is_fatal;
  625. wlan_diag_event.indicator = indicator;
  626. wlan_diag_event.reason_code = reason_code;
  627. wlan_diag_event.reserved = ring_id;
  628. WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE);
  629. }
  630. #endif
  631. #ifdef CONFIG_MCL
  632. /**
  633. * send_flush_completion_to_user() - Indicate flush completion to the user
  634. * @ring_id: Ring id of logging entities
  635. *
  636. * This function is used to send the flush completion message to user space
  637. *
  638. * Return: None
  639. */
  640. static void send_flush_completion_to_user(uint8_t ring_id)
  641. {
  642. uint32_t is_fatal, indicator, reason_code;
  643. bool recovery_needed;
  644. cds_get_and_reset_log_completion(&is_fatal,
  645. &indicator, &reason_code, &recovery_needed);
  646. /* Error on purpose, so that it will get logged in the kmsg */
  647. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  648. "%s: Sending flush done to userspace", __func__);
  649. wlan_report_log_completion(is_fatal, indicator, reason_code, ring_id);
  650. if (recovery_needed)
  651. cds_trigger_recovery();
  652. }
  653. #endif
  654. /**
  655. * wlan_logging_thread() - The WLAN Logger thread
  656. * @Arg - pointer to the HDD context
  657. *
  658. * This thread logs log message to App registered for the logs.
  659. */
  660. static int wlan_logging_thread(void *Arg)
  661. {
  662. int ret_wait_status = 0;
  663. int ret = 0;
  664. unsigned long flags;
  665. while (!gwlan_logging.exit) {
  666. ret_wait_status =
  667. wait_event_interruptible(gwlan_logging.wait_queue,
  668. (!list_empty
  669. (&gwlan_logging.filled_list)
  670. || test_bit(
  671. HOST_LOG_DRIVER_MSG,
  672. &gwlan_logging.eventFlag)
  673. || test_bit(
  674. HOST_LOG_PER_PKT_STATS,
  675. &gwlan_logging.eventFlag)
  676. || test_bit(
  677. HOST_LOG_FW_FLUSH_COMPLETE,
  678. &gwlan_logging.eventFlag)
  679. || gwlan_logging.exit));
  680. if (ret_wait_status == -ERESTARTSYS) {
  681. pr_err
  682. ("%s: wait_event_interruptible returned -ERESTARTSYS",
  683. __func__);
  684. break;
  685. }
  686. if (gwlan_logging.exit)
  687. break;
  688. if (test_and_clear_bit(HOST_LOG_DRIVER_MSG,
  689. &gwlan_logging.eventFlag)) {
  690. ret = send_filled_buffers_to_user();
  691. if (-ENOMEM == ret)
  692. msleep(200);
  693. #ifdef CONFIG_MCL
  694. if (WLAN_LOG_INDICATOR_HOST_ONLY ==
  695. cds_get_log_indicator()) {
  696. send_flush_completion_to_user(
  697. RING_ID_DRIVER_DEBUG);
  698. }
  699. #endif
  700. }
  701. if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS,
  702. &gwlan_logging.eventFlag)) {
  703. ret = pktlog_send_per_pkt_stats_to_user();
  704. if (-ENOMEM == ret)
  705. msleep(200);
  706. }
  707. if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE,
  708. &gwlan_logging.eventFlag)) {
  709. /* Flush bit could have been set while we were mid
  710. * way in the logging thread. So, need to check other
  711. * buffers like log messages, per packet stats again
  712. * to flush any residual data in them
  713. */
  714. if (gwlan_logging.is_flush_complete == true) {
  715. gwlan_logging.is_flush_complete = false;
  716. #ifdef CONFIG_MCL
  717. send_flush_completion_to_user(
  718. RING_ID_DRIVER_DEBUG);
  719. #endif
  720. } else {
  721. gwlan_logging.is_flush_complete = true;
  722. /* Flush all current host logs*/
  723. spin_lock_irqsave(&gwlan_logging.spin_lock,
  724. flags);
  725. wlan_queue_logmsg_for_app();
  726. spin_unlock_irqrestore(&gwlan_logging.spin_lock,
  727. flags);
  728. set_bit(HOST_LOG_DRIVER_MSG,
  729. &gwlan_logging.eventFlag);
  730. set_bit(HOST_LOG_PER_PKT_STATS,
  731. &gwlan_logging.eventFlag);
  732. set_bit(HOST_LOG_FW_FLUSH_COMPLETE,
  733. &gwlan_logging.eventFlag);
  734. wake_up_interruptible(
  735. &gwlan_logging.wait_queue);
  736. }
  737. }
  738. }
  739. complete_and_exit(&gwlan_logging.shutdown_comp, 0);
  740. return 0;
  741. }
  742. void wlan_logging_set_active(bool active)
  743. {
  744. gwlan_logging.is_active = active;
  745. }
  746. void wlan_logging_set_log_to_console(bool log_to_console)
  747. {
  748. gwlan_logging.log_to_console = log_to_console;
  749. }
  750. int wlan_logging_sock_init_svc(void)
  751. {
  752. int i = 0, j, pkt_stats_size;
  753. unsigned long irq_flag;
  754. spin_lock_init(&gwlan_logging.spin_lock);
  755. spin_lock_init(&gwlan_logging.pkt_stats_lock);
  756. gwlan_logging.log_to_console = true;
  757. gwlan_logging.num_buf = MAX_LOGMSG_COUNT;
  758. gwlan_logging.buffer_length = MAX_LOGMSG_LENGTH;
  759. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  760. INIT_LIST_HEAD(&gwlan_logging.free_list);
  761. INIT_LIST_HEAD(&gwlan_logging.filled_list);
  762. for (i = 0; i < gwlan_logging.num_buf; i++) {
  763. list_add(&gplog_msg[i].node, &gwlan_logging.free_list);
  764. gplog_msg[i].index = i;
  765. }
  766. gwlan_logging.pcur_node = (struct log_msg *)
  767. (gwlan_logging.free_list.next);
  768. list_del_init(gwlan_logging.free_list.next);
  769. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  770. /* Initialize the pktStats data structure here */
  771. pkt_stats_size = sizeof(struct pkt_stats_msg);
  772. gpkt_stats_buffers = vmalloc(MAX_PKTSTATS_BUFF * pkt_stats_size);
  773. if (!gpkt_stats_buffers) {
  774. pr_err("%s: Could not allocate memory for Pkt stats\n",
  775. __func__);
  776. goto err1;
  777. }
  778. qdf_mem_zero(gpkt_stats_buffers,
  779. MAX_PKTSTATS_BUFF * pkt_stats_size);
  780. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  781. gwlan_logging.pkt_stats_msg_idx = 0;
  782. INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list);
  783. INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list);
  784. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  785. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  786. gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH);
  787. if (gpkt_stats_buffers[i].skb == NULL) {
  788. pr_err("%s: Memory alloc failed for skb", __func__);
  789. /* free previously allocated skb and return */
  790. for (j = 0; j < i ; j++)
  791. dev_kfree_skb(gpkt_stats_buffers[j].skb);
  792. goto err2;
  793. }
  794. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  795. list_add(&gpkt_stats_buffers[i].node,
  796. &gwlan_logging.pkt_stat_free_list);
  797. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  798. }
  799. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  800. gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *)
  801. (gwlan_logging.pkt_stat_free_list.next);
  802. list_del_init(gwlan_logging.pkt_stat_free_list.next);
  803. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  804. /* Pkt Stats intialization done */
  805. init_waitqueue_head(&gwlan_logging.wait_queue);
  806. gwlan_logging.exit = false;
  807. clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  808. clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  809. clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  810. init_completion(&gwlan_logging.shutdown_comp);
  811. gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
  812. "wlan_logging_thread");
  813. if (IS_ERR(gwlan_logging.thread)) {
  814. pr_err("%s: Could not Create LogMsg Thread Controller",
  815. __func__);
  816. goto err3;
  817. }
  818. wake_up_process(gwlan_logging.thread);
  819. gwlan_logging.is_active = true;
  820. gwlan_logging.is_flush_complete = false;
  821. return 0;
  822. err3:
  823. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  824. if (gpkt_stats_buffers[i].skb)
  825. dev_kfree_skb(gpkt_stats_buffers[i].skb);
  826. }
  827. err2:
  828. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  829. gwlan_logging.pkt_stats_pcur_node = NULL;
  830. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  831. vfree(gpkt_stats_buffers);
  832. gpkt_stats_buffers = NULL;
  833. err1:
  834. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  835. gwlan_logging.pcur_node = NULL;
  836. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  837. return -ENOMEM;
  838. }
  839. int wlan_logging_sock_deinit_svc(void)
  840. {
  841. unsigned long irq_flag;
  842. int i;
  843. if (!gwlan_logging.pcur_node)
  844. return 0;
  845. #ifdef CONFIG_MCL
  846. INIT_COMPLETION(gwlan_logging.shutdown_comp);
  847. #endif
  848. gwlan_logging.exit = true;
  849. gwlan_logging.is_active = false;
  850. #ifdef CONFIG_MCL
  851. cds_set_multicast_logging(0);
  852. #endif
  853. gwlan_logging.is_flush_complete = false;
  854. clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  855. clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  856. clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  857. wake_up_interruptible(&gwlan_logging.wait_queue);
  858. wait_for_completion(&gwlan_logging.shutdown_comp);
  859. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  860. gwlan_logging.pcur_node = NULL;
  861. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  862. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  863. gwlan_logging.pkt_stats_pcur_node = NULL;
  864. gwlan_logging.pkt_stats_msg_idx = 0;
  865. gwlan_logging.pkt_stat_drop_cnt = 0;
  866. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  867. if (gpkt_stats_buffers[i].skb)
  868. dev_kfree_skb(gpkt_stats_buffers[i].skb);
  869. }
  870. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  871. vfree(gpkt_stats_buffers);
  872. gpkt_stats_buffers = NULL;
  873. return 0;
  874. }
  875. /**
  876. * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging
  877. *
  878. * This function is used to send signal to the logger thread for logging per
  879. * packet stats
  880. *
  881. * Return: None
  882. *
  883. */
  884. void wlan_logging_set_per_pkt_stats(void)
  885. {
  886. if (gwlan_logging.is_active == false)
  887. return;
  888. set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  889. wake_up_interruptible(&gwlan_logging.wait_queue);
  890. }
  891. /*
  892. * wlan_logging_set_fw_flush_complete() - FW log flush completion
  893. *
  894. * This function is used to send signal to the logger thread to indicate
  895. * that the flushing of FW logs is complete by the FW
  896. *
  897. * Return: None
  898. *
  899. */
  900. void wlan_logging_set_fw_flush_complete(void)
  901. {
  902. if (gwlan_logging.is_active == false
  903. #ifdef CONFIG_MCL
  904. || !cds_is_fatal_event_enabled()
  905. #endif
  906. )
  907. return;
  908. set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  909. wake_up_interruptible(&gwlan_logging.wait_queue);
  910. }
  911. /**
  912. * wlan_flush_host_logs_for_fatal() - Flush host logs
  913. *
  914. * This function is used to send signal to the logger thread to
  915. * Flush the host logs
  916. *
  917. * Return: None
  918. */
  919. void wlan_flush_host_logs_for_fatal(void)
  920. {
  921. unsigned long flags;
  922. #ifdef CONFIG_MCL
  923. if (cds_is_log_report_in_progress()) {
  924. #endif
  925. pr_info("%s:flush all host logs Setting HOST_LOG_POST_MASK\n",
  926. __func__);
  927. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  928. wlan_queue_logmsg_for_app();
  929. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  930. set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  931. wake_up_interruptible(&gwlan_logging.wait_queue);
  932. #ifdef CONFIG_MCL
  933. }
  934. #endif
  935. }
  936. /**
  937. * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats
  938. *
  939. * This function is used to get the free node for pkt stats from
  940. * free list/filles list
  941. *
  942. * Return: int
  943. *
  944. */
  945. static int wlan_get_pkt_stats_free_node(void)
  946. {
  947. int ret = 0;
  948. list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node,
  949. &gwlan_logging.pkt_stat_filled_list);
  950. if (!list_empty(&gwlan_logging.pkt_stat_free_list)) {
  951. /* Get buffer from free list */
  952. gwlan_logging.pkt_stats_pcur_node =
  953. (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next);
  954. list_del_init(gwlan_logging.pkt_stat_free_list.next);
  955. } else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) {
  956. /* Get buffer from filled list. This condition will drop the
  957. * packet from being indicated to app
  958. */
  959. gwlan_logging.pkt_stats_pcur_node =
  960. (struct pkt_stats_msg *)
  961. (gwlan_logging.pkt_stat_filled_list.next);
  962. ++gwlan_logging.pkt_stat_drop_cnt;
  963. /* print every 64th drop count */
  964. if (
  965. #ifdef CONFIG_MCL
  966. cds_is_multicast_logging() &&
  967. #endif
  968. (!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) {
  969. pr_err("%s: drop_count = %u\n",
  970. __func__, gwlan_logging.pkt_stat_drop_cnt);
  971. }
  972. list_del_init(gwlan_logging.pkt_stat_filled_list.next);
  973. ret = 1;
  974. }
  975. /* Reset the skb values, essential if dequeued from filled list */
  976. skb_trim(gwlan_logging.pkt_stats_pcur_node->skb, 0);
  977. return ret;
  978. }
  979. /**
  980. * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB
  981. * @pl_hdr: Pointer to pl_hdr
  982. * @pkt_dump: Pointer to pkt_dump
  983. * @data: Pointer to data
  984. *
  985. * This function adds the pktstats hdr and data to current
  986. * skb node of free list.
  987. *
  988. * Return: None
  989. */
  990. void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
  991. {
  992. #ifdef CONFIG_MCL
  993. struct ath_pktlog_hdr *pktlog_hdr;
  994. struct packet_dump *pkt_stats_dump;
  995. int total_stats_len = 0;
  996. bool wake_up_thread = false;
  997. unsigned long flags;
  998. struct sk_buff *ptr;
  999. int hdr_size;
  1000. pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr;
  1001. if (pktlog_hdr == NULL) {
  1002. pr_err("%s : Invalid pkt_stats_header\n", __func__);
  1003. return;
  1004. }
  1005. pkt_stats_dump = (struct packet_dump *)pkt_dump;
  1006. total_stats_len = sizeof(struct ath_pktlog_hdr) +
  1007. pktlog_hdr->size;
  1008. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  1009. if (!gwlan_logging.pkt_stats_pcur_node || (NULL == pkt_stats_dump)) {
  1010. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  1011. return;
  1012. }
  1013. /* Check if we can accommodate more log into current node/buffer */
  1014. hdr_size = sizeof(struct host_log_pktlog_info) +
  1015. sizeof(tAniNlHdr);
  1016. if ((total_stats_len + hdr_size) >=
  1017. skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) {
  1018. wake_up_thread = true;
  1019. wlan_get_pkt_stats_free_node();
  1020. }
  1021. ptr = gwlan_logging.pkt_stats_pcur_node->skb;
  1022. qdf_mem_copy(skb_put(ptr,
  1023. sizeof(struct ath_pktlog_hdr)),
  1024. pktlog_hdr,
  1025. sizeof(struct ath_pktlog_hdr));
  1026. if (pkt_stats_dump) {
  1027. qdf_mem_copy(skb_put(ptr,
  1028. sizeof(struct packet_dump)),
  1029. pkt_stats_dump,
  1030. sizeof(struct packet_dump));
  1031. pktlog_hdr->size -= sizeof(struct packet_dump);
  1032. }
  1033. if (data)
  1034. qdf_mem_copy(skb_put(ptr,
  1035. pktlog_hdr->size),
  1036. data, pktlog_hdr->size);
  1037. if (pkt_stats_dump->type == STOP_MONITOR) {
  1038. wake_up_thread = true;
  1039. wlan_get_pkt_stats_free_node();
  1040. }
  1041. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  1042. /* Wakeup logger thread */
  1043. if (true == wake_up_thread) {
  1044. set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  1045. wake_up_interruptible(&gwlan_logging.wait_queue);
  1046. }
  1047. #endif
  1048. }
  1049. #ifdef CONFIG_MCL
  1050. /**
  1051. * driver_hal_status_map() - maps driver to hal
  1052. * status
  1053. * @status: status to be mapped
  1054. *
  1055. * This function is used to map driver to hal status
  1056. *
  1057. * Return: None
  1058. *
  1059. */
  1060. static void driver_hal_status_map(uint8_t *status)
  1061. {
  1062. switch (*status) {
  1063. case tx_status_ok:
  1064. *status = TX_PKT_FATE_ACKED;
  1065. break;
  1066. case tx_status_discard:
  1067. *status = TX_PKT_FATE_DRV_DROP_OTHER;
  1068. break;
  1069. case tx_status_no_ack:
  1070. *status = TX_PKT_FATE_SENT;
  1071. break;
  1072. case tx_status_download_fail:
  1073. *status = TX_PKT_FATE_FW_QUEUED;
  1074. break;
  1075. default:
  1076. *status = TX_PKT_FATE_DRV_DROP_OTHER;
  1077. break;
  1078. }
  1079. }
  1080. /*
  1081. * send_packetdump() - send packet dump
  1082. * @netbuf: netbuf
  1083. * @status: status of tx packet
  1084. * @vdev_id: virtual device id
  1085. * @type: type of packet
  1086. *
  1087. * This function is used to send packet dump to HAL layer
  1088. * using wlan_pkt_stats_to_logger_thread
  1089. *
  1090. * Return: None
  1091. *
  1092. */
  1093. static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status,
  1094. uint8_t vdev_id, uint8_t type)
  1095. {
  1096. struct ath_pktlog_hdr pktlog_hdr = {0};
  1097. struct packet_dump pd_hdr = {0};
  1098. struct hdd_context *hdd_ctx;
  1099. struct hdd_adapter *adapter;
  1100. v_CONTEXT_t vos_ctx;
  1101. vos_ctx = cds_get_global_context();
  1102. if (!vos_ctx)
  1103. return;
  1104. hdd_ctx = (struct hdd_context *)cds_get_context(QDF_MODULE_ID_HDD);
  1105. if (!hdd_ctx)
  1106. return;
  1107. adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
  1108. if (!adapter)
  1109. return;
  1110. /* Send packet dump only for STA interface */
  1111. if (adapter->device_mode != QDF_STA_MODE)
  1112. return;
  1113. #if defined(HELIUMPLUS)
  1114. pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
  1115. #endif
  1116. pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
  1117. pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len;
  1118. pd_hdr.status = status;
  1119. pd_hdr.type = type;
  1120. pd_hdr.driver_ts = qdf_get_monotonic_boottime();
  1121. if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT))
  1122. gtx_count++;
  1123. else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT))
  1124. grx_count++;
  1125. wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data);
  1126. }
  1127. /*
  1128. * send_packetdump_monitor() - sends start/stop packet dump indication
  1129. * @type: type of packet
  1130. *
  1131. * This function is used to indicate HAL layer to start/stop monitoring
  1132. * of packets
  1133. *
  1134. * Return: None
  1135. *
  1136. */
  1137. static void send_packetdump_monitor(uint8_t type)
  1138. {
  1139. struct ath_pktlog_hdr pktlog_hdr = {0};
  1140. struct packet_dump pd_hdr = {0};
  1141. #if defined(HELIUMPLUS)
  1142. pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
  1143. #endif
  1144. pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
  1145. pktlog_hdr.size = sizeof(pd_hdr);
  1146. pd_hdr.type = type;
  1147. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1148. "fate Tx-Rx %s: type: %d", __func__, type);
  1149. wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL);
  1150. }
  1151. /**
  1152. * wlan_deregister_txrx_packetdump() - tx/rx packet dump
  1153. * deregistration
  1154. *
  1155. * This function is used to deregister tx/rx packet dump callbacks
  1156. * with ol, pe and htt layers
  1157. *
  1158. * Return: None
  1159. *
  1160. */
  1161. void wlan_deregister_txrx_packetdump(void)
  1162. {
  1163. if (gtx_count || grx_count) {
  1164. ol_deregister_packetdump_callback();
  1165. wma_deregister_packetdump_callback();
  1166. send_packetdump_monitor(STOP_MONITOR);
  1167. csr_packetdump_timer_stop();
  1168. gtx_count = 0;
  1169. grx_count = 0;
  1170. } else
  1171. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1172. "%s: deregistered packetdump already", __func__);
  1173. }
  1174. /*
  1175. * check_txrx_packetdump_count() - function to check
  1176. * tx/rx packet dump global counts
  1177. *
  1178. * This function is used to check global counts of tx/rx
  1179. * packet dump functionality.
  1180. *
  1181. * Return: 1 if either gtx_count or grx_count reached 32
  1182. * 0 otherwise
  1183. *
  1184. */
  1185. static bool check_txrx_packetdump_count(void)
  1186. {
  1187. if (gtx_count == MAX_NUM_PKT_LOG ||
  1188. grx_count == MAX_NUM_PKT_LOG) {
  1189. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1190. "%s gtx_count: %d grx_count: %d deregister packetdump",
  1191. __func__, gtx_count, grx_count);
  1192. wlan_deregister_txrx_packetdump();
  1193. return 1;
  1194. }
  1195. return 0;
  1196. }
  1197. /*
  1198. * tx_packetdump_cb() - tx packet dump callback
  1199. * @netbuf: netbuf
  1200. * @status: status of tx packet
  1201. * @vdev_id: virtual device id
  1202. * @type: packet type
  1203. *
  1204. * This function is used to send tx packet dump to HAL layer
  1205. * and deregister packet dump callbacks
  1206. *
  1207. * Return: None
  1208. *
  1209. */
  1210. static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
  1211. uint8_t vdev_id, uint8_t type)
  1212. {
  1213. bool temp;
  1214. temp = check_txrx_packetdump_count();
  1215. if (temp)
  1216. return;
  1217. driver_hal_status_map(&status);
  1218. send_packetdump(netbuf, status, vdev_id, type);
  1219. }
  1220. /*
  1221. * rx_packetdump_cb() - rx packet dump callback
  1222. * @netbuf: netbuf
  1223. * @status: status of rx packet
  1224. * @vdev_id: virtual device id
  1225. * @type: packet type
  1226. *
  1227. * This function is used to send rx packet dump to HAL layer
  1228. * and deregister packet dump callbacks
  1229. *
  1230. * Return: None
  1231. *
  1232. */
  1233. static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
  1234. uint8_t vdev_id, uint8_t type)
  1235. {
  1236. bool temp;
  1237. temp = check_txrx_packetdump_count();
  1238. if (temp)
  1239. return;
  1240. send_packetdump(netbuf, status, vdev_id, type);
  1241. }
  1242. /**
  1243. * wlan_register_txrx_packetdump() - tx/rx packet dump
  1244. * registration
  1245. *
  1246. * This function is used to register tx/rx packet dump callbacks
  1247. * with ol, pe and htt layers
  1248. *
  1249. * Return: None
  1250. *
  1251. */
  1252. void wlan_register_txrx_packetdump(void)
  1253. {
  1254. ol_register_packetdump_callback(tx_packetdump_cb,
  1255. rx_packetdump_cb);
  1256. wma_register_packetdump_callback(tx_packetdump_cb,
  1257. rx_packetdump_cb);
  1258. send_packetdump_monitor(START_MONITOR);
  1259. gtx_count = 0;
  1260. grx_count = 0;
  1261. }
  1262. #endif
  1263. #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */