wlan_logging_sock_svc.c 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769
  1. /*
  2. * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for
  6. * any purpose with or without fee is hereby granted, provided that the
  7. * above copyright notice and this permission notice appear in all
  8. * copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  11. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  12. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  13. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  14. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  15. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  17. * PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. /******************************************************************************
  20. * wlan_logging_sock_svc.c
  21. *
  22. ******************************************************************************/
  23. #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
  24. #include <linux/vmalloc.h>
  25. #include <wlan_logging_sock_svc.h>
  26. #include <linux/kthread.h>
  27. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0))
  28. #include <linux/panic_notifier.h>
  29. #endif
  30. #include <qdf_time.h>
  31. #include <qdf_trace.h>
  32. #include <qdf_mc_timer.h>
  33. #include <qdf_timer.h>
  34. #include <qdf_lock.h>
  35. #include <wlan_ptt_sock_svc.h>
  36. #include <host_diag_core_event.h>
  37. #include "host_diag_core_log.h"
  38. #include <qdf_event.h>
  39. #include <qdf_module.h>
  40. #include <qdf_str.h>
  41. #ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
  42. #include <wlan_connectivity_logging.h>
  43. #endif
  44. #ifdef CNSS_GENL
  45. #ifdef CONFIG_CNSS_OUT_OF_TREE
  46. #include "cnss_nl.h"
  47. #else
  48. #include <net/cnss_nl.h>
  49. #endif
  50. #endif
  51. #if defined(FEATURE_FW_LOG_PARSING) || defined(FEATURE_WLAN_DIAG_SUPPORT) || \
  52. defined(CONNECTIVITY_PKTLOG)
  53. #include <cds_api.h>
  54. #include "ani_global.h"
  55. #endif
  56. #ifdef CONNECTIVITY_PKTLOG
  57. #include "wma.h"
  58. #include "pktlog_ac.h"
  59. #include <cdp_txrx_misc.h>
  60. #endif
  61. #define MAX_NUM_PKT_LOG 32
  62. #define LOGGING_TRACE(level, args ...) \
  63. QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args)
  64. /* Global variables */
  65. #define ANI_NL_MSG_LOG_TYPE 89
  66. #define ANI_NL_MSG_READY_IND_TYPE 90
  67. #ifndef MAX_LOGMSG_COUNT
  68. #define MAX_LOGMSG_COUNT 256
  69. #endif
  70. #define MAX_LOGMSG_LENGTH 2048
  71. #define MAX_SKBMSG_LENGTH 4096
  72. #define WLAN_LOG_BUFFER_SIZE 2048
  73. #ifdef CONNECTIVITY_PKTLOG
  74. /**
  75. * Buffer to accommodate -
  76. * pktlog buffer (2048 bytes)
  77. * ath_pktlog_hdr (16 bytes)
  78. * pkt_dump (8 bytes)
  79. * extra padding (40 bytes)
  80. *
  81. * Note: pktlog buffer size is dependent on RX_BUFFER_SIZE and
  82. * HTT_T2H_MAX_MSG_SIZE. Adjust WLAN_LOG_BUFFER_SIZE
  83. * based on the above mentioned macros.
  84. */
  85. #define ATH_PKTLOG_HDR_SIZE (sizeof(struct ath_pktlog_hdr))
  86. #define PKT_DUMP_HDR_SIZE (sizeof(struct packet_dump))
  87. #define EXTRA_PADDING 40
  88. #define MAX_PKTSTATS_LENGTH \
  89. ((WLAN_LOG_BUFFER_SIZE) + (ATH_PKTLOG_HDR_SIZE) + \
  90. (PKT_DUMP_HDR_SIZE) + (EXTRA_PADDING))
  91. #else
  92. #define MAX_PKTSTATS_LENGTH WLAN_LOG_BUFFER_SIZE
  93. #endif /* CONNECTIVITY_PKTLOG */
  94. #define MAX_PKTSTATS_BUFF 16
  95. #define HOST_LOG_DRIVER_MSG 0x001
  96. #define HOST_LOG_PER_PKT_STATS 0x002
  97. #define HOST_LOG_FW_FLUSH_COMPLETE 0x003
  98. #define HOST_LOG_DRIVER_CONNECTIVITY_MSG 0x004
  99. #define DIAG_TYPE_LOGS 1
  100. #define PTT_MSG_DIAG_CMDS_TYPE 0x5050
  101. #define MAX_LOG_LINE 500
  102. /* default rate limit period - 2sec */
  103. #define PANIC_WIFILOG_PRINT_RATE_LIMIT_PERIOD (2*HZ)
  104. /* default burst for rate limit */
  105. #define PANIC_WIFILOG_PRINT_RATE_LIMIT_BURST_DEFAULT 500
  106. DEFINE_RATELIMIT_STATE(panic_wifilog_ratelimit,
  107. PANIC_WIFILOG_PRINT_RATE_LIMIT_PERIOD,
  108. PANIC_WIFILOG_PRINT_RATE_LIMIT_BURST_DEFAULT);
  109. #define FLUSH_LOG_COMPLETION_TIMEOUT 3000
  110. struct log_msg {
  111. struct list_head node;
  112. unsigned int radio;
  113. unsigned int index;
  114. /* indicates the current filled log length in logbuf */
  115. unsigned int filled_length;
  116. /*
  117. * Buf to hold the log msg
  118. * tAniHdr + log
  119. */
  120. char logbuf[MAX_LOGMSG_LENGTH];
  121. };
  122. /**
  123. * struct packet_dump - This data structure contains the
  124. * Tx/Rx packet stats
  125. * @status: Status
  126. * @type: Type
  127. * @driver_ts: driver timestamp
  128. * @fw_ts: fw timestamp
  129. */
  130. struct packet_dump {
  131. unsigned char status;
  132. unsigned char type;
  133. uint32_t driver_ts;
  134. uint16_t fw_ts;
  135. } __attribute__((__packed__));
  136. /**
  137. * struct pkt_stats_msg - This data structure contains the
  138. * pkt stats node for link list
  139. * @node: LinkList node
  140. * @node: Pointer to skb
  141. */
  142. struct pkt_stats_msg {
  143. struct list_head node;
  144. struct sk_buff *skb;
  145. };
  146. #define MAX_FLUSH_TIMER_PERIOD_VALUE 3600000 /* maximum of 1 hour (in ms) */
  147. struct wlan_logging {
  148. /* Console log levels */
  149. uint32_t console_log_levels;
  150. /* Number of buffers to be used for logging */
  151. uint32_t num_buf;
  152. uint32_t buffer_length;
  153. /* Lock to synchronize access to shared logging resource */
  154. spinlock_t spin_lock;
  155. /* Holds the free node which can be used for filling logs */
  156. struct list_head free_list;
  157. /* Holds the filled nodes which needs to be indicated to APP */
  158. struct list_head filled_list;
  159. /* Holds nodes for console printing in case of kernel panic */
  160. struct list_head panic_list;
  161. /* Wait queue for Logger thread */
  162. wait_queue_head_t wait_queue;
  163. /* Logger thread */
  164. struct task_struct *thread;
  165. /* Logging thread sets this variable on exit */
  166. struct completion shutdown_comp;
  167. /* Indicates to logger thread to exit */
  168. bool exit;
  169. /* Holds number of dropped logs */
  170. unsigned int drop_count;
  171. /* current logbuf to which the log will be filled to */
  172. struct log_msg *pcur_node;
  173. /* Event flag used for wakeup and post indication*/
  174. unsigned long eventFlag;
  175. /* Indicates logger thread is activated */
  176. bool is_active;
  177. /* Flush completion check */
  178. bool is_flush_complete;
  179. /* paramaters for pkt stats */
  180. struct list_head pkt_stat_free_list;
  181. struct list_head pkt_stat_filled_list;
  182. struct pkt_stats_msg *pkt_stats_pcur_node;
  183. unsigned int pkt_stat_drop_cnt;
  184. spinlock_t pkt_stats_lock;
  185. unsigned int pkt_stats_msg_idx;
  186. qdf_timer_t flush_timer;
  187. bool is_flush_timer_initialized;
  188. uint32_t flush_timer_period;
  189. qdf_spinlock_t flush_timer_lock;
  190. qdf_event_t flush_log_completion;
  191. };
  192. /* This global variable is intentionally not marked static because it
  193. * is used by offline tools. Please do not use it outside this file.
  194. */
  195. struct wlan_logging gwlan_logging;
  196. static struct pkt_stats_msg *gpkt_stats_buffers;
  197. #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
  198. static struct log_msg *gplog_msg;
  199. static inline QDF_STATUS allocate_log_msg_buffer(void)
  200. {
  201. gplog_msg = qdf_mem_valloc(MAX_LOGMSG_COUNT * sizeof(*gplog_msg));
  202. return gplog_msg ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
  203. }
  204. static inline void free_log_msg_buffer(void)
  205. {
  206. qdf_mem_vfree(gplog_msg);
  207. gplog_msg = NULL;
  208. }
  209. #else
  210. static struct log_msg gplog_msg[MAX_LOGMSG_COUNT];
  211. static inline QDF_STATUS allocate_log_msg_buffer(void)
  212. {
  213. qdf_minidump_log(gplog_msg, sizeof(gplog_msg), "wlan_logs");
  214. return QDF_STATUS_SUCCESS;
  215. }
  216. static inline void free_log_msg_buffer(void)
  217. {
  218. qdf_minidump_remove(gplog_msg, sizeof(gplog_msg), "wlan_logs");
  219. }
  220. #endif
  221. /* Need to call this with spin_lock acquired */
  222. static int wlan_queue_logmsg_for_app(void)
  223. {
  224. char *ptr;
  225. int ret = 0;
  226. ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
  227. ptr[gwlan_logging.pcur_node->filled_length] = '\0';
  228. *(unsigned short *)(gwlan_logging.pcur_node->logbuf) =
  229. ANI_NL_MSG_LOG_TYPE;
  230. *(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) =
  231. gwlan_logging.pcur_node->filled_length;
  232. list_add_tail(&gwlan_logging.pcur_node->node,
  233. &gwlan_logging.filled_list);
  234. if (!list_empty(&gwlan_logging.free_list)) {
  235. /* Get buffer from free list */
  236. gwlan_logging.pcur_node =
  237. (struct log_msg *)(gwlan_logging.free_list.next);
  238. list_del_init(gwlan_logging.free_list.next);
  239. } else if (!list_empty(&gwlan_logging.filled_list)) {
  240. /* Get buffer from filled list */
  241. /* This condition will drop the packet from being
  242. * indicated to app
  243. */
  244. gwlan_logging.pcur_node =
  245. (struct log_msg *)(gwlan_logging.filled_list.next);
  246. ++gwlan_logging.drop_count;
  247. list_del_init(gwlan_logging.filled_list.next);
  248. ret = 1;
  249. }
  250. /* Reset the current node values */
  251. gwlan_logging.pcur_node->filled_length = 0;
  252. return ret;
  253. }
  254. static const char *current_process_name(void)
  255. {
  256. if (in_irq())
  257. return "irq";
  258. if (in_softirq())
  259. return "soft_irq";
  260. return current->comm;
  261. }
  262. /**
  263. * wlan_add_user_log_time_stamp() - populate firmware and kernel timestamps
  264. * @tbuf: Pointer to time stamp buffer
  265. * @tbuf_sz: Time buffer size
  266. * @ts: Time stamp value
  267. *
  268. * For adrastea time stamp is QTIMER raw tick which will be used by cnss_diag
  269. * to convert it into user visible time stamp. In adrstea FW also uses QTIMER
  270. * raw ticks which is needed to synchronize host and fw log time stamps
  271. *
  272. * Also add logcat timestamp so that driver logs and
  273. * logcat logs can be co-related
  274. *
  275. * For discrete solution e.g rome use system tick and convert it into
  276. * seconds.milli seconds
  277. *
  278. * Return: number of characters written in target buffer not including
  279. * trailing '/0'
  280. */
  281. static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts)
  282. {
  283. char time_buf[20];
  284. qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf));
  285. return scnprintf(tbuf, tbuf_sz, "[%.6s][0x%llx]%s",
  286. current_process_name(), (unsigned long long)ts,
  287. time_buf);
  288. }
  289. #ifdef WLAN_MAX_LOGS_PER_SEC
  290. static inline void wlan_panic_on_excessive_logging(void)
  291. {
  292. if (qdf_detected_excessive_logging())
  293. QDF_DEBUG_PANIC("Exceeded %d logs per second",
  294. WLAN_MAX_LOGS_PER_SEC);
  295. }
  296. #else
  297. static inline void wlan_panic_on_excessive_logging(void) {}
  298. #endif /* WLAN_MAX_LOGS_PER_SEC */
  299. #ifdef QDF_TRACE_PRINT_ENABLE
  300. static inline void
  301. log_to_console(QDF_TRACE_LEVEL level, const char *timestamp, const char *msg)
  302. {
  303. if (qdf_detected_excessive_logging()) {
  304. qdf_rl_print_supressed_inc();
  305. return;
  306. }
  307. qdf_rl_print_supressed_log();
  308. pr_err("%s %s\n", timestamp, msg);
  309. }
  310. #else
  311. static inline void
  312. log_to_console(QDF_TRACE_LEVEL level, const char *timestamp, const char *msg)
  313. {
  314. switch (level) {
  315. case QDF_TRACE_LEVEL_FATAL:
  316. pr_alert("%s %s\n", timestamp, msg);
  317. wlan_panic_on_excessive_logging();
  318. break;
  319. case QDF_TRACE_LEVEL_ERROR:
  320. pr_err("%s %s\n", timestamp, msg);
  321. wlan_panic_on_excessive_logging();
  322. break;
  323. case QDF_TRACE_LEVEL_WARN:
  324. pr_warn("%s %s\n", timestamp, msg);
  325. wlan_panic_on_excessive_logging();
  326. break;
  327. case QDF_TRACE_LEVEL_INFO:
  328. pr_info("%s %s\n", timestamp, msg);
  329. wlan_panic_on_excessive_logging();
  330. break;
  331. case QDF_TRACE_LEVEL_INFO_HIGH:
  332. case QDF_TRACE_LEVEL_INFO_MED:
  333. case QDF_TRACE_LEVEL_INFO_LOW:
  334. case QDF_TRACE_LEVEL_DEBUG:
  335. default:
  336. /* these levels should not be logged to console */
  337. break;
  338. }
  339. }
  340. #endif
  341. int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length)
  342. {
  343. char *ptr;
  344. char tbuf[60];
  345. int tlen;
  346. int total_log_len;
  347. unsigned int *pfilled_length;
  348. bool wake_up_thread = false;
  349. unsigned long flags;
  350. uint64_t ts;
  351. /* Add the current time stamp */
  352. ts = qdf_get_log_timestamp();
  353. tlen = wlan_add_user_log_time_stamp(tbuf, sizeof(tbuf), ts);
  354. /* if logging isn't up yet, just dump to dmesg */
  355. if (!gwlan_logging.is_active) {
  356. log_to_console(log_level, tbuf, to_be_sent);
  357. return 0;
  358. }
  359. /* 1+1 indicate '\n'+'\0' */
  360. total_log_len = length + tlen + 1 + 1;
  361. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  362. /* wlan logging svc resources are not yet initialized */
  363. if (!gwlan_logging.pcur_node) {
  364. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  365. return -EIO;
  366. }
  367. pfilled_length = &gwlan_logging.pcur_node->filled_length;
  368. /* Check if we can accommodate more log into current node/buffer */
  369. if ((MAX_LOGMSG_LENGTH - (*pfilled_length +
  370. sizeof(tAniNlHdr))) < total_log_len) {
  371. wake_up_thread = true;
  372. wlan_queue_logmsg_for_app();
  373. pfilled_length = &gwlan_logging.pcur_node->filled_length;
  374. }
  375. ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)];
  376. if (unlikely(MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len))) {
  377. /*
  378. * Assumption here is that we receive logs which is less than
  379. * MAX_LOGMSG_LENGTH, where we can accommodate the
  380. * tAniNlHdr + [context][timestamp] + log
  381. * If log length is over MAX_LOGMSG_LENGTH,
  382. * the overflow part will be discarded.
  383. */
  384. length = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - tlen - 2;
  385. /*
  386. * QDF_ASSERT if complete log was not accommodated into
  387. * the available buffer.
  388. */
  389. QDF_ASSERT(0);
  390. }
  391. memcpy(&ptr[*pfilled_length], tbuf, tlen);
  392. memcpy(&ptr[*pfilled_length + tlen], to_be_sent, length);
  393. *pfilled_length += tlen + length;
  394. ptr[*pfilled_length] = '\n';
  395. *pfilled_length += 1;
  396. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  397. /* Wakeup logger thread */
  398. if (wake_up_thread) {
  399. set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  400. wake_up_interruptible(&gwlan_logging.wait_queue);
  401. }
  402. if (gwlan_logging.console_log_levels & BIT(log_level))
  403. log_to_console(log_level, tbuf, to_be_sent);
  404. return 0;
  405. }
  406. /**
  407. * nl_srv_bcast_host_logs() - Wrapper to send bcast msgs to host logs mcast grp
  408. * @skb: sk buffer pointer
  409. *
  410. * Sends the bcast message to host logs multicast group with generic nl socket
  411. * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
  412. *
  413. * Return: zero on success, error code otherwise
  414. */
  415. #ifdef CNSS_GENL
  416. static int nl_srv_bcast_host_logs(struct sk_buff *skb)
  417. {
  418. return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
  419. }
  420. #else
  421. static int nl_srv_bcast_host_logs(struct sk_buff *skb)
  422. {
  423. return nl_srv_bcast(skb);
  424. }
  425. #endif
  426. #ifdef CONNECTIVITY_PKTLOG
  427. /**
  428. * pkt_stats_fill_headers() - This function adds headers to skb
  429. * @skb: skb to which headers need to be added
  430. *
  431. * Return: 0 on success or Errno on failure
  432. */
  433. static int pkt_stats_fill_headers(struct sk_buff *skb)
  434. {
  435. struct host_log_pktlog_info cds_pktlog;
  436. int cds_pkt_size = sizeof(struct host_log_pktlog_info);
  437. tAniNlHdr msg_header;
  438. int extra_header_len, nl_payload_len;
  439. static int nlmsg_seq;
  440. int diag_type;
  441. qdf_mem_zero(&cds_pktlog, cds_pkt_size);
  442. cds_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C;
  443. cds_pktlog.buf_len = skb->len;
  444. cds_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++;
  445. host_diag_log_set_code(&cds_pktlog, LOG_WLAN_PKT_LOG_INFO_C);
  446. host_diag_log_set_length(&cds_pktlog.log_hdr, skb->len +
  447. cds_pkt_size);
  448. if (unlikely(skb_headroom(skb) < cds_pkt_size)) {
  449. qdf_nofl_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
  450. __LINE__, skb->head, skb->data,
  451. sizeof(msg_header));
  452. return -EIO;
  453. }
  454. qdf_mem_copy(skb_push(skb, cds_pkt_size),
  455. &cds_pktlog, cds_pkt_size);
  456. if (unlikely(skb_headroom(skb) < sizeof(int))) {
  457. qdf_nofl_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
  458. __LINE__, skb->head, skb->data,
  459. sizeof(int));
  460. return -EIO;
  461. }
  462. diag_type = DIAG_TYPE_LOGS;
  463. qdf_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int));
  464. extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) +
  465. sizeof(struct nlmsghdr);
  466. nl_payload_len = extra_header_len + skb->len;
  467. msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC;
  468. msg_header.nlh.nlmsg_len = nl_payload_len;
  469. msg_header.nlh.nlmsg_flags = NLM_F_REQUEST;
  470. msg_header.nlh.nlmsg_pid = 0;
  471. msg_header.nlh.nlmsg_seq = nlmsg_seq++;
  472. msg_header.radio = 0;
  473. msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE;
  474. msg_header.wmsg.length = cpu_to_be16(skb->len);
  475. if (unlikely(skb_headroom(skb) < sizeof(msg_header))) {
  476. qdf_nofl_err("VPKT [%d]: Insufficient headroom, head[%pK], data[%pK], req[%zu]",
  477. __LINE__, skb->head, skb->data,
  478. sizeof(msg_header));
  479. return -EIO;
  480. }
  481. qdf_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header,
  482. sizeof(msg_header));
  483. return 0;
  484. }
  485. /**
  486. * nl_srv_bcast_diag() - Wrapper to send bcast msgs to diag events mcast grp
  487. * @skb: sk buffer pointer
  488. *
  489. * Sends the bcast message to diag events multicast group with generic nl socket
  490. * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
  491. *
  492. * Return: zero on success, error code otherwise
  493. */
  494. static int nl_srv_bcast_diag(struct sk_buff *skb)
  495. {
  496. #ifdef CNSS_GENL
  497. return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
  498. #else
  499. return nl_srv_bcast(skb);
  500. #endif
  501. }
  502. /**
  503. * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per
  504. * packet statistics to the user
  505. *
  506. * This function is used to send the per packet statistics to the user
  507. *
  508. * Return: Success if the message is posted to user
  509. */
  510. static int pktlog_send_per_pkt_stats_to_user(void)
  511. {
  512. int ret = -1;
  513. struct pkt_stats_msg *pstats_msg;
  514. unsigned long flags;
  515. struct sk_buff *skb_new = NULL;
  516. static int rate_limit;
  517. bool free_old_skb = false;
  518. while (!list_empty(&gwlan_logging.pkt_stat_filled_list)
  519. && !gwlan_logging.exit) {
  520. skb_new = dev_alloc_skb(MAX_SKBMSG_LENGTH);
  521. if (!skb_new) {
  522. if (!rate_limit) {
  523. qdf_err("dev_alloc_skb() failed for msg size[%d] drop count = %u",
  524. MAX_SKBMSG_LENGTH,
  525. gwlan_logging.drop_count);
  526. }
  527. rate_limit = 1;
  528. ret = -ENOMEM;
  529. break;
  530. }
  531. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  532. pstats_msg = (struct pkt_stats_msg *)
  533. (gwlan_logging.pkt_stat_filled_list.next);
  534. list_del_init(gwlan_logging.pkt_stat_filled_list.next);
  535. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  536. ret = pkt_stats_fill_headers(pstats_msg->skb);
  537. if (ret < 0) {
  538. qdf_err("Failed to fill headers %d", ret);
  539. free_old_skb = true;
  540. goto err;
  541. }
  542. ret = nl_srv_bcast_diag(pstats_msg->skb);
  543. if (ret < 0) {
  544. qdf_info("Send Failed %d drop_count = %u", ret,
  545. ++gwlan_logging.pkt_stat_drop_cnt);
  546. } else {
  547. ret = 0;
  548. }
  549. err:
  550. /*
  551. * Free old skb in case or error before assigning new skb
  552. * to the free list.
  553. */
  554. if (free_old_skb)
  555. dev_kfree_skb(pstats_msg->skb);
  556. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  557. pstats_msg->skb = skb_new;
  558. list_add_tail(&pstats_msg->node,
  559. &gwlan_logging.pkt_stat_free_list);
  560. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  561. ret = 0;
  562. }
  563. return ret;
  564. }
  565. #else
  566. static inline
  567. int pktlog_send_per_pkt_stats_to_user(void)
  568. {
  569. return 0;
  570. }
  571. #endif
  572. static int send_filled_buffers_to_user(void)
  573. {
  574. int ret = -1;
  575. struct log_msg *plog_msg;
  576. int payload_len;
  577. int tot_msg_len;
  578. tAniNlHdr *wnl;
  579. struct sk_buff *skb = NULL;
  580. struct nlmsghdr *nlh;
  581. static int nlmsg_seq;
  582. unsigned long flags;
  583. static int rate_limit;
  584. while (!list_empty(&gwlan_logging.filled_list)
  585. && !gwlan_logging.exit) {
  586. skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
  587. if (!skb) {
  588. if (!rate_limit) {
  589. qdf_err("dev_alloc_skb() failed for msg size[%d] drop count = %u",
  590. MAX_LOGMSG_LENGTH,
  591. gwlan_logging.drop_count);
  592. }
  593. rate_limit = 1;
  594. ret = -ENOMEM;
  595. break;
  596. }
  597. rate_limit = 0;
  598. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  599. plog_msg = (struct log_msg *)
  600. (gwlan_logging.filled_list.next);
  601. list_del_init(gwlan_logging.filled_list.next);
  602. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  603. /* 4 extra bytes for the radio idx */
  604. payload_len = plog_msg->filled_length +
  605. sizeof(wnl->radio) + sizeof(tAniHdr);
  606. tot_msg_len = NLMSG_SPACE(payload_len);
  607. nlh = nlmsg_put(skb, 0, nlmsg_seq++,
  608. ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST);
  609. if (!nlh) {
  610. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  611. list_add_tail(&plog_msg->node,
  612. &gwlan_logging.free_list);
  613. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  614. qdf_err("drop_count = %u", ++gwlan_logging.drop_count);
  615. qdf_err("nlmsg_put() failed for msg size[%d]",
  616. tot_msg_len);
  617. dev_kfree_skb(skb);
  618. skb = NULL;
  619. ret = -EINVAL;
  620. continue;
  621. }
  622. wnl = (tAniNlHdr *) nlh;
  623. wnl->radio = plog_msg->radio;
  624. memcpy(&wnl->wmsg, plog_msg->logbuf,
  625. plog_msg->filled_length + sizeof(tAniHdr));
  626. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  627. list_add_tail(&plog_msg->node, &gwlan_logging.free_list);
  628. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  629. ret = nl_srv_bcast_host_logs(skb);
  630. /* print every 64th drop count */
  631. if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) {
  632. qdf_err("Send Failed %d drop_count = %u",
  633. ret, ++gwlan_logging.drop_count);
  634. }
  635. }
  636. return ret;
  637. }
  638. #ifdef FEATURE_WLAN_DIAG_SUPPORT
  639. /**
  640. * wlan_report_log_completion() - Report bug report completion to userspace
  641. * @is_fatal: Type of event, fatal or not
  642. * @indicator: Source of bug report, framework/host/firmware
  643. * @reason_code: Reason for triggering bug report
  644. * @ring_id: Ring id of logging entities
  645. *
  646. * This function is used to report the bug report completion to userspace
  647. *
  648. * Return: None
  649. */
  650. void wlan_report_log_completion(uint32_t is_fatal,
  651. uint32_t indicator,
  652. uint32_t reason_code,
  653. uint8_t ring_id)
  654. {
  655. WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event,
  656. struct host_event_wlan_log_complete);
  657. wlan_diag_event.is_fatal = is_fatal;
  658. wlan_diag_event.indicator = indicator;
  659. wlan_diag_event.reason_code = reason_code;
  660. wlan_diag_event.reserved = ring_id;
  661. WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE);
  662. }
  663. #endif
  664. #ifdef FEATURE_WLAN_DIAG_SUPPORT
  665. /**
  666. * send_flush_completion_to_user() - Indicate flush completion to the user
  667. * @ring_id: Ring id of logging entities
  668. *
  669. * This function is used to send the flush completion message to user space
  670. *
  671. * Return: None
  672. */
  673. static void send_flush_completion_to_user(uint8_t ring_id)
  674. {
  675. uint32_t is_fatal, indicator, reason_code;
  676. bool recovery_needed;
  677. cds_get_and_reset_log_completion(&is_fatal,
  678. &indicator, &reason_code, &recovery_needed);
  679. /* Error on purpose, so that it will get logged in the kmsg */
  680. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  681. "%s: Sending flush done to userspace reason code %d",
  682. __func__, reason_code);
  683. wlan_report_log_completion(is_fatal, indicator, reason_code, ring_id);
  684. if (recovery_needed)
  685. cds_trigger_recovery(QDF_REASON_UNSPECIFIED);
  686. }
  687. #endif
  688. static void wlan_logging_set_flush_log_completion(void)
  689. {
  690. qdf_event_set(&gwlan_logging.flush_log_completion);
  691. }
  692. QDF_STATUS wlan_logging_wait_for_flush_log_completion(void)
  693. {
  694. qdf_event_reset(&gwlan_logging.flush_log_completion);
  695. return qdf_wait_for_event_completion(
  696. &gwlan_logging.flush_log_completion,
  697. FLUSH_LOG_COMPLETION_TIMEOUT);
  698. }
  699. static void setup_flush_timer(void)
  700. {
  701. qdf_spin_lock(&gwlan_logging.flush_timer_lock);
  702. if (!gwlan_logging.is_flush_timer_initialized ||
  703. (gwlan_logging.flush_timer_period == 0)) {
  704. qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
  705. return;
  706. }
  707. qdf_timer_mod(&gwlan_logging.flush_timer,
  708. gwlan_logging.flush_timer_period);
  709. qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
  710. }
  711. #ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
  712. static QDF_STATUS
  713. wlan_logging_send_connectivity_event(void)
  714. {
  715. return wlan_connectivity_log_dequeue();
  716. }
  717. #else
  718. static inline QDF_STATUS
  719. wlan_logging_send_connectivity_event(void)
  720. {
  721. return QDF_STATUS_E_NOSUPPORT;
  722. }
  723. #endif
  724. /**
  725. * wlan_logging_thread() - The WLAN Logger thread
  726. * @Arg - pointer to the HDD context
  727. *
  728. * This thread logs log message to App registered for the logs.
  729. */
  730. static int wlan_logging_thread(void *Arg)
  731. {
  732. int ret_wait_status = 0;
  733. int ret = 0;
  734. unsigned long flags;
  735. while (!gwlan_logging.exit) {
  736. setup_flush_timer();
  737. ret_wait_status =
  738. wait_event_interruptible(gwlan_logging.wait_queue,
  739. (!list_empty
  740. (&gwlan_logging.filled_list)
  741. || test_bit(
  742. HOST_LOG_DRIVER_MSG,
  743. &gwlan_logging.eventFlag)
  744. || test_bit(
  745. HOST_LOG_PER_PKT_STATS,
  746. &gwlan_logging.eventFlag)
  747. || test_bit(
  748. HOST_LOG_FW_FLUSH_COMPLETE,
  749. &gwlan_logging.eventFlag)
  750. || test_bit(
  751. HOST_LOG_DRIVER_CONNECTIVITY_MSG,
  752. &gwlan_logging.eventFlag)
  753. || gwlan_logging.exit));
  754. if (ret_wait_status == -ERESTARTSYS) {
  755. qdf_err("wait_event_interruptible returned -ERESTARTSYS");
  756. break;
  757. }
  758. if (gwlan_logging.exit)
  759. break;
  760. if (test_and_clear_bit(HOST_LOG_DRIVER_MSG,
  761. &gwlan_logging.eventFlag)) {
  762. ret = send_filled_buffers_to_user();
  763. if (-ENOMEM == ret)
  764. msleep(200);
  765. #ifdef FEATURE_WLAN_DIAG_SUPPORT
  766. if (WLAN_LOG_INDICATOR_HOST_ONLY ==
  767. cds_get_log_indicator()) {
  768. send_flush_completion_to_user(
  769. RING_ID_DRIVER_DEBUG);
  770. }
  771. #endif
  772. }
  773. if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS,
  774. &gwlan_logging.eventFlag)) {
  775. ret = pktlog_send_per_pkt_stats_to_user();
  776. if (-ENOMEM == ret)
  777. msleep(200);
  778. }
  779. if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE,
  780. &gwlan_logging.eventFlag)) {
  781. /* Flush bit could have been set while we were mid
  782. * way in the logging thread. So, need to check other
  783. * buffers like log messages, per packet stats again
  784. * to flush any residual data in them
  785. */
  786. if (gwlan_logging.is_flush_complete == true) {
  787. gwlan_logging.is_flush_complete = false;
  788. #ifdef FEATURE_WLAN_DIAG_SUPPORT
  789. send_flush_completion_to_user(
  790. RING_ID_DRIVER_DEBUG);
  791. #endif
  792. wlan_logging_set_flush_log_completion();
  793. } else {
  794. gwlan_logging.is_flush_complete = true;
  795. /* Flush all current host logs*/
  796. spin_lock_irqsave(&gwlan_logging.spin_lock,
  797. flags);
  798. wlan_queue_logmsg_for_app();
  799. spin_unlock_irqrestore(&gwlan_logging.spin_lock,
  800. flags);
  801. set_bit(HOST_LOG_DRIVER_MSG,
  802. &gwlan_logging.eventFlag);
  803. set_bit(HOST_LOG_PER_PKT_STATS,
  804. &gwlan_logging.eventFlag);
  805. set_bit(HOST_LOG_FW_FLUSH_COMPLETE,
  806. &gwlan_logging.eventFlag);
  807. wake_up_interruptible(
  808. &gwlan_logging.wait_queue);
  809. }
  810. }
  811. /* Dequeue the connectivity_log */
  812. wlan_logging_send_connectivity_event();
  813. clear_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG,
  814. &gwlan_logging.eventFlag);
  815. }
  816. complete_and_exit(&gwlan_logging.shutdown_comp, 0);
  817. return 0;
  818. }
  819. void wlan_logging_set_active(bool active)
  820. {
  821. gwlan_logging.is_active = active;
  822. }
  823. void wlan_set_console_log_levels(uint32_t console_log_levels)
  824. {
  825. gwlan_logging.console_log_levels = console_log_levels;
  826. }
  827. qdf_export_symbol(wlan_set_console_log_levels);
  828. static void flush_log_buffers_timer(void *dummy)
  829. {
  830. wlan_flush_host_logs_for_fatal();
  831. }
  832. int wlan_logging_set_flush_timer(uint32_t milliseconds)
  833. {
  834. if (milliseconds > MAX_FLUSH_TIMER_PERIOD_VALUE) {
  835. QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
  836. "ERROR! value should be (0 - %d)\n",
  837. MAX_FLUSH_TIMER_PERIOD_VALUE);
  838. return -EINVAL;
  839. }
  840. if (!gwlan_logging.is_active) {
  841. QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
  842. "WLAN-Logging not active");
  843. return -EINVAL;
  844. }
  845. qdf_spin_lock(&gwlan_logging.flush_timer_lock);
  846. if (!gwlan_logging.is_flush_timer_initialized) {
  847. qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
  848. return -EINVAL;
  849. }
  850. gwlan_logging.flush_timer_period = milliseconds;
  851. if (milliseconds) {
  852. qdf_timer_mod(&gwlan_logging.flush_timer,
  853. gwlan_logging.flush_timer_period);
  854. }
  855. qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
  856. return 0;
  857. }
  858. static int panic_wifilog_ratelimit_print(void)
  859. {
  860. return __ratelimit(&panic_wifilog_ratelimit);
  861. }
  862. /**
  863. * wlan_logging_dump_last_logs() - Panic notifier callback's helper function
  864. *
  865. * This function prints buffered logs one line at a time.
  866. */
  867. static void wlan_logging_dump_last_logs(void)
  868. {
  869. char *log;
  870. struct log_msg *plog_msg;
  871. char textbuf[MAX_LOG_LINE];
  872. unsigned int filled_length;
  873. unsigned int text_len;
  874. unsigned long flags;
  875. /* Iterate over panic list */
  876. pr_err("\n");
  877. while (!list_empty(&gwlan_logging.panic_list)) {
  878. plog_msg = (struct log_msg *)
  879. (gwlan_logging.panic_list.next);
  880. list_del_init(gwlan_logging.panic_list.next);
  881. log = &plog_msg->logbuf[sizeof(tAniHdr)];
  882. filled_length = plog_msg->filled_length;
  883. while (filled_length) {
  884. text_len = qdf_str_copy_all_before_char(log, filled_length,
  885. textbuf,
  886. sizeof(textbuf) - 1,
  887. '\n');
  888. textbuf[text_len] = '\0';
  889. if (panic_wifilog_ratelimit_print())
  890. pr_err("%s\n", textbuf);
  891. if (log[text_len] == '\n')
  892. text_len += 1; /* skip newline */
  893. log += text_len;
  894. filled_length -= text_len;
  895. }
  896. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  897. list_add_tail(&plog_msg->node,
  898. &gwlan_logging.free_list);
  899. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  900. }
  901. }
  902. /**
  903. * wlan_logging_panic_handler() - Panic notifier callback
  904. *
  905. * This function extracts log buffers in filled list and
  906. * current node.Sends them to helper function for printing.
  907. */
  908. static int wlan_logging_panic_handler(struct notifier_block *this,
  909. unsigned long event, void *ptr)
  910. {
  911. char *log;
  912. struct log_msg *plog_msg;
  913. unsigned long flags;
  914. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  915. /* Iterate over nodes queued for app */
  916. while (!list_empty(&gwlan_logging.filled_list)) {
  917. plog_msg = (struct log_msg *)
  918. (gwlan_logging.filled_list.next);
  919. list_del_init(gwlan_logging.filled_list.next);
  920. list_add_tail(&plog_msg->node,
  921. &gwlan_logging.panic_list);
  922. }
  923. /* Check current node */
  924. if (gwlan_logging.pcur_node &&
  925. gwlan_logging.pcur_node->filled_length) {
  926. plog_msg = gwlan_logging.pcur_node;
  927. log = &plog_msg->logbuf[sizeof(tAniHdr)];
  928. log[plog_msg->filled_length] = '\0';
  929. list_add_tail(&gwlan_logging.pcur_node->node,
  930. &gwlan_logging.panic_list);
  931. if (!list_empty(&gwlan_logging.free_list)) {
  932. gwlan_logging.pcur_node =
  933. (struct log_msg *)(gwlan_logging.free_list.next);
  934. list_del_init(gwlan_logging.free_list.next);
  935. gwlan_logging.pcur_node->filled_length = 0;
  936. } else
  937. gwlan_logging.pcur_node = NULL;
  938. }
  939. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  940. wlan_logging_dump_last_logs();
  941. return NOTIFY_DONE;
  942. }
  943. static struct notifier_block panic_nb = {
  944. .notifier_call = wlan_logging_panic_handler,
  945. };
  946. int wlan_logging_notifier_init(bool dump_at_kernel_enable)
  947. {
  948. int ret;
  949. if (gwlan_logging.is_active &&
  950. !dump_at_kernel_enable) {
  951. ret = atomic_notifier_chain_register(&panic_notifier_list,
  952. &panic_nb);
  953. if (ret) {
  954. QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
  955. "Failed to register panic notifier");
  956. return -EINVAL;
  957. }
  958. }
  959. return 0;
  960. }
  961. int wlan_logging_notifier_deinit(bool dump_at_kernel_enable)
  962. {
  963. if (gwlan_logging.is_active &&
  964. !dump_at_kernel_enable) {
  965. atomic_notifier_chain_unregister(&panic_notifier_list,
  966. &panic_nb);
  967. }
  968. return 0;
  969. }
  970. static void flush_timer_init(void)
  971. {
  972. qdf_spinlock_create(&gwlan_logging.flush_timer_lock);
  973. qdf_timer_init(NULL, &gwlan_logging.flush_timer,
  974. flush_log_buffers_timer, NULL,
  975. QDF_TIMER_TYPE_SW);
  976. gwlan_logging.is_flush_timer_initialized = true;
  977. gwlan_logging.flush_timer_period = 0;
  978. }
  979. static void flush_timer_deinit(void)
  980. {
  981. gwlan_logging.is_flush_timer_initialized = false;
  982. qdf_spin_lock(&gwlan_logging.flush_timer_lock);
  983. qdf_timer_stop(&gwlan_logging.flush_timer);
  984. qdf_timer_free(&gwlan_logging.flush_timer);
  985. qdf_spin_unlock(&gwlan_logging.flush_timer_lock);
  986. qdf_spinlock_destroy(&gwlan_logging.flush_timer_lock);
  987. }
  988. int wlan_logging_sock_init_svc(void)
  989. {
  990. int i = 0, j, pkt_stats_size;
  991. unsigned long irq_flag;
  992. QDF_STATUS status;
  993. spin_lock_init(&gwlan_logging.spin_lock);
  994. spin_lock_init(&gwlan_logging.pkt_stats_lock);
  995. gwlan_logging.console_log_levels = 0;
  996. gwlan_logging.num_buf = MAX_LOGMSG_COUNT;
  997. gwlan_logging.buffer_length = MAX_LOGMSG_LENGTH;
  998. if (allocate_log_msg_buffer() != QDF_STATUS_SUCCESS) {
  999. qdf_err("Could not allocate memory for log_msg");
  1000. return -ENOMEM;
  1001. }
  1002. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  1003. INIT_LIST_HEAD(&gwlan_logging.free_list);
  1004. INIT_LIST_HEAD(&gwlan_logging.filled_list);
  1005. INIT_LIST_HEAD(&gwlan_logging.panic_list);
  1006. for (i = 0; i < gwlan_logging.num_buf; i++) {
  1007. list_add(&gplog_msg[i].node, &gwlan_logging.free_list);
  1008. gplog_msg[i].index = i;
  1009. }
  1010. gwlan_logging.pcur_node = (struct log_msg *)
  1011. (gwlan_logging.free_list.next);
  1012. list_del_init(gwlan_logging.free_list.next);
  1013. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  1014. flush_timer_init();
  1015. /* Initialize the pktStats data structure here */
  1016. pkt_stats_size = sizeof(struct pkt_stats_msg);
  1017. gpkt_stats_buffers = qdf_mem_valloc(MAX_PKTSTATS_BUFF * pkt_stats_size);
  1018. if (!gpkt_stats_buffers) {
  1019. qdf_err("Could not allocate memory for Pkt stats");
  1020. goto err1;
  1021. }
  1022. qdf_mem_zero(gpkt_stats_buffers,
  1023. MAX_PKTSTATS_BUFF * pkt_stats_size);
  1024. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  1025. gwlan_logging.pkt_stats_msg_idx = 0;
  1026. INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list);
  1027. INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list);
  1028. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  1029. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  1030. gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH);
  1031. if (!gpkt_stats_buffers[i].skb) {
  1032. qdf_err("Memory alloc failed for skb");
  1033. /* free previously allocated skb and return */
  1034. for (j = 0; j < i ; j++)
  1035. dev_kfree_skb(gpkt_stats_buffers[j].skb);
  1036. goto err2;
  1037. }
  1038. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  1039. list_add(&gpkt_stats_buffers[i].node,
  1040. &gwlan_logging.pkt_stat_free_list);
  1041. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  1042. }
  1043. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  1044. gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *)
  1045. (gwlan_logging.pkt_stat_free_list.next);
  1046. list_del_init(gwlan_logging.pkt_stat_free_list.next);
  1047. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  1048. /* Pkt Stats intialization done */
  1049. init_waitqueue_head(&gwlan_logging.wait_queue);
  1050. gwlan_logging.exit = false;
  1051. clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  1052. clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  1053. clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  1054. clear_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG, &gwlan_logging.eventFlag);
  1055. init_completion(&gwlan_logging.shutdown_comp);
  1056. gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
  1057. "wlan_logging_thread");
  1058. if (IS_ERR(gwlan_logging.thread)) {
  1059. qdf_err("Could not Create LogMsg Thread Controller");
  1060. goto err3;
  1061. }
  1062. wake_up_process(gwlan_logging.thread);
  1063. gwlan_logging.is_active = true;
  1064. gwlan_logging.is_flush_complete = false;
  1065. status = qdf_event_create(&gwlan_logging.flush_log_completion);
  1066. if (!QDF_IS_STATUS_SUCCESS(status)) {
  1067. qdf_err("Flush log completion event init failed");
  1068. goto err3;
  1069. }
  1070. return 0;
  1071. err3:
  1072. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  1073. if (gpkt_stats_buffers[i].skb)
  1074. dev_kfree_skb(gpkt_stats_buffers[i].skb);
  1075. }
  1076. err2:
  1077. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  1078. gwlan_logging.pkt_stats_pcur_node = NULL;
  1079. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  1080. qdf_mem_vfree(gpkt_stats_buffers);
  1081. gpkt_stats_buffers = NULL;
  1082. err1:
  1083. flush_timer_deinit();
  1084. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  1085. gwlan_logging.pcur_node = NULL;
  1086. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  1087. free_log_msg_buffer();
  1088. return -ENOMEM;
  1089. }
  1090. int wlan_logging_sock_deinit_svc(void)
  1091. {
  1092. unsigned long irq_flag;
  1093. int i;
  1094. if (!gwlan_logging.pcur_node)
  1095. return 0;
  1096. qdf_event_destroy(&gwlan_logging.flush_log_completion);
  1097. INIT_COMPLETION(gwlan_logging.shutdown_comp);
  1098. gwlan_logging.exit = true;
  1099. gwlan_logging.is_active = false;
  1100. #if defined(FEATURE_FW_LOG_PARSING) || defined(FEATURE_WLAN_DIAG_SUPPORT)
  1101. cds_set_multicast_logging(0);
  1102. #endif
  1103. gwlan_logging.is_flush_complete = false;
  1104. clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  1105. clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  1106. clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  1107. clear_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG, &gwlan_logging.eventFlag);
  1108. wake_up_interruptible(&gwlan_logging.wait_queue);
  1109. wait_for_completion(&gwlan_logging.shutdown_comp);
  1110. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
  1111. gwlan_logging.pkt_stats_pcur_node = NULL;
  1112. gwlan_logging.pkt_stats_msg_idx = 0;
  1113. gwlan_logging.pkt_stat_drop_cnt = 0;
  1114. for (i = 0; i < MAX_PKTSTATS_BUFF; i++) {
  1115. if (gpkt_stats_buffers[i].skb)
  1116. dev_kfree_skb(gpkt_stats_buffers[i].skb);
  1117. }
  1118. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
  1119. qdf_mem_vfree(gpkt_stats_buffers);
  1120. gpkt_stats_buffers = NULL;
  1121. /* Delete the Flush timer then mark pcur_node NULL */
  1122. flush_timer_deinit();
  1123. spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
  1124. gwlan_logging.pcur_node = NULL;
  1125. spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
  1126. free_log_msg_buffer();
  1127. return 0;
  1128. }
  1129. /**
  1130. * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging
  1131. *
  1132. * This function is used to send signal to the logger thread for logging per
  1133. * packet stats
  1134. *
  1135. * Return: None
  1136. *
  1137. */
  1138. void wlan_logging_set_per_pkt_stats(void)
  1139. {
  1140. if (gwlan_logging.is_active == false)
  1141. return;
  1142. set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  1143. wake_up_interruptible(&gwlan_logging.wait_queue);
  1144. }
  1145. void wlan_logging_set_connectivity_log(void)
  1146. {
  1147. if (gwlan_logging.is_active == false)
  1148. return;
  1149. set_bit(HOST_LOG_DRIVER_CONNECTIVITY_MSG, &gwlan_logging.eventFlag);
  1150. wake_up_interruptible(&gwlan_logging.wait_queue);
  1151. }
  1152. /*
  1153. * wlan_logging_set_fw_flush_complete() - FW log flush completion
  1154. *
  1155. * This function is used to send signal to the logger thread to indicate
  1156. * that the flushing of FW logs is complete by the FW
  1157. *
  1158. * Return: None
  1159. *
  1160. */
  1161. void wlan_logging_set_fw_flush_complete(void)
  1162. {
  1163. if (!gwlan_logging.is_active)
  1164. return;
  1165. set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag);
  1166. wake_up_interruptible(&gwlan_logging.wait_queue);
  1167. }
  1168. /**
  1169. * wlan_flush_host_logs_for_fatal() - Flush host logs
  1170. *
  1171. * This function is used to send signal to the logger thread to
  1172. * Flush the host logs
  1173. *
  1174. * Return: None
  1175. */
  1176. void wlan_flush_host_logs_for_fatal(void)
  1177. {
  1178. unsigned long flags;
  1179. if (gwlan_logging.flush_timer_period == 0)
  1180. qdf_info("Flush all host logs Setting HOST_LOG_POST_MAS");
  1181. spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
  1182. wlan_queue_logmsg_for_app();
  1183. spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
  1184. set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag);
  1185. wake_up_interruptible(&gwlan_logging.wait_queue);
  1186. }
  1187. #ifdef CONNECTIVITY_PKTLOG
  1188. static uint8_t gtx_count;
  1189. static uint8_t grx_count;
  1190. /**
  1191. * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats
  1192. *
  1193. * This function is used to get the free node for pkt stats from
  1194. * free list/filles list
  1195. *
  1196. * Return: int
  1197. *
  1198. */
  1199. static int wlan_get_pkt_stats_free_node(void)
  1200. {
  1201. int ret = 0;
  1202. list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node,
  1203. &gwlan_logging.pkt_stat_filled_list);
  1204. if (!list_empty(&gwlan_logging.pkt_stat_free_list)) {
  1205. /* Get buffer from free list */
  1206. gwlan_logging.pkt_stats_pcur_node =
  1207. (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next);
  1208. list_del_init(gwlan_logging.pkt_stat_free_list.next);
  1209. } else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) {
  1210. /* Get buffer from filled list. This condition will drop the
  1211. * packet from being indicated to app
  1212. */
  1213. gwlan_logging.pkt_stats_pcur_node =
  1214. (struct pkt_stats_msg *)
  1215. (gwlan_logging.pkt_stat_filled_list.next);
  1216. ++gwlan_logging.pkt_stat_drop_cnt;
  1217. /* print every 64th drop count */
  1218. if (
  1219. cds_is_multicast_logging() &&
  1220. (!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) {
  1221. qdf_err("drop_count = %u",
  1222. gwlan_logging.pkt_stat_drop_cnt);
  1223. }
  1224. list_del_init(gwlan_logging.pkt_stat_filled_list.next);
  1225. ret = 1;
  1226. }
  1227. /* Reset the skb values, essential if dequeued from filled list */
  1228. skb_trim(gwlan_logging.pkt_stats_pcur_node->skb, 0);
  1229. return ret;
  1230. }
  1231. /**
  1232. * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB
  1233. * @pl_hdr: Pointer to pl_hdr
  1234. * @pkt_dump: Pointer to pkt_dump
  1235. * @data: Pointer to data
  1236. *
  1237. * This function adds the pktstats hdr and data to current
  1238. * skb node of free list.
  1239. *
  1240. * Return: None
  1241. */
  1242. void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data)
  1243. {
  1244. struct ath_pktlog_hdr *pktlog_hdr;
  1245. struct packet_dump *pkt_stats_dump;
  1246. int total_stats_len = 0;
  1247. bool wake_up_thread = false;
  1248. unsigned long flags;
  1249. struct sk_buff *ptr;
  1250. int hdr_size;
  1251. pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr;
  1252. if (!pktlog_hdr) {
  1253. qdf_err("Invalid pkt_stats_header");
  1254. return;
  1255. }
  1256. pkt_stats_dump = (struct packet_dump *)pkt_dump;
  1257. total_stats_len = sizeof(struct ath_pktlog_hdr) +
  1258. pktlog_hdr->size;
  1259. spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
  1260. if (!gwlan_logging.pkt_stats_pcur_node) {
  1261. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  1262. return;
  1263. }
  1264. /* Check if we can accommodate more log into current node/buffer */
  1265. hdr_size = sizeof(struct host_log_pktlog_info) +
  1266. sizeof(tAniNlHdr);
  1267. if ((total_stats_len + hdr_size) >=
  1268. skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) {
  1269. wake_up_thread = true;
  1270. wlan_get_pkt_stats_free_node();
  1271. }
  1272. ptr = gwlan_logging.pkt_stats_pcur_node->skb;
  1273. qdf_mem_copy(skb_put(ptr,
  1274. sizeof(struct ath_pktlog_hdr)),
  1275. pktlog_hdr,
  1276. sizeof(struct ath_pktlog_hdr));
  1277. if (pkt_stats_dump) {
  1278. qdf_mem_copy(skb_put(ptr,
  1279. sizeof(struct packet_dump)),
  1280. pkt_stats_dump,
  1281. sizeof(struct packet_dump));
  1282. pktlog_hdr->size -= sizeof(struct packet_dump);
  1283. }
  1284. if (data)
  1285. qdf_mem_copy(skb_put(ptr,
  1286. pktlog_hdr->size),
  1287. data, pktlog_hdr->size);
  1288. if (pkt_stats_dump && pkt_stats_dump->type == STOP_MONITOR) {
  1289. wake_up_thread = true;
  1290. wlan_get_pkt_stats_free_node();
  1291. }
  1292. spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
  1293. /* Wakeup logger thread */
  1294. if (true == wake_up_thread) {
  1295. set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag);
  1296. wake_up_interruptible(&gwlan_logging.wait_queue);
  1297. }
  1298. }
  1299. /**
  1300. * qdf_hal_tx_status_map() - map Tx completion status with
  1301. * packet dump Tx status
  1302. * @status: Tx completion status
  1303. *
  1304. * Return: packet dump tx_status enum
  1305. */
  1306. static inline enum tx_pkt_fate
  1307. qdf_hal_tx_status_map(enum qdf_dp_tx_rx_status status)
  1308. {
  1309. switch (status) {
  1310. case QDF_TX_RX_STATUS_OK:
  1311. return TX_PKT_FATE_ACKED;
  1312. case QDF_TX_RX_STATUS_FW_DISCARD:
  1313. return TX_PKT_FATE_FW_DROP_OTHER;
  1314. case QDF_TX_RX_STATUS_NO_ACK:
  1315. return TX_PKT_FATE_SENT;
  1316. case QDF_TX_RX_STATUS_DROP:
  1317. return TX_PKT_FATE_DRV_DROP_OTHER;
  1318. case QDF_TX_RX_STATUS_DOWNLOAD_SUCC:
  1319. return TX_PKT_FATE_DRV_QUEUED;
  1320. default:
  1321. return TX_PKT_FATE_DRV_DROP_OTHER;
  1322. }
  1323. }
  1324. /**
  1325. * qdf_hal_rx_status_map() - map Rx status with
  1326. * packet dump Rx status
  1327. * @status: Rx status
  1328. *
  1329. * Return: packet dump rx_status enum
  1330. */
  1331. static inline enum rx_pkt_fate
  1332. qdf_hal_rx_status_map(enum qdf_dp_tx_rx_status status)
  1333. {
  1334. switch (status) {
  1335. case QDF_TX_RX_STATUS_OK:
  1336. return RX_PKT_FATE_SUCCESS;
  1337. case QDF_TX_RX_STATUS_FW_DISCARD:
  1338. return RX_PKT_FATE_FW_DROP_OTHER;
  1339. case QDF_TX_RX_STATUS_DROP:
  1340. return RX_PKT_FATE_DRV_DROP_OTHER;
  1341. case QDF_TX_RX_STATUS_DOWNLOAD_SUCC:
  1342. return RX_PKT_FATE_DRV_QUEUED;
  1343. default:
  1344. return RX_PKT_FATE_DRV_DROP_OTHER;
  1345. }
  1346. }
  1347. /**
  1348. * qdf_hal_pkt_type_map() - map qdf packet type with
  1349. * packet dump packet type
  1350. * @type: packet type
  1351. *
  1352. * Return: Packet dump packet type
  1353. */
  1354. static inline enum pkt_type
  1355. qdf_hal_pkt_type_map(enum qdf_pkt_type type)
  1356. {
  1357. switch (type) {
  1358. case QDF_TX_MGMT_PKT:
  1359. return TX_MGMT_PKT;
  1360. case QDF_TX_DATA_PKT:
  1361. return TX_DATA_PKT;
  1362. case QDF_RX_MGMT_PKT:
  1363. return RX_MGMT_PKT;
  1364. case QDF_RX_DATA_PKT:
  1365. return RX_DATA_PKT;
  1366. default:
  1367. return INVALID_PKT;
  1368. }
  1369. }
  1370. /*
  1371. * send_packetdump() - send packet dump
  1372. * @soc: soc handle
  1373. * @vdev_id: ID of the virtual device handle
  1374. * @netbuf: netbuf
  1375. * @status: status of tx packet
  1376. * @type: type of packet
  1377. *
  1378. * This function is used to send packet dump to HAL layer
  1379. * using wlan_pkt_stats_to_logger_thread
  1380. *
  1381. * Return: None
  1382. *
  1383. */
  1384. static void send_packetdump(ol_txrx_soc_handle soc,
  1385. uint8_t vdev_id, qdf_nbuf_t netbuf,
  1386. uint8_t status, uint8_t type)
  1387. {
  1388. struct ath_pktlog_hdr pktlog_hdr = {0};
  1389. struct packet_dump pd_hdr = {0};
  1390. if (!netbuf) {
  1391. qdf_err("Invalid netbuf");
  1392. return;
  1393. }
  1394. /* Send packet dump only for STA interface */
  1395. if (wlan_op_mode_sta != cdp_get_opmode(soc, vdev_id))
  1396. return;
  1397. pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
  1398. pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
  1399. pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len;
  1400. pd_hdr.status = status;
  1401. pd_hdr.type = type;
  1402. pd_hdr.driver_ts = qdf_get_monotonic_boottime();
  1403. if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT))
  1404. gtx_count++;
  1405. else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT))
  1406. grx_count++;
  1407. wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data);
  1408. }
  1409. /*
  1410. * send_packetdump_monitor() - sends start/stop packet dump indication
  1411. * @type: type of packet
  1412. *
  1413. * This function is used to indicate HAL layer to start/stop monitoring
  1414. * of packets
  1415. *
  1416. * Return: None
  1417. *
  1418. */
  1419. static void send_packetdump_monitor(uint8_t type)
  1420. {
  1421. struct ath_pktlog_hdr pktlog_hdr = {0};
  1422. struct packet_dump pd_hdr = {0};
  1423. pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16;
  1424. pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP;
  1425. pktlog_hdr.size = sizeof(pd_hdr);
  1426. pd_hdr.type = type;
  1427. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1428. "fate Tx-Rx %s: type: %d", __func__, type);
  1429. wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL);
  1430. }
  1431. void wlan_deregister_txrx_packetdump(uint8_t pdev_id)
  1432. {
  1433. void *soc = cds_get_context(QDF_MODULE_ID_SOC);
  1434. if (!soc)
  1435. return;
  1436. if (gtx_count || grx_count) {
  1437. cdp_deregister_packetdump_cb(soc, pdev_id);
  1438. wma_deregister_packetdump_callback();
  1439. send_packetdump_monitor(STOP_MONITOR);
  1440. csr_packetdump_timer_stop();
  1441. gtx_count = 0;
  1442. grx_count = 0;
  1443. } else
  1444. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1445. "%s: deregistered packetdump already", __func__);
  1446. }
  1447. /*
  1448. * check_txrx_packetdump_count() - function to check
  1449. * tx/rx packet dump global counts
  1450. * @pdev_id: datapath pdev identifier
  1451. *
  1452. * This function is used to check global counts of tx/rx
  1453. * packet dump functionality.
  1454. *
  1455. * Return: 1 if either gtx_count or grx_count reached 32
  1456. * 0 otherwise
  1457. *
  1458. */
  1459. static bool check_txrx_packetdump_count(uint8_t pdev_id)
  1460. {
  1461. if (gtx_count == MAX_NUM_PKT_LOG ||
  1462. grx_count == MAX_NUM_PKT_LOG) {
  1463. LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG,
  1464. "%s gtx_count: %d grx_count: %d deregister packetdump",
  1465. __func__, gtx_count, grx_count);
  1466. wlan_deregister_txrx_packetdump(pdev_id);
  1467. return 1;
  1468. }
  1469. return 0;
  1470. }
  1471. /*
  1472. * tx_packetdump_cb() - tx packet dump callback
  1473. * @soc: soc handle
  1474. * @pdev_id: datapath pdev id
  1475. * @vdev_id: vdev id
  1476. * @netbuf: netbuf
  1477. * @status: status of tx packet
  1478. * @type: packet type
  1479. *
  1480. * This function is used to send tx packet dump to HAL layer
  1481. * and deregister packet dump callbacks
  1482. *
  1483. * Return: None
  1484. *
  1485. */
  1486. static void tx_packetdump_cb(ol_txrx_soc_handle soc,
  1487. uint8_t pdev_id, uint8_t vdev_id,
  1488. qdf_nbuf_t netbuf,
  1489. enum qdf_dp_tx_rx_status status,
  1490. enum qdf_pkt_type type)
  1491. {
  1492. bool temp;
  1493. enum tx_pkt_fate tx_status = qdf_hal_tx_status_map(status);
  1494. enum pkt_type pkt_type = qdf_hal_pkt_type_map(type);
  1495. if (!soc)
  1496. return;
  1497. temp = check_txrx_packetdump_count(pdev_id);
  1498. if (temp)
  1499. return;
  1500. send_packetdump(soc, vdev_id, netbuf, tx_status, pkt_type);
  1501. }
  1502. /*
  1503. * rx_packetdump_cb() - rx packet dump callback
  1504. * @soc: soc handle
  1505. * @pdev_id: datapath pdev id
  1506. * @vdev_id: vdev id
  1507. * @netbuf: netbuf
  1508. * @status: status of rx packet
  1509. * @type: packet type
  1510. *
  1511. * This function is used to send rx packet dump to HAL layer
  1512. * and deregister packet dump callbacks
  1513. *
  1514. * Return: None
  1515. *
  1516. */
  1517. static void rx_packetdump_cb(ol_txrx_soc_handle soc,
  1518. uint8_t pdev_id, uint8_t vdev_id,
  1519. qdf_nbuf_t netbuf,
  1520. enum qdf_dp_tx_rx_status status,
  1521. enum qdf_pkt_type type)
  1522. {
  1523. bool temp;
  1524. enum rx_pkt_fate rx_status = qdf_hal_rx_status_map(status);
  1525. enum pkt_type pkt_type = qdf_hal_pkt_type_map(type);
  1526. if (!soc)
  1527. return;
  1528. temp = check_txrx_packetdump_count(pdev_id);
  1529. if (temp)
  1530. return;
  1531. send_packetdump(soc, vdev_id, netbuf, rx_status, pkt_type);
  1532. }
  1533. void wlan_register_txrx_packetdump(uint8_t pdev_id)
  1534. {
  1535. void *soc = cds_get_context(QDF_MODULE_ID_SOC);
  1536. if (!soc)
  1537. return;
  1538. cdp_register_packetdump_cb(soc, pdev_id,
  1539. tx_packetdump_cb, rx_packetdump_cb);
  1540. wma_register_packetdump_callback(tx_packetdump_cb,
  1541. rx_packetdump_cb);
  1542. send_packetdump_monitor(START_MONITOR);
  1543. gtx_count = 0;
  1544. grx_count = 0;
  1545. csr_packetdump_timer_start();
  1546. }
  1547. #endif /* CONNECTIVITY_PKTLOG */
  1548. #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */