浏览代码

qcacmn: Add support to collect pktlogs as part of bugreport

Add infrastructure in pktlog utils to collect pktlogs as part
of bug report generation. As part of this when pktlog read command
is received on host:
1. disable pktlog,
2. read pktlog,
3. clear pktlog buffer,and
4. Retain pktlog initial state

Change-Id: I67e2231c2897007b58fa42a4f931b3c35ad1f418
CRs-Fixed: 2031287
Poddar, Siddarth 8 年之前
父节点
当前提交
3a52bd7e6a
共有 3 个文件被更改,包括 192 次插入5 次删除
  1. 28 0
      utils/pktlog/include/pktlog_ac_api.h
  2. 95 1
      utils/pktlog/linux_ac.c
  3. 69 4
      utils/pktlog/pktlog_ac.c

+ 28 - 0
utils/pktlog/include/pktlog_ac_api.h

@@ -61,11 +61,39 @@ void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle,
 /* Packet log state information */
 #ifndef _PKTLOG_INFO
 #define _PKTLOG_INFO
+
+/**
+ * enum ath_pktlog_state - pktlog status
+ * @PKTLOG_OPR_IN_PROGRESS : pktlog command in progress
+ * @PKTLOG_OPR_IN_PROGRESS_READ_START: pktlog read is issued
+ * @PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED:
+ *			as part of pktlog read, pktlog is disabled
+ * @PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE:
+ *		as part of read, till pktlog read is complete
+ * @PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE:
+ *		as part of read, pktlog clear buffer is done
+ * @PKTLOG_OPR_NOT_IN_PROGRESS: no pktlog command in progress
+ */
+enum ath_pktlog_state {
+	PKTLOG_OPR_IN_PROGRESS = 0,
+	PKTLOG_OPR_IN_PROGRESS_READ_START,
+	PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED,
+	PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE,
+	PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE,
+	PKTLOG_OPR_NOT_IN_PROGRESS
+};
+
 struct ath_pktlog_info {
 	struct ath_pktlog_buf *buf;
 	uint32_t log_state;
 	uint32_t saved_state;
 	uint32_t options;
+	/* Initial saved state: It will save the log state in pktlog
+	 * open and used in pktlog release after
+	 * pktlog read is complete.
+	 */
+	uint32_t init_saved_state;
+	enum ath_pktlog_state curr_pkt_state;
 
 	/* Size of buffer in bytes */
 	int32_t buf_size;

+ 95 - 1
utils/pktlog/linux_ac.c

@@ -534,13 +534,107 @@ static void pktlog_detach(struct ol_txrx_pdev_t *handle)
 
 static int pktlog_open(struct inode *i, struct file *f)
 {
+	struct hif_opaque_softc *scn;
+	struct ol_pktlog_dev_t *pl_dev;
+	struct ath_pktlog_info *pl_info;
+	int ret = 0;
+
 	PKTLOG_MOD_INC_USE_COUNT;
-	return 0;
+	pl_info = (struct ath_pktlog_info *)
+			PDE_DATA(f->f_path.dentry->d_inode);
+
+	if (!pl_info) {
+		pr_err("%s: pl_info NULL", __func__);
+		return -EINVAL;
+	}
+
+	if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
+		pr_info("%s: plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
+			__func__, pl_info->curr_pkt_state);
+		return -EBUSY;
+	}
+
+	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
+	scn = cds_get_context(QDF_MODULE_ID_HIF);
+	if (!scn) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
+		qdf_print("%s: Invalid scn context\n", __func__);
+		ASSERT(0);
+		return -EINVAL;
+	}
+
+	pl_dev = cds_get_pl_handle();
+
+	if (!pl_dev) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
+		qdf_print("%s: Invalid pktlog handle\n", __func__);
+		ASSERT(0);
+		return -ENODEV;
+	}
+
+	pl_info->init_saved_state = pl_info->log_state;
+	if (!pl_info->log_state) {
+		/* Pktlog is already disabled.
+		 * Proceed to read directly.
+		 */
+		pl_info->curr_pkt_state =
+			PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
+		return ret;
+	}
+	/* Disbable the pktlog internally. */
+	ret = pl_dev->pl_funcs->pktlog_disable(scn);
+	pl_info->log_state = 0;
+	pl_info->curr_pkt_state =
+			PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
+	return ret;
 }
 
 static int pktlog_release(struct inode *i, struct file *f)
 {
+	struct hif_opaque_softc *scn;
+	struct ol_pktlog_dev_t *pl_dev;
+	struct ath_pktlog_info *pl_info;
+	int ret = 0;
+
 	PKTLOG_MOD_DEC_USE_COUNT;
+
+	pl_info = (struct ath_pktlog_info *)
+			PDE_DATA(f->f_path.dentry->d_inode);
+
+	if (!pl_info)
+		return -EINVAL;
+
+	scn = cds_get_context(QDF_MODULE_ID_HIF);
+	if (!scn) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
+		qdf_print("%s: Invalid scn context\n", __func__);
+		ASSERT(0);
+		return -EINVAL;
+	}
+
+	pl_dev = cds_get_pl_handle();
+
+	if (!pl_dev) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
+		qdf_print("%s: Invalid pktlog handle\n", __func__);
+		ASSERT(0);
+		return -ENODEV;
+	}
+
+	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE;
+	/*clear pktlog buffer.*/
+	pktlog_clearbuff(scn, true);
+	pl_info->log_state = pl_info->init_saved_state;
+	pl_info->init_saved_state = 0;
+
+	/*Enable pktlog again*/
+	ret = pl_dev->pl_funcs->pktlog_enable(
+			(struct hif_opaque_softc *)scn, pl_info->log_state,
+			cds_is_packet_log_enabled(), 0, 1);
+	if (ret != 0)
+		pr_warn("%s: pktlog cannot be enabled", __func__);
+
+	pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 	return 0;
 }
 

+ 69 - 4
utils/pktlog/pktlog_ac.c

@@ -304,6 +304,7 @@ int pktlog_disable(struct hif_opaque_softc *scn)
 		cds_get_context(QDF_MODULE_ID_TXRX);
 	struct ol_pktlog_dev_t *pl_dev;
 	struct ath_pktlog_info *pl_info;
+	uint8_t save_pktlog_state;
 
 	if (txrx_pdev == NULL ||
 			txrx_pdev->pl_dev == NULL ||
@@ -313,17 +314,36 @@ int pktlog_disable(struct hif_opaque_softc *scn)
 	pl_dev = txrx_pdev->pl_dev;
 	pl_info = pl_dev->pl_info;
 
+	if (pl_info->curr_pkt_state == PKTLOG_OPR_IN_PROGRESS ||
+	    pl_info->curr_pkt_state ==
+			PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED ||
+	    pl_info->curr_pkt_state == PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE ||
+	    pl_info->curr_pkt_state ==
+			PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE)
+		return -EBUSY;
+
+	save_pktlog_state = pl_info->curr_pkt_state;
+	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS;
+
 	if (pktlog_wma_post_msg(0, WMI_PDEV_PKTLOG_DISABLE_CMDID, 0, 0)) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		printk("Failed to disable pktlog in target\n");
 		return -EINVAL;
 	}
 
 	if (pl_dev->is_pktlog_cb_subscribed &&
 		wdi_pktlog_unsubscribe(txrx_pdev, pl_info->log_state)) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		printk("Cannot unsubscribe pktlog from the WDI\n");
 		return -EINVAL;
 	}
 	pl_dev->is_pktlog_cb_subscribed = false;
+	pl_dev->is_pktlog_cb_subscribed = false;
+	if (save_pktlog_state == PKTLOG_OPR_IN_PROGRESS_READ_START)
+		pl_info->curr_pkt_state =
+			PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
+	else
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 	return 0;
 }
 
@@ -346,6 +366,8 @@ void pktlog_init(struct hif_opaque_softc *scn)
 	pl_info->buf_size = PKTLOG_DEFAULT_BUFSIZE;
 	pl_info->buf = NULL;
 	pl_info->log_state = 0;
+	pl_info->init_saved_state = 0;
+	pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 	pl_info->sack_thr = PKTLOG_DEFAULT_SACK_THR;
 	pl_info->tail_length = PKTLOG_DEFAULT_TAIL_LENGTH;
 	pl_info->thruput_thresh = PKTLOG_DEFAULT_THRUPUT_THRESH;
@@ -399,23 +421,34 @@ int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
 	if (!pl_info)
 		return 0;
 
+	if (pl_info->curr_pkt_state < PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE)
+		return -EBUSY;
+
+	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS;
 	/* is_iwpriv_command : 0 indicates its a vendor command
 	 * log_state: 0 indicates pktlog disable command
 	 * vendor_cmd_send flag; false means no vendor pktlog enable
 	 * command was sent previously
 	 */
 	if (is_iwpriv_command == 0 && log_state == 0 &&
-	    pl_dev->vendor_cmd_send == false)
+	    pl_dev->vendor_cmd_send == false) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		return 0;
+	}
 
 	if (!pl_dev->tgt_pktlog_alloced) {
 		if (pl_info->buf == NULL) {
 			error = pktlog_alloc_buf(scn);
 
-			if (error != 0)
+			if (error != 0) {
+				pl_info->curr_pkt_state =
+					PKTLOG_OPR_NOT_IN_PROGRESS;
 				return error;
+			}
 
 			if (!pl_info->buf) {
+				pl_info->curr_pkt_state =
+					PKTLOG_OPR_NOT_IN_PROGRESS;
 				printk("%s: pktlog buf alloc failed\n",
 				       __func__);
 				ASSERT(0);
@@ -443,6 +476,7 @@ int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
 		/* WDI subscribe */
 		if ((!pl_dev->is_pktlog_cb_subscribed) &&
 			wdi_pktlog_subscribe(txrx_pdev, log_state)) {
+			pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 			printk("Unable to subscribe to the WDI %s\n", __func__);
 			return -EINVAL;
 		}
@@ -450,6 +484,7 @@ int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
 		/* WMI command to enable pktlog on the firmware */
 		if (pktlog_enable_tgt(scn, log_state, ini_triggered,
 				user_triggered)) {
+			pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 			printk("Device cannot be enabled, %s\n", __func__);
 			return -EINVAL;
 		}
@@ -457,12 +492,14 @@ int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
 		if (is_iwpriv_command == 0)
 			pl_dev->vendor_cmd_send = true;
 	} else {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		pl_dev->pl_funcs->pktlog_disable(scn);
 		if (is_iwpriv_command == 0)
 			pl_dev->vendor_cmd_send = false;
 	}
 
 	pl_info->log_state = log_state;
+	pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 	return 0;
 }
 
@@ -481,16 +518,25 @@ int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size)
 	pl_dev = pdev_txrx_handle->pl_dev;
 	pl_info = pl_dev->pl_info;
 
-	if (size < 0)
+	if (pl_info->curr_pkt_state < PKTLOG_OPR_NOT_IN_PROGRESS)
+		return -EBUSY;
+
+	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS;
+
+	if (size < 0) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		return -EINVAL;
+	}
 
 	if (size == pl_info->buf_size) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		qdf_print("%s: Pktlog Buff Size is already of same size.",
 			  __func__);
 		return 0;
 	}
 
 	if (pl_info->log_state) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		qdf_print("%s: Logging should be disabled before changing"
 			  "buffer size.", __func__);
 		return -EINVAL;
@@ -500,6 +546,7 @@ int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size)
 		if (pl_dev->is_pktlog_cb_subscribed &&
 			wdi_pktlog_unsubscribe(pdev_txrx_handle,
 					 pl_info->log_state)) {
+			pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 			printk("Cannot unsubscribe pktlog from the WDI\n");
 			return -EFAULT;
 		}
@@ -512,7 +559,7 @@ int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size)
 		qdf_print("%s: New Pktlog Buff Size is %d\n", __func__, size);
 		pl_info->buf_size = size;
 	}
-
+	pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 	return 0;
 }
 
@@ -522,6 +569,7 @@ int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff)
 		cds_get_context(QDF_MODULE_ID_TXRX);
 	struct ol_pktlog_dev_t *pl_dev;
 	struct ath_pktlog_info *pl_info;
+	uint8_t save_pktlog_state;
 
 	if (pdev_txrx_handle == NULL ||
 			pdev_txrx_handle->pl_dev == NULL ||
@@ -534,7 +582,16 @@ int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff)
 	if (!clear_buff)
 		return -EINVAL;
 
+	if (pl_info->curr_pkt_state < PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE ||
+	    pl_info->curr_pkt_state ==
+				PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE)
+		return -EBUSY;
+
+	save_pktlog_state = pl_info->curr_pkt_state;
+	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS;
+
 	if (pl_info->log_state) {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		qdf_print("%s: Logging should be disabled before clearing "
 			  "pktlog buffer.", __func__);
 		return -EINVAL;
@@ -548,16 +605,24 @@ int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff)
 			pl_dev->tgt_pktlog_alloced = false;
 			pl_info->buf->rd_offset = -1;
 		} else {
+			pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 			qdf_print("%s: pktlog buffer size is not proper. "
 				  "Existing Buf size %d", __func__,
 				  pl_info->buf_size);
 			return -EFAULT;
 		}
 	} else {
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
 		qdf_print("%s: pktlog buff is NULL", __func__);
 		return -EFAULT;
 	}
 
+	if (save_pktlog_state == PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE)
+		pl_info->curr_pkt_state =
+			PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE;
+	else
+		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
+
 	return 0;
 }