diff --git a/utils/pktlog/include/pktlog_ac_api.h b/utils/pktlog/include/pktlog_ac_api.h index d033ddb5ec..b27558201a 100644 --- a/utils/pktlog/include/pktlog_ac_api.h +++ b/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; diff --git a/utils/pktlog/linux_ac.c b/utils/pktlog/linux_ac.c index cf5b4e1f57..a62fd55ecd 100644 --- a/utils/pktlog/linux_ac.c +++ b/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; } diff --git a/utils/pktlog/pktlog_ac.c b/utils/pktlog/pktlog_ac.c index 7f70c5b700..9d4b2291a7 100644 --- a/utils/pktlog/pktlog_ac.c +++ b/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; }