wlan: Add support to start/stop specific logging features
Add support to start and stop the logging of specific
logging features such as logging of wakelocks, per packet
statistics and connectivity events.
Change-Id: I94155e04c01757620be8686eec2c689166f22f3a
CRs-Fixed: 915570
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index 3bd6efa..d98bf55 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -2274,6 +2274,12 @@
#define CFG_WLAN_LOGGING_NUM_BUF_DEFAULT ( 32 )
#endif //WLAN_LOGGING_SOCK_SVC_ENABLE
+//Enable PerPKT stats Logging
+#define CFG_WLAN_PKT_STATS_LOGGING_NAME "wlanPerPktStatsLogEnable"
+#define CFG_WLAN_PKT_STATS_LOGGING_ENABLE ( 1 )
+#define CFG_WLAN_PKT_STATS_LOGGING_DISABLE ( 0 )
+#define CFG_WLAN_PKT_STATS_LOGGING_DEFAULT ( 1 )
+
#define CFG_IGNORE_PEER_ERP_INFO_NAME "gIgnorePeerErpInfo"
#define CFG_IGNORE_PEER_ERP_INFO_MIN ( 0 )
#define CFG_IGNORE_PEER_ERP_INFO_MAX ( 1 )
@@ -2997,6 +3003,7 @@
v_U32_t wlanLoggingEnable;
v_U32_t wlanLoggingFEToConsole;
v_U32_t wlanLoggingNumBuf;
+ v_U32_t wlanPerPktStatsLogEnable;
#endif
v_BOOL_t ignorePeerErpInfo;
v_BOOL_t initialScanSkipDFSCh;
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 68aed06..79c54f9 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -164,6 +164,8 @@
/* Get Concurrency Matrix */
QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42,
+ /* Start Wifi Logger */
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62,
/* Get Wifi Specific Info */
QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO = 61,
@@ -1026,6 +1028,26 @@
QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_wifi_logger_start - Enum for wifi logger starting
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID: Invalid attribute
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID: Ring ID
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL: Verbose level
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS: Flag
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST: Last value
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX: Max value
+ */
+enum qca_wlan_vendor_attr_wifi_logger_start {
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL = 2,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS = 3,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST - 1,
+};
+
/* Feature defines */
#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */
#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index 5163f55..834ff92 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -3052,6 +3052,13 @@
CFG_WLAN_LOGGING_NUM_BUF_DEFAULT,
CFG_WLAN_LOGGING_NUM_BUF_MIN,
CFG_WLAN_LOGGING_NUM_BUF_MAX ),
+ REG_VARIABLE( CFG_WLAN_PKT_STATS_LOGGING_NAME, WLAN_PARAM_Integer,
+ hdd_config_t, wlanPerPktStatsLogEnable,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_WLAN_PKT_STATS_LOGGING_DEFAULT,
+ CFG_WLAN_PKT_STATS_LOGGING_DISABLE,
+ CFG_WLAN_PKT_STATS_LOGGING_ENABLE ),
+
#endif //WLAN_LOGGING_SOCK_SVC_ENABLE
REG_VARIABLE( CFG_IGNORE_PEER_ERP_INFO_NAME, WLAN_PARAM_Integer,
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 4cb9e0d..d9b3646 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -5738,17 +5738,127 @@
wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data, int data_len)
+{
+ int ret = 0;
+ vos_ssr_protect(__func__);
+ ret = __wlan_hdd_cfg80211_get_fw_mem_dump(wiphy, wdev, data,
+ data_len);
+ vos_ssr_unprotect(__func__);
+ return ret;
+}
+static const struct
+nla_policy
+qca_wlan_vendor_wifi_logger_start_policy
+[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]
+ = {.type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]
+ = {.type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]
+ = {.type = NLA_U32 },
+};
+
+/**
+ * __wlan_hdd_cfg80211_wifi_logger_start() - This function is used to enable
+ * or disable the collection of packet statistics from the firmware
+ * @wiphy: WIPHY structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of the data received
+ *
+ * This function is used to enable or disable the collection of packet
+ * statistics from the firmware
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int __wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ eHalStatus status;
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1];
+ tAniWifiStartLog start_log;
+
+ status = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != status) {
+ return -EINVAL;
+ }
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX,
+ data, data_len,
+ qca_wlan_vendor_wifi_logger_start_policy)) {
+ hddLog(LOGE, FL("Invalid attribute"));
+ return -EINVAL;
+ }
+
+ /* Parse and fetch ring id */
+ if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]) {
+ hddLog(LOGE, FL("attr ATTR failed"));
+ return -EINVAL;
+ }
+ start_log.ringId = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]);
+ hddLog(LOG1, FL("Ring ID=%d"), start_log.ringId);
+
+ /* Parse and fetch verbose level */
+ if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]) {
+ hddLog(LOGE, FL("attr verbose_level failed"));
+ return -EINVAL;
+ }
+ start_log.verboseLevel = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]);
+ hddLog(LOG1, FL("verbose_level=%d"), start_log.verboseLevel);
+
+ /* Parse and fetch flag */
+ if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]) {
+ hddLog(LOGE, FL("attr flag failed"));
+ return -EINVAL;
+ }
+ start_log.flag = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]);
+ hddLog(LOG1, FL("flag=%d"), start_log.flag);
+
+ if ((RING_ID_PER_PACKET_STATS == start_log.ringId) &&
+ !hdd_ctx->cfg_ini->wlanPerPktStatsLogEnable)
+ {
+ hddLog(LOGE, FL("per pkt stats not enabled"));
+ return -EINVAL;
+ }
+ vos_set_ring_log_level(start_log.ringId, start_log.verboseLevel);
+
+ return 0;
+}
+
+/**
+ * wlan_hdd_cfg80211_wifi_logger_start() - Wrapper function used to enable
+ * or disable the collection of packet statistics from the firmware
+ * @wiphy: WIPHY structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of the data received
+ *
+ * This function is used to enable or disable the collection of packet
+ * statistics from the firmware
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
{
int ret = 0;
vos_ssr_protect(__func__);
- ret = __wlan_hdd_cfg80211_get_fw_mem_dump(wiphy, wdev, data,
- data_len);
+
+ ret = __wlan_hdd_cfg80211_wifi_logger_start(wiphy,
+ wdev, data, data_len);
vos_ssr_unprotect(__func__);
return ret;
-
}
@@ -6155,7 +6265,14 @@
WIPHY_VENDOR_CMD_NEED_NETDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wlan_hdd_cfg80211_setband
- }
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wlan_hdd_cfg80211_wifi_logger_start
+ },
};
/* vendor specific events */
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 5477b24..5cd541f 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -5648,6 +5648,20 @@
tANI_U8 SetTdls2040BSSCoex; //enabled or disabled
} tAniSetTdls2040BSSCoex, *tpAniSetTdls2040BSSCoex;
+/**
+ * struct sir_wifi_start_log - Structure to store the params sent to start/
+ * stop logging
+ * @ringId: Attribute which indicates the type of logging like per packet
+ * statistics, connectivity etc.
+ * @verboseLevel: Verbose level which can be 0,1,2,3
+ * @flag: Flag field for future use
+ */
+typedef struct sir_wifi_start_log {
+ tANI_U32 ringId;
+ tANI_U32 verboseLevel;
+ tANI_U32 flag;
+}tAniWifiStartLog, *tpAniWifiStartLog;
+
typedef struct
{
tANI_U16 mesgType;
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 7e5d0da..2cd0e03 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -75,6 +75,55 @@
#include <vos_timer.h>
#include <vos_pack_align.h>
+/**
+ * enum userspace_log_level - Log level at userspace
+ * @LOG_LEVEL_NO_COLLECTION: verbose_level 0 corresponds to no collection
+ * @LOG_LEVEL_NORMAL_COLLECT: verbose_level 1 correspond to normal log level,
+ * with minimal user impact. this is the default value
+ * @LOG_LEVEL_ISSUE_REPRO: verbose_level 2 are enabled when user is lazily
+ * trying to reproduce a problem, wifi performances and power can be impacted
+ * but device should not otherwise be significantly impacted
+ * @LOG_LEVEL_ACTIVE: verbose_level 3+ are used when trying to
+ * actively debug a problem
+ *
+ * Various log levels defined in the userspace for logging applications
+ */
+enum userspace_log_level {
+ LOG_LEVEL_NO_COLLECTION,
+ LOG_LEVEL_NORMAL_COLLECT,
+ LOG_LEVEL_ISSUE_REPRO,
+ LOG_LEVEL_ACTIVE,
+};
+
+/**
+ * enum wifi_driver_log_level - Log level defined in the driver for logging
+ * @WLAN_LOG_LEVEL_OFF: No logging
+ * @WLAN_LOG_LEVEL_NORMAL: Default logging
+ * @WLAN_LOG_LEVEL_REPRO: Normal debug level
+ * @WLAN_LOG_LEVEL_ACTIVE: Active debug level
+ *
+ * Log levels defined for logging by the wifi driver
+ */
+enum wifi_driver_log_level {
+ WLAN_LOG_LEVEL_OFF,
+ WLAN_LOG_LEVEL_NORMAL,
+ WLAN_LOG_LEVEL_REPRO,
+ WLAN_LOG_LEVEL_ACTIVE,
+};
+
+/**
+ * enum wifi_logging_ring_id - Ring id of logging entities
+ * @RING_ID_WAKELOCK: Power events ring id
+ * @RING_ID_CONNECTIVITY: Connectivity event ring id
+ * @RING_ID_PER_PACKET_STATS: Per packet statistic ring id
+ *
+ * This enum has the ring id values of logging rings
+ */
+enum wifi_logging_ring_id {
+ RING_ID_WAKELOCK,
+ RING_ID_CONNECTIVITY,
+ RING_ID_PER_PACKET_STATS,
+};
/**
* enum log_event_type - Type of event initiating bug report
@@ -432,7 +481,8 @@
v_U8_t vos_is_fw_logging_supported(void);
void vos_set_multicast_logging(uint8_t value);
v_U8_t vos_is_multicast_logging(void);
-bool vos_is_wakelock_enabled(void);
+void vos_set_ring_log_level(v_U32_t ring_id, v_U32_t log_level);
+v_U8_t vos_get_ring_log_level(v_U32_t ring_id);
v_BOOL_t vos_isUnloadInProgress(void);
v_BOOL_t vos_isLoadUnloadInProgress(void);
diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c
index 721e624..2bd28d9 100644
--- a/CORE/VOSS/src/vos_api.c
+++ b/CORE/VOSS/src/vos_api.c
@@ -2936,3 +2936,79 @@
}
}
+/**
+ * vos_set_ring_log_level() - Convert HLOS values to driver log levels
+ * @ring_id: ring_id
+ * @log_levelvalue: Log level specificed
+ *
+ * This function sets the log level of a particular ring
+ *
+ * Return: None
+ */
+ void vos_set_ring_log_level(v_U32_t ring_id, v_U32_t log_level)
+{
+ VosContextType *vos_context;
+ v_U32_t log_val;
+
+ vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ if (!vos_context) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: vos context is Invald", __func__);
+ return;
+ }
+
+ switch (log_level) {
+ case LOG_LEVEL_NO_COLLECTION:
+ log_val = WLAN_LOG_LEVEL_OFF;
+ break;
+ case LOG_LEVEL_NORMAL_COLLECT:
+ log_val = WLAN_LOG_LEVEL_NORMAL;
+ break;
+ case LOG_LEVEL_ISSUE_REPRO:
+ log_val = WLAN_LOG_LEVEL_REPRO;
+ break;
+ case LOG_LEVEL_ACTIVE:
+ default:
+ log_val = WLAN_LOG_LEVEL_ACTIVE;
+ break;
+ }
+
+ if (ring_id == RING_ID_WAKELOCK) {
+ vos_context->wakelock_log_level = log_val;
+ return;
+ } else if (ring_id == RING_ID_CONNECTIVITY) {
+ vos_context->connectivity_log_level = log_val;
+ return;
+ } else if (ring_id == RING_ID_PER_PACKET_STATS) {
+ vos_context->packet_stats_log_level = log_val;
+ return;
+ }
+}
+/**
+ * vos_get_ring_log_level() - Get the a ring id's log level
+ * @ring_id: Ring id
+ *
+ * Fetch and return the log level corresponding to a ring id
+ *
+ * Return: Log level corresponding to the ring ID
+ */
+v_U8_t vos_get_ring_log_level(v_U32_t ring_id)
+{
+ VosContextType *vos_context;
+
+ vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ if (!vos_context) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: vos context is Invald", __func__);
+ return WLAN_LOG_LEVEL_OFF;
+ }
+
+ if (ring_id == RING_ID_WAKELOCK)
+ return vos_context->wakelock_log_level;
+ else if (ring_id == RING_ID_CONNECTIVITY)
+ return vos_context->connectivity_log_level;
+ else if (ring_id == RING_ID_PER_PACKET_STATS)
+ return vos_context->packet_stats_log_level;
+
+ return WLAN_LOG_LEVEL_OFF;
+}
diff --git a/CORE/VOSS/src/vos_diag.c b/CORE/VOSS/src/vos_diag.c
index 285581d..aab6c6e 100644
--- a/CORE/VOSS/src/vos_diag.c
+++ b/CORE/VOSS/src/vos_diag.c
@@ -211,10 +211,18 @@
void vos_log_wlock_diag(uint32_t reason, const char *wake_lock_name,
uint32_t timeout, uint32_t status)
{
+ VosContextType *vos_context;
WLAN_VOS_DIAG_EVENT_DEF(wlan_diag_event,
struct vos_event_wlan_wake_lock);
- if (nl_srv_is_initialized() != 0)
+ vos_context = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+ if (!vos_context) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "vos context is Invald");
+ return;
+ }
+ if (nl_srv_is_initialized() != 0 ||
+ vos_context->wakelock_log_level == WLAN_LOG_LEVEL_OFF)
return;
wlan_diag_event.status = status;
diff --git a/CORE/VOSS/src/vos_sched.h b/CORE/VOSS/src/vos_sched.h
index 7dcd7a5..89cbf58 100644
--- a/CORE/VOSS/src/vos_sched.h
+++ b/CORE/VOSS/src/vos_sched.h
@@ -339,6 +339,9 @@
/*Fw log complete Event*/
vos_event_t fwLogsComplete;
+ v_U32_t wakelock_log_level;
+ v_U32_t connectivity_log_level;
+ v_U32_t packet_stats_log_level;
} VosContextType, *pVosContextType;