wlan_logging_sock_svc.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. /*
  2. * Copyright (c) 2014-2018 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 <linux/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 <linux/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. #ifdef CONFIG_MCL
  301. radio = cds_get_radio_index();
  302. #endif
  303. if ((radio == -EINVAL) || (!gwlan_logging.is_active)) {
  304. /*
  305. * R%d: if the radio index is invalid, just post the message
  306. * to console.
  307. * Also the radio index shouldn't happen to be EINVAL, but if
  308. * that happen just print it, so that the logging would be
  309. * aware the cnss_logger is somehow failed.
  310. */
  311. pr_info("R%d: %s\n", radio, to_be_sent);
  312. return 0;
  313. }
  314. ts = qdf_get_log_timestamp();
  315. tlen = wlan_add_user_log_radio_time_stamp(tbuf, sizeof(tbuf), ts,
  316. radio);
  317. /* 1+1 indicate '\n'+'\0' */
  318. total_log_len = length + tlen + 1 + 1;
  319. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  320. /* wlan logging svc resources are not yet initialized */
  321. if (!gwlan_logging.pcur_node) {
  322. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  323. return -EIO;
  324. }
  325. pfilled_length = &gwlan_logging.pcur_node->filled_length;
  326. /* Check if we can accommodate more log into current node/buffer */
  327. if ((MAX_LOGMSG_LENGTH - (*pfilled_length +
  328. sizeof(tAniNlHdr))) < total_log_len) {
  329. wake_up_thread = true;
  330. wlan_queue_logmsg_for_app();
  331. pfilled_length = &gwlan_logging.pcur_node->filled_length;
  332. }
  333. ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
  334. if (unlikely(MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len))) {
  335. /*
  336. * Assumption here is that we receive logs which is less than
  337. * MAX_LOGMSG_LENGTH, where we can accommodate the
  338. * tAniNlHdr + [context][timestamp] + log
  339. * If log length is over MAX_LOGMSG_LENGTH,
  340. * the overflow part will be discarded.
  341. */
  342. length = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - tlen - 2;
  343. /*
  344. * QDF_ASSERT if complete log was not accommodated into
  345. * the available buffer.
  346. */
  347. QDF_ASSERT(0);
  348. }
  349. memcpy(&ptr[*pfilled_length], tbuf, tlen);
  350. memcpy(&ptr[*pfilled_length + tlen], to_be_sent, length);
  351. *pfilled_length += tlen + length;
  352. ptr[*pfilled_length] = '\n';
  353. *pfilled_length += 1;
  354. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  355. /* Wakeup logger thread */
  356. if ((true == wake_up_thread)) {
  357. set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  358. wake_up_interruptible(&gwlan_logging.wait_queue);
  359. }
  360. if (gwlan_logging.log_to_console
  361. && ALLOWED_LOG_LEVELS_TO_CONSOLE(log_level)) {
  362. print_to_console(tbuf, to_be_sent);
  363. }
  364. return 0;
  365. }
  366. /**
  367. * pkt_stats_fill_headers() - This function adds headers to skb
  368. * @skb: skb to which headers need to be added
  369. *
  370. * Return: 0 on success or Errno on failure
  371. */
  372. static int pkt_stats_fill_headers(struct sk_buff *skb)
  373. {
  374. struct host_log_pktlog_info cds_pktlog;
  375. int cds_pkt_size = sizeof(struct host_log_pktlog_info);
  376. tAniNlHdr msg_header;
  377. int extra_header_len, nl_payload_len;
  378. static int nlmsg_seq;
  379. int diag_type;
  380. qdf_mem_zero(&cds_pktlog, cds_pkt_size);
  381. cds_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C;
  382. cds_pktlog.buf_len = skb->len;
  383. cds_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++;
  384. #ifdef CONFIG_MCL
  385. host_diag_log_set_code(&cds_pktlog, LOG_WLAN_PKT_LOG_INFO_C);
  386. host_diag_log_set_length(&cds_pktlog.log_hdr, skb->len +
  387. cds_pkt_size);
  388. #endif
  389. if (unlikely(skb_headroom(skb) < cds_pkt_size)) {
  390. pr_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
  391. __LINE__, skb->head, skb->data, sizeof(msg_header));
  392. return -EIO;
  393. }
  394. qdf_mem_copy(skb_push(skb, cds_pkt_size),
  395. &cds_pktlog, cds_pkt_size);
  396. if (unlikely(skb_headroom(skb) < sizeof(int))) {
  397. pr_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
  398. __LINE__, skb->head, skb->data, sizeof(int));
  399. return -EIO;
  400. }
  401. diag_type = DIAG_TYPE_LOGS;
  402. qdf_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int));
  403. extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) +
  404. sizeof(struct nlmsghdr);
  405. nl_payload_len = extra_header_len + skb->len;
  406. msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC;
  407. msg_header.nlh.nlmsg_len = nl_payload_len;
  408. msg_header.nlh.nlmsg_flags = NLM_F_REQUEST;
  409. msg_header.nlh.nlmsg_pid = 0;
  410. msg_header.nlh.nlmsg_seq = nlmsg_seq++;
  411. msg_header.radio = 0;
  412. msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE;
  413. msg_header.wmsg.length = cpu_to_be16(skb->len);
  414. if (unlikely(skb_headroom(skb) < sizeof(msg_header))) {
  415. pr_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
  416. __LINE__, skb->head, skb->data, sizeof(msg_header));
  417. return -EIO;
  418. }
  419. qdf_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header,
  420. sizeof(msg_header));
  421. return 0;
  422. }
  423. /**
  424. * nl_srv_bcast_diag() - Wrapper to send bcast msgs to diag events mcast grp
  425. * @skb: sk buffer pointer
  426. *
  427. * Sends the bcast message to diag events multicast group with generic nl socket
  428. * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
  429. *
  430. * Return: zero on success, error code otherwise
  431. */
  432. static int nl_srv_bcast_diag(struct sk_buff *skb)
  433. {
  434. #ifdef CNSS_GENL
  435. return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
  436. #else
  437. return nl_srv_bcast(skb);
  438. #endif
  439. }
  440. /**
  441. * nl_srv_bcast_host_logs() - Wrapper to send bcast msgs to host logs mcast grp
  442. * @skb: sk buffer pointer
  443. *
  444. * Sends the bcast message to host logs multicast group with generic nl socket
  445. * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
  446. *
  447. * Return: zero on success, error code otherwise
  448. */
  449. static int nl_srv_bcast_host_logs(struct sk_buff *skb)
  450. {
  451. #ifdef CNSS_GENL
  452. return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
  453. #else
  454. return nl_srv_bcast(skb);
  455. #endif
  456. }
  457. /**
  458. * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per
  459. * packet statistics to the user
  460. *
  461. * This function is used to send the per packet statistics to the user
  462. *
  463. * Return: Success if the message is posted to user
  464. */
  465. int pktlog_send_per_pkt_stats_to_user(void)
  466. {
  467. int ret = -1;
  468. struct pkt_stats_msg *pstats_msg;
  469. unsigned long flags;
  470. struct sk_buff *skb_new = NULL;
  471. static int rate_limit;
  472. bool free_old_skb = false;
  473. while (!list_empty(&gwlan_logging.pkt_stat_filled_list)
  474. && !gwlan_logging.exit) {
  475. skb_new = dev_alloc_skb(MAX_SKBMSG_LENGTH);
  476. if (skb_new == NULL) {
  477. if (!rate_limit) {
  478. pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
  479. __func__, MAX_SKBMSG_LENGTH,
  480. gwlan_logging.drop_count);
  481. }
  482. rate_limit = 1;
  483. ret = -ENOMEM;
  484. break;
  485. }
  486. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  487. pstats_msg = (struct pkt_stats_msg *)
  488. (gwlan_logging.pkt_stat_filled_list.next);
  489. list_del_init(gwlan_logging.pkt_stat_filled_list.next);
  490. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  491. ret = pkt_stats_fill_headers(pstats_msg->skb);
  492. if (ret < 0) {
  493. pr_err("%s failed to fill headers %d\n", __func__, ret);
  494. free_old_skb = true;
  495. goto err;
  496. }
  497. ret = nl_srv_bcast_diag(pstats_msg->skb);
  498. if (ret < 0) {
  499. pr_info("%s: Send Failed %d drop_count = %u\n",
  500. __func__, ret,
  501. ++gwlan_logging.pkt_stat_drop_cnt);
  502. } else {
  503. ret = 0;
  504. }
  505. err:
  506. /*
  507. * Free old skb in case or error before assigning new skb
  508. * to the free list.
  509. */
  510. if (free_old_skb)
  511. dev_kfree_skb(pstats_msg->skb);
  512. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  513. pstats_msg->skb = skb_new;
  514. list_add_tail(&pstats_msg->node,
  515. &gwlan_logging.pkt_stat_free_list);
  516. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  517. ret = 0;
  518. }
  519. return ret;
  520. }
  521. static int send_filled_buffers_to_user(void)
  522. {
  523. int ret = -1;
  524. struct log_msg *plog_msg;
  525. int payload_len;
  526. int tot_msg_len;
  527. tAniNlHdr *wnl;
  528. struct sk_buff *skb = NULL;
  529. struct nlmsghdr *nlh;
  530. static int nlmsg_seq;
  531. unsigned long flags;
  532. static int rate_limit;
  533. while (!list_empty(&gwlan_logging.filled_list)
  534. && !gwlan_logging.exit) {
  535. skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
  536. if (skb == NULL) {
  537. if (!rate_limit) {
  538. pr_err
  539. ("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
  540. __func__, MAX_LOGMSG_LENGTH,
  541. gwlan_logging.drop_count);
  542. }
  543. rate_limit = 1;
  544. ret = -ENOMEM;
  545. break;
  546. }
  547. rate_limit = 0;
  548. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  549. plog_msg = (struct log_msg *)
  550. (gwlan_logging.filled_list.next);
  551. list_del_init(gwlan_logging.filled_list.next);
  552. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  553. /* 4 extra bytes for the radio idx */
  554. payload_len = plog_msg->filled_length +
  555. sizeof(wnl->radio) + sizeof(tAniHdr);
  556. tot_msg_len = NLMSG_SPACE(payload_len);
  557. nlh = nlmsg_put(skb, 0, nlmsg_seq++,
  558. ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST);
  559. if (NULL == nlh) {
  560. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  561. list_add_tail(&plog_msg->node,
  562. &gwlan_logging.free_list);
  563. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  564. pr_err("%s: drop_count = %u\n", __func__,
  565. ++gwlan_logging.drop_count);
  566. pr_err("%s: nlmsg_put() failed for msg size[%d]\n",
  567. __func__, tot_msg_len);
  568. dev_kfree_skb(skb);
  569. skb = NULL;
  570. ret = -EINVAL;
  571. continue;
  572. }
  573. wnl = (tAniNlHdr *) nlh;
  574. wnl->radio = plog_msg->radio;
  575. memcpy(&wnl->wmsg, plog_msg->logbuf,
  576. plog_msg->filled_length + sizeof(tAniHdr));
  577. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  578. list_add_tail(&plog_msg->node, &gwlan_logging.free_list);
  579. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  580. ret = nl_srv_bcast_host_logs(skb);
  581. /* print every 64th drop count */
  582. if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) {
  583. pr_err("%s: Send Failed %d drop_count = %u\n",
  584. __func__, ret, ++gwlan_logging.drop_count);
  585. }
  586. }
  587. return ret;
  588. }
  589. #ifdef FEATURE_WLAN_DIAG_SUPPORT
  590. /**
  591. * wlan_report_log_completion() - Report bug report completion to userspace
  592. * @is_fatal: Type of event, fatal or not
  593. * @indicator: Source of bug report, framework/host/firmware
  594. * @reason_code: Reason for triggering bug report
  595. * @ring_id: Ring id of logging entities
  596. *
  597. * This function is used to report the bug report completion to userspace
  598. *
  599. * Return: None
  600. */
  601. void wlan_report_log_completion(uint32_t is_fatal,
  602. uint32_t indicator,
  603. uint32_t reason_code,
  604. uint8_t ring_id)
  605. {
  606. WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
  607. struct host_event_wlan_log_complete);
  608. wlan_diag_event.is_fatal = is_fatal;
  609. wlan_diag_event.indicator = indicator;
  610. wlan_diag_event.reason_code = reason_code;
  611. wlan_diag_event.reserved = ring_id;
  612. WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE);
  613. }
  614. #endif
  615. #ifdef CONFIG_MCL
  616. /**
  617. * send_flush_completion_to_user() - Indicate flush completion to the user
  618. * @ring_id: Ring id of logging entities
  619. *
  620. * This function is used to send the flush completion message to user space
  621. *
  622. * Return: None
  623. */
  624. static void send_flush_completion_to_user(uint8_t ring_id)
  625. {
  626. uint32_t is_fatal, indicator, reason_code;
  627. bool recovery_needed;
  628. cds_get_and_reset_log_completion(&is_fatal,
  629. &indicator, &reason_code, &recovery_needed);
  630. /* Error on purpose, so that it will get logged in the kmsg */
  631. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  632. "%s: Sending flush done to userspace", __func__);
  633. wlan_report_log_completion(is_fatal, indicator, reason_code, ring_id);
  634. if (recovery_needed)
  635. cds_trigger_recovery(QDF_REASON_UNSPECIFIED);
  636. }
  637. #endif
  638. /**
  639. * wlan_logging_thread() - The WLAN Logger thread
  640. * @Arg - pointer to the HDD context
  641. *
  642. * This thread logs log message to App registered for the logs.
  643. */
  644. static int wlan_logging_thread(void *Arg)
  645. {
  646. int ret_wait_status = 0;
  647. int ret = 0;
  648. unsigned long flags;
  649. while (!gwlan_logging.exit) {
  650. ret_wait_status =
  651. wait_event_interruptible(gwlan_logging.wait_queue,
  652. (!list_empty
  653. (&gwlan_logging.filled_list)
  654. || test_bit(
  655. HOST_LOG_DRIVER_MSG,
  656. &gwlan_logging.eventFlag)
  657. || test_bit(
  658. HOST_LOG_PER_PKT_STATS,
  659. &gwlan_logging.eventFlag)
  660. || test_bit(
  661. HOST_LOG_FW_FLUSH_COMPLETE,
  662. &gwlan_logging.eventFlag)
  663. || gwlan_logging.exit));
  664. if (ret_wait_status == -ERESTARTSYS) {
  665. pr_err
  666. ("%s: wait_event_interruptible returned -ERESTARTSYS",
  667. __func__);
  668. break;
  669. }
  670. if (gwlan_logging.exit)
  671. break;
  672. if (test_and_clear_bit(HOST_LOG_DRIVER_MSG,
  673. &gwlan_logging.eventFlag)) {
  674. ret = send_filled_buffers_to_user();
  675. if (-ENOMEM == ret)
  676. msleep(200);
  677. #ifdef CONFIG_MCL
  678. if (WLAN_LOG_INDICATOR_HOST_ONLY ==
  679. cds_get_log_indicator()) {
  680. send_flush_completion_to_user(
  681. RING_ID_DRIVER_DEBUG);
  682. }
  683. #endif
  684. }
  685. if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS,
  686. &gwlan_logging.eventFlag)) {
  687. ret = pktlog_send_per_pkt_stats_to_user();
  688. if (-ENOMEM == ret)
  689. msleep(200);
  690. }
  691. if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE,
  692. &gwlan_logging.eventFlag)) {
  693. /* Flush bit could have been set while we were mid
  694. * way in the logging thread. So, need to check other
  695. * buffers like log messages, per packet stats again
  696. * to flush any residual data in them
  697. */
  698. if (gwlan_logging.is_flush_complete == true) {
  699. gwlan_logging.is_flush_complete = false;
  700. #ifdef CONFIG_MCL
  701. send_flush_completion_to_user(
  702. RING_ID_DRIVER_DEBUG);
  703. #endif
  704. } else {
  705. gwlan_logging.is_flush_complete = true;
  706. /* Flush all current host logs*/
  707. spin_lock_irqsave(&gwlan_logging.spin_lock,
  708. flags);
  709. wlan_queue_logmsg_for_app();
  710. spin_unlock_irqrestore(&gwlan_logging.spin_lock,
  711. flags);
  712. set_bit(HOST_LOG_DRIVER_MSG,
  713. &gwlan_logging.eventFlag);
  714. set_bit(HOST_LOG_PER_PKT_STATS,
  715. &gwlan_logging.eventFlag);
  716. set_bit(HOST_LOG_FW_FLUSH_COMPLETE,
  717. &gwlan_logging.eventFlag);
  718. wake_up_interruptible(
  719. &gwlan_logging.wait_queue);
  720. }
  721. }
  722. }
  723. complete_and_exit(&gwlan_logging.shutdown_comp, 0);
  724. return 0;
  725. }
  726. void wlan_logging_set_active(bool active)
  727. {
  728. gwlan_logging.is_active = active;
  729. }
  730. void wlan_logging_set_log_to_console(bool log_to_console)
  731. {
  732. gwlan_logging.log_to_console = log_to_console;
  733. }
  734. int wlan_logging_sock_init_svc(void)
  735. {
  736. int i = 0, j, pkt_stats_size;
  737. unsigned long irq_flag;
  738. spin_lock_init(&gwlan_logging.spin_lock);
  739. spin_lock_init(&gwlan_logging.pkt_stats_lock);
  740. gwlan_logging.log_to_console = true;
  741. gwlan_logging.num_buf = MAX_LOGMSG_COUNT;
  742. gwlan_logging.buffer_length = MAX_LOGMSG_LENGTH;
  743. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  744. INIT_LIST_HEAD(&gwlan_logging.free_list);
  745. INIT_LIST_HEAD(&gwlan_logging.filled_list);
  746. for (i = 0; i < gwlan_logging.num_buf; i++) {
  747. list_add(&gplog_msg[i].node, &gwlan_logging.free_list);
  748. gplog_msg[i].index = i;
  749. }
  750. gwlan_logging.pcur_node = (struct log_msg *)
  751. (gwlan_logging.free_list.next);
  752. list_del_init(gwlan_logging.free_list.next);
  753. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  754. /* Initialize the pktStats data structure here */
  755. pkt_stats_size = sizeof(struct pkt_stats_msg);
  756. gpkt_stats_buffers = vmalloc(MAX_PKTSTATS_BUFF * pkt_stats_size);
  757. if (!gpkt_stats_buffers) {
  758. pr_err("%s: Could not allocate memory for Pkt stats\n",
  759. __func__);
  760. goto err1;
  761. }
  762. qdf_mem_zero(gpkt_stats_buffers,
  763. MAX_PKTSTATS_BUFF * pkt_stats_size);
  764. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  765. gwlan_logging.pkt_stats_msg_idx = 0;
  766. INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list);
  767. INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list);
  768. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  769. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  770. gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH);
  771. if (gpkt_stats_buffers[i].skb == NULL) {
  772. pr_err("%s: Memory alloc failed for skb", __func__);
  773. /* free previously allocated skb and return */
  774. for (j = 0; j < i ; j++)
  775. dev_kfree_skb(gpkt_stats_buffers[j].skb);
  776. goto err2;
  777. }
  778. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  779. list_add(&gpkt_stats_buffers[i].node,
  780. &gwlan_logging.pkt_stat_free_list);
  781. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  782. }
  783. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  784. gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *)
  785. (gwlan_logging.pkt_stat_free_list.next);
  786. list_del_init(gwlan_logging.pkt_stat_free_list.next);
  787. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  788. /* Pkt Stats intialization done */
  789. init_waitqueue_head(&gwlan_logging.wait_queue);
  790. gwlan_logging.exit = false;
  791. clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  792. clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  793. clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  794. init_completion(&gwlan_logging.shutdown_comp);
  795. gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
  796. "wlan_logging_thread");
  797. if (IS_ERR(gwlan_logging.thread)) {
  798. pr_err("%s: Could not Create LogMsg Thread Controller",
  799. __func__);
  800. goto err3;
  801. }
  802. wake_up_process(gwlan_logging.thread);
  803. gwlan_logging.is_active = true;
  804. gwlan_logging.is_flush_complete = false;
  805. return 0;
  806. err3:
  807. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  808. if (gpkt_stats_buffers[i].skb)
  809. dev_kfree_skb(gpkt_stats_buffers[i].skb);
  810. }
  811. err2:
  812. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  813. gwlan_logging.pkt_stats_pcur_node = NULL;
  814. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  815. vfree(gpkt_stats_buffers);
  816. gpkt_stats_buffers = NULL;
  817. err1:
  818. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  819. gwlan_logging.pcur_node = NULL;
  820. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  821. return -ENOMEM;
  822. }
  823. int wlan_logging_sock_deinit_svc(void)
  824. {
  825. unsigned long irq_flag;
  826. int i;
  827. if (!gwlan_logging.pcur_node)
  828. return 0;
  829. #ifdef CONFIG_MCL
  830. INIT_COMPLETION(gwlan_logging.shutdown_comp);
  831. #endif
  832. gwlan_logging.exit = true;
  833. gwlan_logging.is_active = false;
  834. #ifdef CONFIG_MCL
  835. cds_set_multicast_logging(0);
  836. #endif
  837. gwlan_logging.is_flush_complete = false;
  838. clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  839. clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  840. clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  841. wake_up_interruptible(&gwlan_logging.wait_queue);
  842. wait_for_completion(&gwlan_logging.shutdown_comp);
  843. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  844. gwlan_logging.pcur_node = NULL;
  845. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  846. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  847. gwlan_logging.pkt_stats_pcur_node = NULL;
  848. gwlan_logging.pkt_stats_msg_idx = 0;
  849. gwlan_logging.pkt_stat_drop_cnt = 0;
  850. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  851. if (gpkt_stats_buffers[i].skb)
  852. dev_kfree_skb(gpkt_stats_buffers[i].skb);
  853. }
  854. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  855. vfree(gpkt_stats_buffers);
  856. gpkt_stats_buffers = NULL;
  857. return 0;
  858. }
  859. /**
  860. * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging
  861. *
  862. * This function is used to send signal to the logger thread for logging per
  863. * packet stats
  864. *
  865. * Return: None
  866. *
  867. */
  868. void wlan_logging_set_per_pkt_stats(void)
  869. {
  870. if (gwlan_logging.is_active == false)
  871. return;
  872. set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  873. wake_up_interruptible(&gwlan_logging.wait_queue);
  874. }
  875. /*
  876. * wlan_logging_set_fw_flush_complete() - FW log flush completion
  877. *
  878. * This function is used to send signal to the logger thread to indicate
  879. * that the flushing of FW logs is complete by the FW
  880. *
  881. * Return: None
  882. *
  883. */
  884. void wlan_logging_set_fw_flush_complete(void)
  885. {
  886. if (gwlan_logging.is_active == false
  887. #ifdef CONFIG_MCL
  888. || !cds_is_fatal_event_enabled()
  889. #endif
  890. )
  891. return;
  892. set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  893. wake_up_interruptible(&gwlan_logging.wait_queue);
  894. }
  895. /**
  896. * wlan_flush_host_logs_for_fatal() - Flush host logs
  897. *
  898. * This function is used to send signal to the logger thread to
  899. * Flush the host logs
  900. *
  901. * Return: None
  902. */
  903. void wlan_flush_host_logs_for_fatal(void)
  904. {
  905. unsigned long flags;
  906. #ifdef CONFIG_MCL
  907. if (cds_is_log_report_in_progress()) {
  908. #endif
  909. pr_info("%s:flush all host logs Setting HOST_LOG_POST_MASK\n",
  910. __func__);
  911. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  912. wlan_queue_logmsg_for_app();
  913. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  914. set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  915. wake_up_interruptible(&gwlan_logging.wait_queue);
  916. #ifdef CONFIG_MCL
  917. }
  918. #endif
  919. }
  920. /**
  921. * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats
  922. *
  923. * This function is used to get the free node for pkt stats from
  924. * free list/filles list
  925. *
  926. * Return: int
  927. *
  928. */
  929. static int wlan_get_pkt_stats_free_node(void)
  930. {
  931. int ret = 0;
  932. list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node,
  933. &gwlan_logging.pkt_stat_filled_list);
  934. if (!list_empty(&gwlan_logging.pkt_stat_free_list)) {
  935. /* Get buffer from free list */
  936. gwlan_logging.pkt_stats_pcur_node =
  937. (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next);
  938. list_del_init(gwlan_logging.pkt_stat_free_list.next);
  939. } else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) {
  940. /* Get buffer from filled list. This condition will drop the
  941. * packet from being indicated to app
  942. */
  943. gwlan_logging.pkt_stats_pcur_node =
  944. (struct pkt_stats_msg *)
  945. (gwlan_logging.pkt_stat_filled_list.next);
  946. ++gwlan_logging.pkt_stat_drop_cnt;
  947. /* print every 64th drop count */
  948. if (
  949. #ifdef CONFIG_MCL
  950. cds_is_multicast_logging() &&
  951. #endif
  952. (!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) {
  953. pr_err("%s: drop_count = %u\n",
  954. __func__, gwlan_logging.pkt_stat_drop_cnt);
  955. }
  956. list_del_init(gwlan_logging.pkt_stat_filled_list.next);
  957. ret = 1;
  958. }
  959. /* Reset the skb values, essential if dequeued from filled list */
  960. skb_trim(gwlan_logging.pkt_stats_pcur_node->skb, 0);
  961. return ret;
  962. }
  963. /**
  964. * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB
  965. * @pl_hdr: Pointer to pl_hdr
  966. * @pkt_dump: Pointer to pkt_dump
  967. * @data: Pointer to data
  968. *
  969. * This function adds the pktstats hdr and data to current
  970. * skb node of free list.
  971. *
  972. * Return: None
  973. */
  974. void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
  975. {
  976. #ifdef CONFIG_MCL
  977. struct ath_pktlog_hdr *pktlog_hdr;
  978. struct packet_dump *pkt_stats_dump;
  979. int total_stats_len = 0;
  980. bool wake_up_thread = false;
  981. unsigned long flags;
  982. struct sk_buff *ptr;
  983. int hdr_size;
  984. pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr;
  985. if (pktlog_hdr == NULL) {
  986. pr_err("%s : Invalid pkt_stats_header\n", __func__);
  987. return;
  988. }
  989. pkt_stats_dump = (struct packet_dump *)pkt_dump;
  990. total_stats_len = sizeof(struct ath_pktlog_hdr) +
  991. pktlog_hdr->size;
  992. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  993. if (!gwlan_logging.pkt_stats_pcur_node || (NULL == pkt_stats_dump)) {
  994. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  995. return;
  996. }
  997. /* Check if we can accommodate more log into current node/buffer */
  998. hdr_size = sizeof(struct host_log_pktlog_info) +
  999. sizeof(tAniNlHdr);
  1000. if ((total_stats_len + hdr_size) >=
  1001. skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) {
  1002. wake_up_thread = true;
  1003. wlan_get_pkt_stats_free_node();
  1004. }
  1005. ptr = gwlan_logging.pkt_stats_pcur_node->skb;
  1006. qdf_mem_copy(skb_put(ptr,
  1007. sizeof(struct ath_pktlog_hdr)),
  1008. pktlog_hdr,
  1009. sizeof(struct ath_pktlog_hdr));
  1010. if (pkt_stats_dump) {
  1011. qdf_mem_copy(skb_put(ptr,
  1012. sizeof(struct packet_dump)),
  1013. pkt_stats_dump,
  1014. sizeof(struct packet_dump));
  1015. pktlog_hdr->size -= sizeof(struct packet_dump);
  1016. }
  1017. if (data)
  1018. qdf_mem_copy(skb_put(ptr,
  1019. pktlog_hdr->size),
  1020. data, pktlog_hdr->size);
  1021. if (pkt_stats_dump->type == STOP_MONITOR) {
  1022. wake_up_thread = true;
  1023. wlan_get_pkt_stats_free_node();
  1024. }
  1025. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  1026. /* Wakeup logger thread */
  1027. if (true == wake_up_thread) {
  1028. set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  1029. wake_up_interruptible(&gwlan_logging.wait_queue);
  1030. }
  1031. #endif
  1032. }
  1033. #ifdef CONFIG_MCL
  1034. /**
  1035. * driver_hal_status_map() - maps driver to hal
  1036. * status
  1037. * @status: status to be mapped
  1038. *
  1039. * This function is used to map driver to hal status
  1040. *
  1041. * Return: None
  1042. *
  1043. */
  1044. static void driver_hal_status_map(uint8_t *status)
  1045. {
  1046. switch (*status) {
  1047. case tx_status_ok:
  1048. *status = TX_PKT_FATE_ACKED;
  1049. break;
  1050. case tx_status_discard:
  1051. *status = TX_PKT_FATE_DRV_DROP_OTHER;
  1052. break;
  1053. case tx_status_no_ack:
  1054. *status = TX_PKT_FATE_SENT;
  1055. break;
  1056. case tx_status_download_fail:
  1057. *status = TX_PKT_FATE_FW_QUEUED;
  1058. break;
  1059. default:
  1060. *status = TX_PKT_FATE_DRV_DROP_OTHER;
  1061. break;
  1062. }
  1063. }
  1064. /*
  1065. * send_packetdump() - send packet dump
  1066. * @netbuf: netbuf
  1067. * @status: status of tx packet
  1068. * @vdev_id: virtual device id
  1069. * @type: type of packet
  1070. *
  1071. * This function is used to send packet dump to HAL layer
  1072. * using wlan_pkt_stats_to_logger_thread
  1073. *
  1074. * Return: None
  1075. *
  1076. */
  1077. static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status,
  1078. uint8_t vdev_id, uint8_t type)
  1079. {
  1080. struct ath_pktlog_hdr pktlog_hdr = {0};
  1081. struct packet_dump pd_hdr = {0};
  1082. struct hdd_context *hdd_ctx;
  1083. struct hdd_adapter *adapter;
  1084. hdd_ctx = (struct hdd_context *)cds_get_context(QDF_MODULE_ID_HDD);
  1085. if (!hdd_ctx)
  1086. return;
  1087. adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
  1088. if (!adapter)
  1089. return;
  1090. /* Send packet dump only for STA interface */
  1091. if (adapter->device_mode != QDF_STA_MODE)
  1092. return;
  1093. #if defined(HELIUMPLUS)
  1094. pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
  1095. #endif
  1096. pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
  1097. pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len;
  1098. pd_hdr.status = status;
  1099. pd_hdr.type = type;
  1100. pd_hdr.driver_ts = qdf_get_monotonic_boottime();
  1101. if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT))
  1102. gtx_count++;
  1103. else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT))
  1104. grx_count++;
  1105. wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data);
  1106. }
  1107. /*
  1108. * send_packetdump_monitor() - sends start/stop packet dump indication
  1109. * @type: type of packet
  1110. *
  1111. * This function is used to indicate HAL layer to start/stop monitoring
  1112. * of packets
  1113. *
  1114. * Return: None
  1115. *
  1116. */
  1117. static void send_packetdump_monitor(uint8_t type)
  1118. {
  1119. struct ath_pktlog_hdr pktlog_hdr = {0};
  1120. struct packet_dump pd_hdr = {0};
  1121. #if defined(HELIUMPLUS)
  1122. pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
  1123. #endif
  1124. pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
  1125. pktlog_hdr.size = sizeof(pd_hdr);
  1126. pd_hdr.type = type;
  1127. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1128. "fate Tx-Rx %s: type: %d", __func__, type);
  1129. wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL);
  1130. }
  1131. /**
  1132. * wlan_deregister_txrx_packetdump() - tx/rx packet dump
  1133. * deregistration
  1134. *
  1135. * This function is used to deregister tx/rx packet dump callbacks
  1136. * with ol, pe and htt layers
  1137. *
  1138. * Return: None
  1139. *
  1140. */
  1141. void wlan_deregister_txrx_packetdump(void)
  1142. {
  1143. if (gtx_count || grx_count) {
  1144. ol_deregister_packetdump_callback();
  1145. wma_deregister_packetdump_callback();
  1146. send_packetdump_monitor(STOP_MONITOR);
  1147. csr_packetdump_timer_stop();
  1148. gtx_count = 0;
  1149. grx_count = 0;
  1150. } else
  1151. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1152. "%s: deregistered packetdump already", __func__);
  1153. }
  1154. /*
  1155. * check_txrx_packetdump_count() - function to check
  1156. * tx/rx packet dump global counts
  1157. *
  1158. * This function is used to check global counts of tx/rx
  1159. * packet dump functionality.
  1160. *
  1161. * Return: 1 if either gtx_count or grx_count reached 32
  1162. * 0 otherwise
  1163. *
  1164. */
  1165. static bool check_txrx_packetdump_count(void)
  1166. {
  1167. if (gtx_count == MAX_NUM_PKT_LOG ||
  1168. grx_count == MAX_NUM_PKT_LOG) {
  1169. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1170. "%s gtx_count: %d grx_count: %d deregister packetdump",
  1171. __func__, gtx_count, grx_count);
  1172. wlan_deregister_txrx_packetdump();
  1173. return 1;
  1174. }
  1175. return 0;
  1176. }
  1177. /*
  1178. * tx_packetdump_cb() - tx packet dump callback
  1179. * @netbuf: netbuf
  1180. * @status: status of tx packet
  1181. * @vdev_id: virtual device id
  1182. * @type: packet type
  1183. *
  1184. * This function is used to send tx packet dump to HAL layer
  1185. * and deregister packet dump callbacks
  1186. *
  1187. * Return: None
  1188. *
  1189. */
  1190. static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
  1191. uint8_t vdev_id, uint8_t type)
  1192. {
  1193. bool temp;
  1194. temp = check_txrx_packetdump_count();
  1195. if (temp)
  1196. return;
  1197. driver_hal_status_map(&status);
  1198. send_packetdump(netbuf, status, vdev_id, type);
  1199. }
  1200. /*
  1201. * rx_packetdump_cb() - rx packet dump callback
  1202. * @netbuf: netbuf
  1203. * @status: status of rx packet
  1204. * @vdev_id: virtual device id
  1205. * @type: packet type
  1206. *
  1207. * This function is used to send rx packet dump to HAL layer
  1208. * and deregister packet dump callbacks
  1209. *
  1210. * Return: None
  1211. *
  1212. */
  1213. static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status,
  1214. uint8_t vdev_id, uint8_t type)
  1215. {
  1216. bool temp;
  1217. temp = check_txrx_packetdump_count();
  1218. if (temp)
  1219. return;
  1220. send_packetdump(netbuf, status, vdev_id, type);
  1221. }
  1222. /**
  1223. * wlan_register_txrx_packetdump() - tx/rx packet dump
  1224. * registration
  1225. *
  1226. * This function is used to register tx/rx packet dump callbacks
  1227. * with ol, pe and htt layers
  1228. *
  1229. * Return: None
  1230. *
  1231. */
  1232. void wlan_register_txrx_packetdump(void)
  1233. {
  1234. ol_register_packetdump_callback(tx_packetdump_cb,
  1235. rx_packetdump_cb);
  1236. wma_register_packetdump_callback(tx_packetdump_cb,
  1237. rx_packetdump_cb);
  1238. send_packetdump_monitor(START_MONITOR);
  1239. gtx_count = 0;
  1240. grx_count = 0;
  1241. }
  1242. #endif
  1243. #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */