xref: /wlan-dirver/qca-wifi-host-cmn/utils/pktlog/pktlog_internal.c (revision d78dedc9dd8c4ee677ac1649d1d42f2a7c3cc1b7)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  *
21  * Permission to use, copy, modify, and/or distribute this software for any
22  * purpose with or without fee is hereby granted, provided that the above
23  * copyright notice and this permission notice appear in all copies.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
26  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
28  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32  */
33 
34 #ifndef REMOVE_PKT_LOG
35 #include "ol_txrx_types.h"
36 #include "ol_htt_tx_api.h"
37 #include "ol_tx_desc.h"
38 #include "qdf_mem.h"
39 #include "htt.h"
40 #include "htt_internal.h"
41 #include "pktlog_ac_i.h"
42 #include "wma_api.h"
43 #include "wlan_logging_sock_svc.h"
44 
45 #define TX_DESC_ID_LOW_MASK     0xffff
46 #define TX_DESC_ID_LOW_SHIFT    0
47 #define TX_DESC_ID_HIGH_MASK    0xffff0000
48 #define TX_DESC_ID_HIGH_SHIFT   16
49 
50 void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg)
51 {
52 	struct ath_pktlog_buf *log_buf;
53 	int32_t buf_size;
54 	struct ath_pktlog_hdr *log_hdr;
55 	int32_t cur_wr_offset;
56 	char *log_ptr;
57 	struct ath_pktlog_info *pl_info;
58 	uint16_t log_type;
59 	size_t log_size;
60 	uint32_t flags;
61 #ifdef HELIUMPLUS
62 	uint8_t mac_id;
63 #endif
64 
65 	if (!plarg) {
66 		printk("Invalid parg in %s\n", __func__);
67 		return;
68 	}
69 
70 	pl_info = plarg->pl_info;
71 #ifdef HELIUMPLUS
72 	mac_id = plarg->macId;
73 	log_type = plarg->log_type;
74 #else
75 	log_type = plarg->log_type;
76 #endif
77 	log_size = plarg->log_size;
78 	log_buf = pl_info->buf;
79 	flags = plarg->flags;
80 
81 	if (!log_buf) {
82 		printk("Invalid log_buf in %s\n", __func__);
83 		return;
84 	}
85 
86 
87 	buf_size = pl_info->buf_size;
88 	cur_wr_offset = log_buf->wr_offset;
89 	/* Move read offset to the next entry if there is a buffer overlap */
90 	if (log_buf->rd_offset >= 0) {
91 		if ((cur_wr_offset <= log_buf->rd_offset)
92 		    && (cur_wr_offset + sizeof(struct ath_pktlog_hdr)) >
93 		    log_buf->rd_offset) {
94 			PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf,
95 					  buf_size);
96 		}
97 	} else {
98 		log_buf->rd_offset = cur_wr_offset;
99 	}
100 
101 	log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + cur_wr_offset);
102 
103 	log_hdr->flags = flags;
104 #ifdef HELIUMPLUS
105 	log_hdr->macId = mac_id;
106 	log_hdr->log_type = log_type;
107 #else
108 	log_hdr->log_type = log_type;
109 #endif
110 	log_hdr->size = (uint16_t) log_size;
111 	log_hdr->missed_cnt = plarg->missed_cnt;
112 	log_hdr->timestamp = plarg->timestamp;
113 #ifdef HELIUMPLUS
114 	log_hdr->type_specific_data = plarg->type_specific_data;
115 #endif
116 	cur_wr_offset += sizeof(*log_hdr);
117 
118 	if ((buf_size - cur_wr_offset) < log_size) {
119 		while ((cur_wr_offset <= log_buf->rd_offset)
120 		       && (log_buf->rd_offset < buf_size)) {
121 			PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf,
122 					  buf_size);
123 		}
124 		cur_wr_offset = 0;
125 	}
126 
127 	while ((cur_wr_offset <= log_buf->rd_offset)
128 	       && (cur_wr_offset + log_size) > log_buf->rd_offset) {
129 		PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, buf_size);
130 	}
131 
132 	log_ptr = &(log_buf->log_data[cur_wr_offset]);
133 	cur_wr_offset += log_hdr->size;
134 
135 	log_buf->wr_offset = ((buf_size - cur_wr_offset) >=
136 			      sizeof(struct ath_pktlog_hdr)) ? cur_wr_offset :
137 			     0;
138 
139 	plarg->buf = log_ptr;
140 }
141 
142 char *pktlog_getbuf(struct pktlog_dev_t *pl_dev,
143 		    struct ath_pktlog_info *pl_info,
144 		    size_t log_size, struct ath_pktlog_hdr *pl_hdr)
145 {
146 	struct ath_pktlog_arg plarg = { 0, };
147 	uint8_t flags = 0;
148 
149 	plarg.pl_info = pl_info;
150 #ifdef HELIUMPLUS
151 	plarg.macId = pl_hdr->macId;
152 	plarg.log_type = pl_hdr->log_type;
153 #else
154 	plarg.log_type = pl_hdr->log_type;
155 #endif
156 	plarg.log_size = log_size;
157 	plarg.flags = pl_hdr->flags;
158 	plarg.missed_cnt = pl_hdr->missed_cnt;
159 	plarg.timestamp = pl_hdr->timestamp;
160 #ifdef HELIUMPLUS
161 	plarg.type_specific_data = pl_hdr->type_specific_data;
162 #endif
163 	if (flags & PHFLAGS_INTERRUPT_CONTEXT) {
164 		/*
165 		 * We are already in interrupt context, no need to make it
166 		 * intsafe. call the function directly.
167 		 */
168 		pktlog_getbuf_intsafe(&plarg);
169 	} else {
170 		PKTLOG_LOCK(pl_info);
171 		pktlog_getbuf_intsafe(&plarg);
172 		PKTLOG_UNLOCK(pl_info);
173 	}
174 
175 	return plarg.buf;
176 }
177 
178 static struct txctl_frm_hdr frm_hdr;
179 
180 #ifndef HELIUMPLUS
181 static void process_ieee_hdr(void *data)
182 {
183 	uint8_t dir;
184 	struct ieee80211_frame *wh = (struct ieee80211_frame *)(data);
185 
186 	frm_hdr.framectrl = *(uint16_t *) (wh->i_fc);
187 	frm_hdr.seqctrl = *(uint16_t *) (wh->i_seq);
188 	dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK);
189 
190 	if (dir == IEEE80211_FC1_DIR_TODS) {
191 		frm_hdr.bssid_tail =
192 			(wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
193 								      i_addr1
194 								      [IEEE80211_ADDR_LEN
195 								       - 1]);
196 		frm_hdr.sa_tail =
197 			(wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
198 								      i_addr2
199 								      [IEEE80211_ADDR_LEN
200 								       - 1]);
201 		frm_hdr.da_tail =
202 			(wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
203 								      i_addr3
204 								      [IEEE80211_ADDR_LEN
205 								       - 1]);
206 	} else if (dir == IEEE80211_FC1_DIR_FROMDS) {
207 		frm_hdr.bssid_tail =
208 			(wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
209 								      i_addr2
210 								      [IEEE80211_ADDR_LEN
211 								       - 1]);
212 		frm_hdr.sa_tail =
213 			(wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
214 								      i_addr3
215 								      [IEEE80211_ADDR_LEN
216 								       - 1]);
217 		frm_hdr.da_tail =
218 			(wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
219 								      i_addr1
220 								      [IEEE80211_ADDR_LEN
221 								       - 1]);
222 	} else {
223 		frm_hdr.bssid_tail =
224 			(wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
225 								      i_addr3
226 								      [IEEE80211_ADDR_LEN
227 								       - 1]);
228 		frm_hdr.sa_tail =
229 			(wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
230 								      i_addr2
231 								      [IEEE80211_ADDR_LEN
232 								       - 1]);
233 		frm_hdr.da_tail =
234 			(wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh->
235 								      i_addr1
236 								      [IEEE80211_ADDR_LEN
237 								       - 1]);
238 	}
239 }
240 
241 /**
242  * fill_ieee80211_hdr_data() - fill ieee802.11 data header
243  * @txrx_pdev: txrx pdev
244  * @pl_msdu_info: msdu info
245  * @data: data received from event
246  *
247  * Return: none
248  */
249 /* TODO: Platform specific function */
250 static void
251 fill_ieee80211_hdr_data(struct cdp_pdev *pdev,
252 	struct ath_pktlog_msdu_info *pl_msdu_info, void *data)
253 {
254 	uint32_t i;
255 	uint32_t *htt_tx_desc;
256 	struct ol_tx_desc_t *tx_desc;
257 	uint8_t msdu_id_offset = MSDU_ID_INFO_ID_OFFSET;
258 	uint16_t tx_desc_id;
259 	uint32_t *msdu_id_info = (uint32_t *)
260 				 ((void *)data + sizeof(struct ath_pktlog_hdr));
261 	uint32_t *msdu_id = (uint32_t *) ((char *)msdu_id_info +
262 					  msdu_id_offset);
263 	uint8_t *addr, *vap_addr;
264 	uint8_t vdev_id;
265 	qdf_nbuf_t netbuf;
266 	uint32_t len;
267 	struct ol_txrx_pdev_t *txrx_pdev = (struct ol_txrx_pdev_t *)pdev;
268 
269 
270 	pl_msdu_info->num_msdu = *msdu_id_info;
271 	pl_msdu_info->priv_size = sizeof(uint32_t) *
272 				 pl_msdu_info->num_msdu + sizeof(uint32_t);
273 
274 	if (pl_msdu_info->num_msdu > MAX_PKT_INFO_MSDU_ID) {
275 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
276 			  "%s: Invalid num_msdu count",
277 			  __func__);
278 		qdf_assert(0);
279 		return;
280 	}
281 	for (i = 0; i < pl_msdu_info->num_msdu; i++) {
282 		/*
283 		 * Handle big endianness
284 		 * Increment msdu_id once after retrieving
285 		 * lower 16 bits and uppper 16 bits
286 		 */
287 		if (!(i % 2)) {
288 			tx_desc_id = ((*msdu_id & TX_DESC_ID_LOW_MASK)
289 				      >> TX_DESC_ID_LOW_SHIFT);
290 		} else {
291 			tx_desc_id = ((*msdu_id & TX_DESC_ID_HIGH_MASK)
292 				      >> TX_DESC_ID_HIGH_SHIFT);
293 			msdu_id += 1;
294 		}
295 		if (tx_desc_id >= txrx_pdev->tx_desc.pool_size) {
296 			QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
297 				"%s: drop due to invalid msdu id = %x\n",
298 				__func__, tx_desc_id);
299 			return;
300 		}
301 		tx_desc = ol_tx_desc_find(txrx_pdev, tx_desc_id);
302 		qdf_assert(tx_desc);
303 		netbuf = tx_desc->netbuf;
304 		htt_tx_desc = (uint32_t *) tx_desc->htt_tx_desc;
305 		qdf_assert(htt_tx_desc);
306 
307 		qdf_nbuf_peek_header(netbuf, &addr, &len);
308 
309 		if (len < (2 * IEEE80211_ADDR_LEN)) {
310 			qdf_print("TX frame does not have a valid address\n");
311 			return;
312 		}
313 		/* Adding header information for the TX data frames */
314 		vdev_id = (uint8_t) (*(htt_tx_desc +
315 				       HTT_TX_VDEV_ID_WORD) >>
316 				     HTT_TX_VDEV_ID_SHIFT) &
317 			  HTT_TX_VDEV_ID_MASK;
318 
319 		vap_addr = wma_get_vdev_address_by_vdev_id(vdev_id);
320 
321 		frm_hdr.da_tail = (addr[IEEE80211_ADDR_LEN - 2] << 8) |
322 				  (addr[IEEE80211_ADDR_LEN - 1]);
323 		frm_hdr.sa_tail =
324 			(addr[2 * IEEE80211_ADDR_LEN - 2] << 8) |
325 			(addr[2 * IEEE80211_ADDR_LEN - 1]);
326 		if (vap_addr) {
327 			frm_hdr.bssid_tail =
328 				(vap_addr[IEEE80211_ADDR_LEN - 2] << 8) |
329 				(vap_addr[IEEE80211_ADDR_LEN - 1]);
330 		} else {
331 			frm_hdr.bssid_tail = 0x0000;
332 		}
333 		pl_msdu_info->priv.msdu_len[i] = *(htt_tx_desc +
334 						  HTT_TX_MSDU_LEN_DWORD)
335 						& HTT_TX_MSDU_LEN_MASK;
336 		/*
337 		 * Add more information per MSDU
338 		 * e.g., protocol information
339 		 */
340 	}
341 
342 }
343 #endif
344 
345 #ifdef HELIUMPLUS
346 A_STATUS process_tx_info(struct cdp_pdev *txrx_pdev, void *data)
347 {
348 	/*
349 	 * Must include to process different types
350 	 * TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR
351 	 */
352 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
353 	struct ath_pktlog_hdr pl_hdr;
354 	struct ath_pktlog_info *pl_info;
355 	uint32_t *pl_tgt_hdr;
356 	struct ol_fw_data *fw_data;
357 	uint32_t len;
358 
359 	if (!txrx_pdev) {
360 		printk("Invalid pdev in %s\n", __func__);
361 		return A_ERROR;
362 	}
363 
364 	if (!pl_dev) {
365 		pr_err("Invalid pktlog handle in %s\n", __func__);
366 		qdf_assert(pl_dev);
367 		return A_ERROR;
368 	}
369 
370 	qdf_assert(data);
371 
372 	fw_data = (struct ol_fw_data *)data;
373 	len = fw_data->len;
374 	if (len < (sizeof(uint32_t) *
375 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
376 		len < (sizeof(uint32_t) *
377 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
378 		len < (sizeof(uint32_t) *
379 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
380 		len < (sizeof(uint32_t) *
381 		       (ATH_PKTLOG_HDR_MAC_ID_OFFSET + 1)) ||
382 		len < (sizeof(uint32_t) *
383 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
384 		len < (sizeof(uint32_t) *
385 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
386 		qdf_print("Invalid msdu len in %s\n", __func__);
387 		qdf_assert(0);
388 		return A_ERROR;
389 	}
390 
391 	pl_tgt_hdr = (uint32_t *)fw_data->data;
392 	/*
393 	 * Makes the short words (16 bits) portable b/w little endian
394 	 * and big endian
395 	 */
396 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
397 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
398 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
399 	pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
400 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
401 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
402 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
403 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
404 		   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
405 		  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
406 	pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
407 		   ATH_PKTLOG_HDR_MAC_ID_MASK) >>
408 		  ATH_PKTLOG_HDR_MAC_ID_SHIFT;
409 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
410 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
411 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
412 	pl_hdr.type_specific_data =
413 		*(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET);
414 	pl_info = pl_dev->pl_info;
415 
416 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
417 		qdf_assert(0);
418 		return A_ERROR;
419 	}
420 
421 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) {
422 		size_t log_size = sizeof(frm_hdr) + pl_hdr.size;
423 		void *txdesc_hdr_ctl = (void *)
424 		pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr);
425 		qdf_assert(txdesc_hdr_ctl);
426 		qdf_assert(pl_hdr.size < (370 * sizeof(u_int32_t)));
427 
428 		qdf_mem_copy(txdesc_hdr_ctl, &frm_hdr, sizeof(frm_hdr));
429 		qdf_mem_copy((char *)txdesc_hdr_ctl + sizeof(frm_hdr),
430 					((void *)fw_data->data +
431 					 sizeof(struct ath_pktlog_hdr)),
432 					 pl_hdr.size);
433 		pl_hdr.size = log_size;
434 		cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
435 						txdesc_hdr_ctl);
436 	}
437 
438 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) {
439 		struct ath_pktlog_tx_status txstat_log;
440 		size_t log_size = pl_hdr.size;
441 
442 		txstat_log.ds_status = (void *)
443 				       pktlog_getbuf(pl_dev, pl_info,
444 						     log_size, &pl_hdr);
445 		qdf_assert(txstat_log.ds_status);
446 		qdf_mem_copy(txstat_log.ds_status,
447 			     ((void *)fw_data->data +
448 			      sizeof(struct ath_pktlog_hdr)),
449 			     pl_hdr.size);
450 		/* TODO: MCL specific API */
451 		cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
452 						txstat_log.ds_status);
453 	}
454 	return A_OK;
455 }
456 
457 #else
458 A_STATUS process_tx_info(struct cdp_pdev *txrx_pdev, void *data)
459 {
460 	/*
461 	 * Must include to process different types
462 	 * TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR
463 	 */
464 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
465 	struct ath_pktlog_hdr pl_hdr;
466 	struct ath_pktlog_info *pl_info;
467 	uint32_t *pl_tgt_hdr;
468 	struct ol_fw_data *fw_data;
469 	uint32_t len;
470 
471 	if (!txrx_pdev) {
472 		qdf_print("Invalid pdev in %s\n", __func__);
473 		return A_ERROR;
474 	}
475 
476 	qdf_assert(pl_dev);
477 	qdf_assert(data);
478 
479 	fw_data = (struct ol_fw_data *)data;
480 	len = fw_data->len;
481 	if (len < (sizeof(uint32_t) *
482 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
483 		len < (sizeof(uint32_t) *
484 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
485 		len < (sizeof(uint32_t) *
486 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
487 		len < (sizeof(uint32_t) *
488 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
489 		len < (sizeof(uint32_t) *
490 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
491 		qdf_print("Invalid msdu len in %s\n", __func__);
492 		qdf_assert(0);
493 		return A_ERROR;
494 	}
495 
496 	pl_tgt_hdr = (uint32_t *)fw_data->data;
497 	/*
498 	 * Makes the short words (16 bits) portable b/w little endian
499 	 * and big endian
500 	 */
501 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
502 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
503 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
504 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
505 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
506 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
507 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
508 			   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
509 			  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
510 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
511 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
512 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
513 
514 	pl_info = pl_dev->pl_info;
515 
516 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_FRM_HDR) {
517 		/* Valid only for the TX CTL */
518 		process_ieee_hdr(fw_data->data + sizeof(pl_hdr));
519 	}
520 
521 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_VIRT_ADDR) {
522 		uint32_t desc_id = (uint32_t) *((uint32_t *)(fw_data->data +
523 						 sizeof(pl_hdr)));
524 		uint32_t vdev_id = desc_id;
525 
526 		/* if the pkt log msg is for the bcn frame the vdev id
527 		 * is piggybacked in desc_id and the MSB of the desc ID
528 		 * would be set to FF
529 		 */
530 #define BCN_DESC_ID 0xFF
531 		if ((desc_id >> 24) == BCN_DESC_ID) {
532 			void *data;
533 			uint32_t buf_size;
534 
535 			vdev_id &= 0x00FFFFFF;
536 			/* TODO: MCL specific API */
537 			data = wma_get_beacon_buffer_by_vdev_id(vdev_id,
538 								&buf_size);
539 			if (data) {
540 				/* TODO: platform specific API */
541 				process_ieee_hdr(data);
542 				qdf_mem_free(data);
543 			}
544 		} else {
545 			/*
546 			 * TODO: get the hdr content for mgmt frames from
547 			 * Tx mgmt desc pool
548 			 */
549 		}
550 	}
551 
552 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) {
553 		struct ath_pktlog_txctl txctl_log;
554 		size_t log_size = sizeof(txctl_log.priv);
555 
556 		txctl_log.txdesc_hdr_ctl = (void *)pktlog_getbuf(pl_dev,
557 								 pl_info,
558 								 log_size,
559 								 &pl_hdr);
560 
561 		if (!txctl_log.txdesc_hdr_ctl) {
562 			printk
563 				("failed to get buf for txctl_log.txdesc_hdr_ctl\n");
564 			return A_ERROR;
565 		}
566 
567 		/*
568 		 * frm hdr is currently Valid only for local frames
569 		 * Add capability to include the fmr hdr for remote frames
570 		 */
571 		txctl_log.priv.frm_hdr = frm_hdr;
572 		qdf_assert(txctl_log.priv.txdesc_ctl);
573 		qdf_assert(pl_hdr.size < sizeof(txctl_log.priv.txdesc_ctl));
574 		pl_hdr.size = (pl_hdr.size > sizeof(txctl_log.priv.txdesc_ctl))
575 			       ? sizeof(txctl_log.priv.txdesc_ctl) :
576 			       pl_hdr.size;
577 
578 		if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
579 			qdf_assert(0);
580 			return A_ERROR;
581 		}
582 		qdf_mem_copy((void *)&txctl_log.priv.txdesc_ctl,
583 			     ((void *)fw_data->data +
584 			      sizeof(struct ath_pktlog_hdr)),
585 			     pl_hdr.size);
586 		qdf_assert(txctl_log.txdesc_hdr_ctl);
587 		qdf_mem_copy(txctl_log.txdesc_hdr_ctl, &txctl_log.priv,
588 			     sizeof(txctl_log.priv));
589 		pl_hdr.size = log_size;
590 		cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
591 						txctl_log.txdesc_hdr_ctl);
592 		/* Add Protocol information and HT specific information */
593 	}
594 
595 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) {
596 		struct ath_pktlog_tx_status txstat_log;
597 		size_t log_size = pl_hdr.size;
598 
599 		txstat_log.ds_status = (void *)
600 				       pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr);
601 		qdf_assert(txstat_log.ds_status);
602 		qdf_mem_copy(txstat_log.ds_status,
603 			     ((void *)fw_data->data +
604 			      sizeof(struct ath_pktlog_hdr)),
605 			     pl_hdr.size);
606 
607 		cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
608 						txstat_log.ds_status);
609 	}
610 
611 	if (pl_hdr.log_type == PKTLOG_TYPE_TX_MSDU_ID) {
612 		struct ath_pktlog_msdu_info pl_msdu_info;
613 		size_t log_size;
614 
615 		qdf_mem_set(&pl_msdu_info, sizeof(pl_msdu_info), 0);
616 		log_size = sizeof(pl_msdu_info.priv);
617 
618 		if (pl_dev->mt_pktlog_enabled == false)
619 			fill_ieee80211_hdr_data(txrx_pdev,
620 						&pl_msdu_info, fw_data->data);
621 
622 		pl_msdu_info.ath_msdu_info = pktlog_getbuf(pl_dev, pl_info,
623 							   log_size, &pl_hdr);
624 		qdf_mem_copy((void *)&pl_msdu_info.priv.msdu_id_info,
625 			     ((void *)fw_data->data +
626 			      sizeof(struct ath_pktlog_hdr)),
627 			     sizeof(pl_msdu_info.priv.msdu_id_info));
628 		qdf_mem_copy(pl_msdu_info.ath_msdu_info, &pl_msdu_info.priv,
629 			     sizeof(pl_msdu_info.priv));
630 		cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
631 						pl_msdu_info.ath_msdu_info);
632 	}
633 
634 	return A_OK;
635 }
636 #endif
637 
638 /* TODO: hardware dependent function */
639 A_STATUS process_rx_info_remote(void *pdev, void *data)
640 {
641 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
642 	struct ath_pktlog_info *pl_info;
643 	struct htt_host_rx_desc_base *rx_desc;
644 	struct ath_pktlog_hdr pl_hdr;
645 	struct ath_pktlog_rx_info rxstat_log;
646 	size_t log_size;
647 	struct ol_rx_remote_data *r_data = (struct ol_rx_remote_data *)data;
648 	qdf_nbuf_t msdu;
649 
650 	if (!pdev || !r_data || !pl_dev) {
651 		qdf_print("%s: Invalid handle", __func__);
652 		return A_ERROR;
653 	}
654 
655 	pl_info = pl_dev->pl_info;
656 	msdu = r_data->msdu;
657 
658 	while (msdu) {
659 		rx_desc =
660 		   (struct htt_host_rx_desc_base *)(qdf_nbuf_data(msdu)) - 1;
661 		log_size =
662 			sizeof(*rx_desc) - sizeof(struct htt_host_fw_desc_base);
663 
664 		/*
665 		 * Construct the pktlog header pl_hdr
666 		 * Because desc is DMA'd to the host memory
667 		 */
668 		pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
669 		pl_hdr.missed_cnt = 0;
670 #if defined(HELIUMPLUS)
671 		pl_hdr.macId = r_data->mac_id;
672 		pl_hdr.log_type = PKTLOG_TYPE_RX_STAT;
673 		pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
674 #else
675 		pl_hdr.log_type = PKTLOG_TYPE_RX_STAT;
676 #endif
677 		pl_hdr.size = sizeof(*rx_desc) -
678 			      sizeof(struct htt_host_fw_desc_base);
679 #if defined(HELIUMPLUS)
680 		pl_hdr.timestamp =
681 			rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32;
682 		pl_hdr.type_specific_data = 0xDEADAA;
683 #else
684 		pl_hdr.timestamp = rx_desc->ppdu_end.tsf_timestamp;
685 #endif /* !defined(HELIUMPLUS) */
686 		rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
687 							   log_size, &pl_hdr);
688 		qdf_mem_copy(rxstat_log.rx_desc, (void *)rx_desc +
689 			     sizeof(struct htt_host_fw_desc_base), pl_hdr.size);
690 		cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
691 						rxstat_log.rx_desc);
692 		msdu = qdf_nbuf_next(msdu);
693 	}
694 	return A_OK;
695 }
696 
697 #ifdef HELIUMPLUS
698 A_STATUS process_rx_info(void *pdev, void *data)
699 {
700 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
701 	struct ath_pktlog_info *pl_info;
702 	struct ath_pktlog_rx_info rxstat_log;
703 	struct ath_pktlog_hdr pl_hdr;
704 	size_t log_size;
705 	uint32_t *pl_tgt_hdr;
706 	struct ol_fw_data *fw_data;
707 	uint32_t len;
708 
709 	if (!pdev) {
710 		printk("Invalid pdev in %s", __func__);
711 		return A_ERROR;
712 	}
713 
714 	pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
715 	if (!pl_dev) {
716 		printk("Invalid pl_dev in %s", __func__);
717 		return A_ERROR;
718 	}
719 
720 	fw_data = (struct ol_fw_data *)data;
721 	len = fw_data->len;
722 	if (len < (sizeof(uint32_t) *
723 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
724 		len < (sizeof(uint32_t) *
725 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
726 		len < (sizeof(uint32_t) *
727 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
728 		len < (sizeof(uint32_t) *
729 		       (ATH_PKTLOG_HDR_MAC_ID_OFFSET + 1)) ||
730 		len < (sizeof(uint32_t) *
731 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
732 		len < (sizeof(uint32_t) *
733 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
734 		qdf_print("Invalid msdu len in %s\n", __func__);
735 		qdf_assert(0);
736 		return A_ERROR;
737 	}
738 
739 	pl_info = pl_dev->pl_info;
740 	pl_tgt_hdr = (uint32_t *)fw_data->data;
741 
742 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
743 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
744 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
745 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
746 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
747 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
748 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
749 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
750 			   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
751 			  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
752 	pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
753 			   ATH_PKTLOG_HDR_MAC_ID_MASK) >>
754 			  ATH_PKTLOG_HDR_MAC_ID_SHIFT;
755 	pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
756 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
757 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
758 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
759 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
760 		qdf_assert(0);
761 		return A_ERROR;
762 	}
763 
764 	log_size = pl_hdr.size;
765 	rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
766 						   log_size, &pl_hdr);
767 	qdf_mem_copy(rxstat_log.rx_desc,
768 		     (void *)fw_data->data + sizeof(struct ath_pktlog_hdr),
769 		     pl_hdr.size);
770 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc);
771 
772 	return A_OK;
773 }
774 
775 #else
776 A_STATUS process_rx_info(void *pdev, void *data)
777 {
778 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
779 	struct ath_pktlog_info *pl_info;
780 	struct ath_pktlog_rx_info rxstat_log;
781 	struct ath_pktlog_hdr pl_hdr;
782 	size_t log_size;
783 	uint32_t *pl_tgt_hdr;
784 	struct ol_fw_data *fw_data;
785 	uint32_t len;
786 
787 	if (!pdev) {
788 		printk("Invalid pdev in %s", __func__);
789 		return A_ERROR;
790 	}
791 
792 	pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev;
793 	if (!pl_dev) {
794 		printk("Invalid pl_dev in %s", __func__);
795 		return A_ERROR;
796 	}
797 
798 	fw_data = (struct ol_fw_data *)data;
799 	len = fw_data->len;
800 	if (len < (sizeof(uint32_t) *
801 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
802 		len < (sizeof(uint32_t) *
803 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
804 		len < (sizeof(uint32_t) *
805 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
806 		len < (sizeof(uint32_t) *
807 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
808 		len < (sizeof(uint32_t) *
809 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
810 		qdf_print("Invalid msdu len in %s\n", __func__);
811 		qdf_assert(0);
812 		return A_ERROR;
813 	}
814 
815 	pl_info = pl_dev->pl_info;
816 	pl_tgt_hdr = (uint32_t *)fw_data->data;
817 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
818 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
819 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
820 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
821 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
822 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
823 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
824 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
825 				   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
826 				  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
827 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
828 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
829 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
830 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
831 		qdf_assert(0);
832 		return A_ERROR;
833 	}
834 
835 	log_size = pl_hdr.size;
836 	rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
837 						   log_size, &pl_hdr);
838 	qdf_mem_copy(rxstat_log.rx_desc,
839 		     (void *)fw_data->data + sizeof(struct ath_pktlog_hdr),
840 		     pl_hdr.size);
841 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc);
842 
843 	return A_OK;
844 }
845 #endif
846 
847 #ifdef HELIUMPLUS
848 A_STATUS process_rate_find(void *pdev, void *data)
849 {
850 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
851 	struct ath_pktlog_hdr pl_hdr;
852 	struct ath_pktlog_info *pl_info;
853 	size_t log_size;
854 	uint32_t len;
855 	struct ol_fw_data *fw_data;
856 
857 	/*
858 	 * Will be uncommented when the rate control find
859 	 * for pktlog is implemented in the firmware.
860 	 * Currently derived from the TX PPDU status
861 	 */
862 	struct ath_pktlog_rc_find rcf_log;
863 	uint32_t *pl_tgt_hdr;
864 
865 	if (!pdev || !data || !pl_dev) {
866 		qdf_print("%s: Invalid handle", __func__);
867 		return A_ERROR;
868 	}
869 
870 	fw_data = (struct ol_fw_data *)data;
871 	len = fw_data->len;
872 	if (len < (sizeof(uint32_t) *
873 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
874 		len < (sizeof(uint32_t) *
875 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
876 		len < (sizeof(uint32_t) *
877 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
878 		len < (sizeof(uint32_t) *
879 		       (ATH_PKTLOG_HDR_MAC_ID_OFFSET + 1)) ||
880 		len < (sizeof(uint32_t) *
881 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
882 		len < (sizeof(uint32_t) *
883 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
884 		qdf_print("Invalid msdu len in %s\n", __func__);
885 		qdf_assert(0);
886 		return A_ERROR;
887 	}
888 
889 	pl_tgt_hdr = (uint32_t *)fw_data->data;
890 	/*
891 	 * Makes the short words (16 bits) portable b/w little endian
892 	 * and big endian
893 	 */
894 
895 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
896 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
897 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
898 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
899 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
900 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
901 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
902 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
903 			   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
904 			  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
905 	pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
906 			   ATH_PKTLOG_HDR_MAC_ID_MASK) >>
907 			  ATH_PKTLOG_HDR_MAC_ID_SHIFT;
908 	pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
909 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
910 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
911 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
912 	pl_info = pl_dev->pl_info;
913 	log_size = pl_hdr.size;
914 	rcf_log.rcFind = (void *)pktlog_getbuf(pl_dev, pl_info,
915 					       log_size, &pl_hdr);
916 
917 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
918 		qdf_assert(0);
919 		return A_ERROR;
920 	}
921 	qdf_mem_copy(rcf_log.rcFind,
922 		     ((char *)fw_data->data + sizeof(struct ath_pktlog_hdr)),
923 		     pl_hdr.size);
924 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcf_log.rcFind);
925 
926 	return A_OK;
927 }
928 
929 #else
930 A_STATUS process_rate_find(void *pdev, void *data)
931 {
932 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
933 	struct ath_pktlog_hdr pl_hdr;
934 	struct ath_pktlog_info *pl_info;
935 	size_t log_size;
936 	uint32_t len;
937 	struct ol_fw_data *fw_data;
938 
939 	/*
940 	 * Will be uncommented when the rate control find
941 	 * for pktlog is implemented in the firmware.
942 	 * Currently derived from the TX PPDU status
943 	 */
944 	struct ath_pktlog_rc_find rcf_log;
945 	uint32_t *pl_tgt_hdr;
946 
947 	if (!pdev || !data || !pl_dev) {
948 		qdf_print("%s: Invalid handle", __func__);
949 		return A_ERROR;
950 	}
951 
952 	fw_data = (struct ol_fw_data *)data;
953 	len = fw_data->len;
954 	if (len < (sizeof(uint32_t) *
955 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
956 		len < (sizeof(uint32_t) *
957 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
958 		len < (sizeof(uint32_t) *
959 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
960 		len < (sizeof(uint32_t) *
961 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
962 		len < (sizeof(uint32_t) *
963 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
964 		qdf_print("Invalid msdu len in %s\n", __func__);
965 		qdf_assert(0);
966 		return A_ERROR;
967 	}
968 
969 	pl_tgt_hdr = (uint32_t *)fw_data->data;
970 	/*
971 	 * Makes the short words (16 bits) portable b/w little endian
972 	 * and big endian
973 	 */
974 
975 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
976 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
977 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
978 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
979 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
980 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
981 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
982 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
983 			   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
984 			  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
985 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
986 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
987 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
988 	pl_info = pl_dev->pl_info;
989 	log_size = pl_hdr.size;
990 	rcf_log.rcFind = (void *)pktlog_getbuf(pl_dev, pl_info,
991 					       log_size, &pl_hdr);
992 
993 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
994 		qdf_assert(0);
995 		return A_ERROR;
996 	}
997 	qdf_mem_copy(rcf_log.rcFind,
998 		     ((char *)fw_data->data + sizeof(struct ath_pktlog_hdr)),
999 		     pl_hdr.size);
1000 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcf_log.rcFind);
1001 
1002 	return A_OK;
1003 }
1004 #endif
1005 
1006 #ifdef HELIUMPLUS
1007 A_STATUS process_sw_event(void *pdev, void *data)
1008 {
1009 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
1010 	struct ath_pktlog_hdr pl_hdr;
1011 	struct ath_pktlog_info *pl_info;
1012 	size_t log_size;
1013 	uint32_t len;
1014 	struct ol_fw_data *fw_data;
1015 
1016 	/*
1017 	 * Will be uncommented when the rate control find
1018 	 * for pktlog is implemented in the firmware.
1019 	 * Currently derived from the TX PPDU status
1020 	 */
1021 	struct ath_pktlog_sw_event sw_event;
1022 	uint32_t *pl_tgt_hdr;
1023 
1024 	if (!pdev) {
1025 		qdf_print("Invalid pdev in %s\n", __func__);
1026 		return A_ERROR;
1027 	}
1028 	if (!data) {
1029 		qdf_print("Invalid data in %s\n", __func__);
1030 		return A_ERROR;
1031 	}
1032 	if (!pl_dev) {
1033 		qdf_print("Invalid pl_dev in %s", __func__);
1034 		return A_ERROR;
1035 	}
1036 
1037 	fw_data = (struct ol_fw_data *)data;
1038 	len = fw_data->len;
1039 	if (len < (sizeof(uint32_t) *
1040 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
1041 		len < (sizeof(uint32_t) *
1042 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
1043 		len < (sizeof(uint32_t) *
1044 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
1045 		len < (sizeof(uint32_t) *
1046 		       (ATH_PKTLOG_HDR_MAC_ID_OFFSET + 1)) ||
1047 		len < (sizeof(uint32_t) *
1048 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
1049 		len < (sizeof(uint32_t) *
1050 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
1051 		qdf_print("Invalid msdu len in %s\n", __func__);
1052 		qdf_assert(0);
1053 		return A_ERROR;
1054 	}
1055 
1056 	pl_tgt_hdr = (uint32_t *)fw_data->data;
1057 	/*
1058 	 * Makes the short words (16 bits) portable b/w little endian
1059 	 * and big endian
1060 	 */
1061 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
1062 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
1063 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
1064 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
1065 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
1066 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
1067 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
1068 			   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
1069 			  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
1070 	pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
1071 			   ATH_PKTLOG_HDR_MAC_ID_MASK) >>
1072 			  ATH_PKTLOG_HDR_MAC_ID_SHIFT;
1073 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
1074 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
1075 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
1076 
1077 	pl_hdr.type_specific_data =
1078 		*(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET);
1079 	pl_info = pl_dev->pl_info;
1080 	log_size = pl_hdr.size;
1081 	sw_event.sw_event = (void *)pktlog_getbuf(pl_dev, pl_info,
1082 					       log_size, &pl_hdr);
1083 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
1084 		qdf_assert(0);
1085 		return A_ERROR;
1086 	}
1087 	qdf_mem_copy(sw_event.sw_event,
1088 		     ((char *)fw_data->data + sizeof(struct ath_pktlog_hdr)),
1089 		     pl_hdr.size);
1090 
1091 	return A_OK;
1092 }
1093 
1094 #else
1095 A_STATUS process_sw_event(void *pdev, void *data)
1096 {
1097 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
1098 	struct ath_pktlog_hdr pl_hdr;
1099 	struct ath_pktlog_info *pl_info;
1100 	size_t log_size;
1101 	uint32_t len;
1102 	struct ol_fw_data *fw_data;
1103 
1104 	/*
1105 	 * Will be uncommented when the rate control find
1106 	 * for pktlog is implemented in the firmware.
1107 	 * Currently derived from the TX PPDU status
1108 	 */
1109 	struct ath_pktlog_sw_event sw_event;
1110 	uint32_t *pl_tgt_hdr;
1111 
1112 	if (!pdev) {
1113 		qdf_print("Invalid pdev in %s\n", __func__);
1114 		return A_ERROR;
1115 	}
1116 	if (!data) {
1117 		qdf_print("Invalid data in %s\n", __func__);
1118 		return A_ERROR;
1119 	}
1120 	if (!pl_dev) {
1121 		qdf_print("Invalid pl_dev in %s", __func__);
1122 		return A_ERROR;
1123 	}
1124 
1125 	fw_data = (struct ol_fw_data *)data;
1126 	len = fw_data->len;
1127 	if (len < (sizeof(uint32_t) *
1128 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
1129 		len < (sizeof(uint32_t) *
1130 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
1131 		len < (sizeof(uint32_t) *
1132 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
1133 		len < (sizeof(uint32_t) *
1134 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
1135 		len < (sizeof(uint32_t) *
1136 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
1137 		qdf_print("Invalid msdu len in %s\n", __func__);
1138 		qdf_assert(0);
1139 		return A_ERROR;
1140 	}
1141 
1142 	pl_tgt_hdr = (uint32_t *)fw_data->data;
1143 	/*
1144 	 * Makes the short words (16 bits) portable b/w little endian
1145 	 * and big endian
1146 	 */
1147 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
1148 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
1149 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
1150 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
1151 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
1152 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
1153 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
1154 				   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
1155 				  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
1156 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
1157 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
1158 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
1159 	pl_info = pl_dev->pl_info;
1160 	log_size = pl_hdr.size;
1161 	sw_event.sw_event = (void *)pktlog_getbuf(pl_dev, pl_info,
1162 					       log_size, &pl_hdr);
1163 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
1164 		qdf_assert(0);
1165 		return A_ERROR;
1166 	}
1167 	qdf_mem_copy(sw_event.sw_event,
1168 		     ((char *)fw_data->data + sizeof(struct ath_pktlog_hdr)),
1169 		     pl_hdr.size);
1170 
1171 	return A_OK;
1172 }
1173 #endif
1174 
1175 #ifdef HELIUMPLUS
1176 A_STATUS process_rate_update(void *pdev, void *data)
1177 {
1178 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
1179 	struct ath_pktlog_hdr pl_hdr;
1180 	size_t log_size;
1181 	struct ath_pktlog_info *pl_info;
1182 	struct ath_pktlog_rc_update rcu_log;
1183 	uint32_t *pl_tgt_hdr;
1184 	struct ol_fw_data *fw_data;
1185 	uint32_t len;
1186 
1187 	if (!pdev || !data || !pl_dev) {
1188 		qdf_print("%s: Invalid handle", __func__);
1189 		return A_ERROR;
1190 	}
1191 
1192 	fw_data = (struct ol_fw_data *)data;
1193 	len = fw_data->len;
1194 	if (len < (sizeof(uint32_t) *
1195 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
1196 		len < (sizeof(uint32_t) *
1197 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
1198 		len < (sizeof(uint32_t) *
1199 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
1200 		len < (sizeof(uint32_t) *
1201 		       (ATH_PKTLOG_HDR_MAC_ID_OFFSET + 1)) ||
1202 		len < (sizeof(uint32_t) *
1203 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
1204 		len < (sizeof(uint32_t) *
1205 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
1206 		qdf_print("Invalid msdu len in %s\n", __func__);
1207 		qdf_assert(0);
1208 		return A_ERROR;
1209 	}
1210 
1211 	pl_tgt_hdr = (uint32_t *)fw_data->data;
1212 	/*
1213 	 * Makes the short words (16 bits) portable b/w little endian
1214 	 * and big endian
1215 	 */
1216 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
1217 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
1218 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
1219 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
1220 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
1221 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
1222 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
1223 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
1224 			   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
1225 			  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
1226 	pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) &
1227 			   ATH_PKTLOG_HDR_MAC_ID_MASK) >>
1228 			  ATH_PKTLOG_HDR_MAC_ID_SHIFT;
1229 	pl_hdr.flags |= PKTLOG_HDR_SIZE_16;
1230 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
1231 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
1232 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
1233 	log_size = pl_hdr.size;
1234 	pl_info = pl_dev->pl_info;
1235 
1236 	/*
1237 	 * Will be uncommented when the rate control update
1238 	 * for pktlog is implemented in the firmware.
1239 	 * Currently derived from the TX PPDU status
1240 	 */
1241 	rcu_log.txRateCtrl = (void *)pktlog_getbuf(pl_dev, pl_info,
1242 						   log_size, &pl_hdr);
1243 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
1244 		qdf_assert(0);
1245 		return A_ERROR;
1246 	}
1247 	qdf_mem_copy(rcu_log.txRateCtrl,
1248 		     ((char *)fw_data->data +
1249 		      sizeof(struct ath_pktlog_hdr)),
1250 		     pl_hdr.size);
1251 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcu_log.txRateCtrl);
1252 	return A_OK;
1253 }
1254 
1255 #else
1256 A_STATUS process_rate_update(void *pdev, void *data)
1257 {
1258 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
1259 	struct ath_pktlog_hdr pl_hdr;
1260 	size_t log_size;
1261 	struct ath_pktlog_info *pl_info;
1262 	struct ath_pktlog_rc_update rcu_log;
1263 	uint32_t *pl_tgt_hdr;
1264 	struct ol_fw_data *fw_data;
1265 	uint32_t len;
1266 
1267 	if (!pdev || !data || !pl_dev) {
1268 		qdf_print("%s: Invalid handle", __func__);
1269 		return A_ERROR;
1270 	}
1271 
1272 	fw_data = (struct ol_fw_data *)data;
1273 	len = fw_data->len;
1274 	if (len < (sizeof(uint32_t) *
1275 		   (ATH_PKTLOG_HDR_FLAGS_OFFSET + 1)) ||
1276 		len < (sizeof(uint32_t) *
1277 		       (ATH_PKTLOG_HDR_MISSED_CNT_OFFSET + 1)) ||
1278 		len < (sizeof(uint32_t) *
1279 		       (ATH_PKTLOG_HDR_LOG_TYPE_OFFSET + 1)) ||
1280 		len < (sizeof(uint32_t) *
1281 		       (ATH_PKTLOG_HDR_SIZE_OFFSET + 1)) ||
1282 		len < (sizeof(uint32_t) *
1283 		       (ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET + 1))) {
1284 		qdf_print("Invalid msdu len in %s\n", __func__);
1285 		qdf_assert(0);
1286 		return A_ERROR;
1287 	}
1288 
1289 	pl_tgt_hdr = (uint32_t *)fw_data->data;
1290 	/*
1291 	 * Makes the short words (16 bits) portable b/w little endian
1292 	 * and big endian
1293 	 */
1294 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
1295 	pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) &
1296 			ATH_PKTLOG_HDR_FLAGS_MASK) >>
1297 		       ATH_PKTLOG_HDR_FLAGS_SHIFT;
1298 	pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) &
1299 			     ATH_PKTLOG_HDR_MISSED_CNT_MASK) >>
1300 			    ATH_PKTLOG_HDR_MISSED_CNT_SHIFT;
1301 	pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) &
1302 				   ATH_PKTLOG_HDR_LOG_TYPE_MASK) >>
1303 				  ATH_PKTLOG_HDR_LOG_TYPE_SHIFT;
1304 	pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) &
1305 		       ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT;
1306 	pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET);
1307 	log_size = pl_hdr.size;
1308 	pl_info = pl_dev->pl_info;
1309 
1310 	/*
1311 	 * Will be uncommented when the rate control update
1312 	 * for pktlog is implemented in the firmware.
1313 	 * Currently derived from the TX PPDU status
1314 	 */
1315 	rcu_log.txRateCtrl = (void *)pktlog_getbuf(pl_dev, pl_info,
1316 						   log_size, &pl_hdr);
1317 	if (sizeof(struct ath_pktlog_hdr) + pl_hdr.size > len) {
1318 		qdf_assert(0);
1319 		return A_ERROR;
1320 	}
1321 	qdf_mem_copy(rcu_log.txRateCtrl,
1322 		     ((char *)fw_data->data +
1323 		      sizeof(struct ath_pktlog_hdr)),
1324 		     pl_hdr.size);
1325 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcu_log.txRateCtrl);
1326 	return A_OK;
1327 }
1328 #endif
1329 
1330 #ifdef QCA_WIFI_QCA6290
1331 int process_rx_desc_remote(void *pdev, void *data)
1332 {
1333 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
1334 	struct ath_pktlog_hdr pl_hdr;
1335 	struct ath_pktlog_rx_info rxstat_log;
1336 	size_t log_size;
1337 	struct ath_pktlog_info *pl_info;
1338 	qdf_nbuf_t log_nbuf = (qdf_nbuf_t)data;
1339 
1340 	pl_info = pl_dev->pl_info;
1341 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
1342 	pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
1343 	pl_hdr.missed_cnt = 0;
1344 	pl_hdr.log_type = 22; /*PKTLOG_TYPE_RX_STATBUF*/
1345 	pl_hdr.size = qdf_nbuf_len(log_nbuf);
1346 	pl_hdr.timestamp = 0;
1347 	log_size = pl_hdr.size;
1348 	rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
1349 						  log_size, &pl_hdr);
1350 
1351 	if (rxstat_log.rx_desc == NULL) {
1352 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
1353 				"%s: Rx descriptor is NULL", __func__);
1354 		return -EFAULT;
1355 	}
1356 
1357 	qdf_mem_copy(rxstat_log.rx_desc, qdf_nbuf_data(log_nbuf), pl_hdr.size);
1358 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL,
1359 						rxstat_log.rx_desc);
1360 	return 0;
1361 }
1362 
1363 int
1364 process_pktlog_lite(void *context, void *log_data, uint16_t log_type)
1365 {
1366 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
1367 	struct ath_pktlog_info *pl_info;
1368 	struct ath_pktlog_hdr pl_hdr;
1369 	struct ath_pktlog_rx_info rxstat_log;
1370 	size_t log_size;
1371 	qdf_nbuf_t log_nbuf = (qdf_nbuf_t)log_data;
1372 
1373 	pl_info = pl_dev->pl_info;
1374 	qdf_mem_set(&pl_hdr, sizeof(pl_hdr), 0);
1375 	pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
1376 	pl_hdr.missed_cnt = 0;
1377 	pl_hdr.log_type = log_type;
1378 	pl_hdr.size = qdf_nbuf_len(log_nbuf);
1379 	pl_hdr.timestamp = 0;
1380 	log_size = pl_hdr.size;
1381 	rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info,
1382 						  log_size, &pl_hdr);
1383 
1384 	if (rxstat_log.rx_desc == NULL) {
1385 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
1386 			"%s: Rx descriptor is NULL", __func__);
1387 		return -EFAULT;
1388 	}
1389 
1390 	qdf_mem_copy(rxstat_log.rx_desc, qdf_nbuf_data(log_nbuf), pl_hdr.size);
1391 
1392 	cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc);
1393 	return 0;
1394 }
1395 #else
1396 int process_rx_desc_remote(void *pdev, void *data)
1397 {
1398 	return 0;
1399 }
1400 int
1401 process_pktlog_lite(void *context, void *log_data, uint16_t log_type)
1402 {
1403 	return 0;
1404 }
1405 #endif
1406 #endif /*REMOVE_PKT_LOG */
1407