summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDustin Brown <dustinb@codeaurora.org>2017-01-09 12:46:03 -0800
committerqcabuildsw <qcabuildsw@localhost>2017-01-18 02:20:55 -0800
commitaa6a64449b3c667f01bae69cf77f328f60d9fbd6 (patch)
tree0f153140f81ce765c331361b9d6a28dce0d0a6ae
parent597ee2178a8144fd6d9123ab51bccff548ef5b9f (diff)
qcacld-3.0: Add internal ioctl to get suspend/resume stats
To assist in testing scenarios, add an ioctl that prints the suspend/resume stats since the driver was last loaded. Change-Id: I48e60dd0420e658ea43de721e9802f999b653bd3 CRs-Fixed: 1109141
-rw-r--r--core/hdd/inc/wlan_hdd_main.h15
-rw-r--r--core/hdd/src/wlan_hdd_driver_ops.c4
-rw-r--r--core/hdd/src/wlan_hdd_power.c52
-rw-r--r--core/hdd/src/wlan_hdd_wext.c117
4 files changed, 164 insertions, 24 deletions
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 241b9fd82527..356f606cdbf2 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1310,6 +1310,18 @@ enum suspend_fail_reason {
SUSPEND_FAIL_MAX_COUNT
};
+/**
+ * suspend_resume_stats - Collection of counters for suspend/resume events
+ * @suspends: number of suspends completed
+ * @resumes: number of resumes completed
+ * @suspend_fail: counters for failed suspend reasons
+ */
+struct suspend_resume_stats {
+ uint32_t suspends;
+ uint32_t resumes;
+ uint32_t suspend_fail[SUSPEND_FAIL_MAX_COUNT];
+};
+
/** Adapter structure definition */
struct hdd_context_s {
/** Global CDS context */
@@ -1587,8 +1599,7 @@ struct hdd_context_s {
bool update_mac_addr_to_fw;
struct acs_dfs_policy acs_policy;
uint16_t wmi_max_len;
- /* counters for failed suspend reasons */
- uint32_t suspend_fail_stats[SUSPEND_FAIL_MAX_COUNT];
+ struct suspend_resume_stats suspend_resume_stats;
struct hdd_runtime_pm_context runtime_context;
bool roaming_in_progress;
/* bit map to set/reset TDLS by different sources */
diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c
index 332bb3531005..f2e714d3fc9d 100644
--- a/core/hdd/src/wlan_hdd_driver_ops.c
+++ b/core/hdd/src/wlan_hdd_driver_ops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -635,6 +635,8 @@ static int __wlan_hdd_bus_suspend_noirq(void)
if (err)
goto resume_hif_noirq;
+ hdd_ctx->suspend_resume_stats.suspends++;
+
hdd_info("suspend_noirq done");
return 0;
diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c
index d31d92f74a60..3a63ba7b6e7c 100644
--- a/core/hdd/src/wlan_hdd_power.c
+++ b/core/hdd/src/wlan_hdd_power.c
@@ -1710,19 +1710,20 @@ static int wlan_hdd_set_powersave(hdd_adapter_t *adapter,
static void wlan_hdd_print_suspend_fail_stats(hdd_context_t *hdd_ctx)
{
+ struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats;
hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d",
- hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_IPA],
- hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_RADAR],
- hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_ROAM],
- hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_SCAN],
- hdd_ctx->suspend_fail_stats[SUSPEND_FAIL_INITIAL_WAKEUP]);
+ stats->suspend_fail[SUSPEND_FAIL_IPA],
+ stats->suspend_fail[SUSPEND_FAIL_RADAR],
+ stats->suspend_fail[SUSPEND_FAIL_ROAM],
+ stats->suspend_fail[SUSPEND_FAIL_SCAN],
+ stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]);
}
void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx,
enum suspend_fail_reason reason)
{
wlan_hdd_print_suspend_fail_stats(hdd_ctx);
- hdd_ctx->suspend_fail_stats[reason]++;
+ hdd_ctx->suspend_resume_stats.suspend_fail[reason]++;
wlan_hdd_print_suspend_fail_stats(hdd_ctx);
}
@@ -1741,30 +1742,38 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
hdd_adapter_t *pAdapter;
hdd_adapter_list_node_t *pAdapterNode, *pNext;
QDF_STATUS status = QDF_STATUS_SUCCESS;
- int result;
+ int exit_code;
p_cds_sched_context cds_sched_context = get_cds_sched_ctxt();
ENTER();
- if (cds_is_driver_recovering())
- return 0;
+ if (cds_is_driver_recovering()) {
+ hdd_info("Driver is recovering; Skipping resume");
+ exit_code = 0;
+ goto exit_with_code;
+ }
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
hdd_err("Command not allowed in FTM mode");
- return -EINVAL;
+ exit_code = -EINVAL;
+ goto exit_with_code;
}
- result = wlan_hdd_validate_context(pHddCtx);
- if (0 != result)
- return result;
+ exit_code = wlan_hdd_validate_context(pHddCtx);
+ if (exit_code) {
+ hdd_err("Invalid HDD context");
+ goto exit_with_code;
+ }
mutex_lock(&pHddCtx->iface_change_lock);
if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) {
mutex_unlock(&pHddCtx->iface_change_lock);
- hdd_info("Driver Module not enabled return success");
- return 0;
+ hdd_info("Driver is not enabled; Skipping resume");
+ exit_code = 0;
+ goto exit_with_code;
}
mutex_unlock(&pHddCtx->iface_change_lock);
+
pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM);
/* Resume MC thread */
@@ -1789,14 +1798,13 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
if (true != pHddCtx->isSchedScanUpdatePending) {
qdf_spin_unlock(&pHddCtx->sched_scan_lock);
hdd_info("Return resume is not due to PNO indication");
- return 0;
+ goto exit_with_success;
}
/* Reset flag to avoid updatating cfg80211 data old results again */
pHddCtx->isSchedScanUpdatePending = false;
qdf_spin_unlock(&pHddCtx->sched_scan_lock);
status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
-
while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
pAdapter = pAdapterNode->pAdapter;
if ((NULL != pAdapter) &&
@@ -1819,15 +1827,19 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
}
hdd_info("cfg80211 scan result database updated");
- EXIT();
- return result;
+ goto exit_with_success;
}
status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
pAdapterNode = pNext;
}
+exit_with_success:
+ pHddCtx->suspend_resume_stats.resumes++;
+ exit_code = 0;
+
+exit_with_code:
EXIT();
- return result;
+ return exit_code;
}
/**
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index c46b8d8c79a6..9d642dfddb0b 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -408,6 +408,29 @@ static const hdd_freq_chan_map_t freq_chan_map[] = {
#define WE_GET_WMM_STATUS 4
#define WE_GET_CHANNEL_LIST 5
#define WE_GET_RSSI 6
+
+/*
+ * <ioctl>
+ * getSuspendStats - Get suspend/resume stats
+ *
+ * @INPUT: None
+ *
+ * @OUTPUT: character string containing formatted suspend/resume stats
+ *
+ * This ioctl is used to get suspend/resume stats formatted for display.
+ * Currently it includes suspend/resume counts, wow wake up reasons, and
+ * suspend fail reasons.
+ *
+ * @E.g: iwpriv wlan0 getSuspendStats
+ * iwpriv wlan0 getSuspendStats
+ *
+ * Supported Feature: suspend/resume
+ *
+ * Usage: Internal
+ *
+ * </ioctl>
+ */
+#define WE_GET_SUSPEND_RESUME_STATS 7
#ifdef FEATURE_WLAN_TDLS
/*
* <ioctl>
@@ -1293,6 +1316,81 @@ void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length,
}
/**
+ * wlan_hdd_write_suspend_resume_stats() - Writes suspend/resume stats to buffer
+ * @hdd_ctx: The Hdd context owning the stats to be written
+ * @buffer: The char buffer to write to
+ * @max_len: The maximum number of chars to write
+ *
+ * This assumes hdd_ctx has already been validated, and buffer is not NULL.
+ *
+ * Return - length of written content, negative number on error
+ */
+static int wlan_hdd_write_suspend_resume_stats(hdd_context_t *hdd_ctx,
+ char *buffer, uint16_t max_len)
+{
+ QDF_STATUS status;
+ struct suspend_resume_stats *sr_stats;
+ struct sir_wake_lock_stats wow_stats;
+
+ sr_stats = &hdd_ctx->suspend_resume_stats;
+
+ status = wma_get_wakelock_stats(&wow_stats);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ hdd_err("Failed to get WoW stats");
+ return qdf_status_to_os_return(status);
+ }
+
+ return scnprintf(buffer, max_len,
+ "\n"
+ "Suspends: %u\n"
+ "Resumes: %u\n"
+ "\n"
+ "Suspend Fail Reasons\n"
+ "\tIPA: %u\n"
+ "\tRadar: %u\n"
+ "\tRoam: %u\n"
+ "\tScan: %u\n"
+ "\tInitial Wakeup: %u\n"
+ "\n"
+ "WoW Wake Reasons\n"
+ "\tunicast: %u\n"
+ "\tbroadcast: %u\n"
+ "\tIPv4 multicast: %u\n"
+ "\tIPv6 multicast: %u\n"
+ "\tIPv6 multicast RA: %u\n"
+ "\tIPv6 multicast NS: %u\n"
+ "\tIPv6 multicast NA: %u\n"
+ "\tICMPv4: %u\n"
+ "\tICMPv6: %u\n"
+ "\tRSSI Breach: %u\n"
+ "\tLow RSSI: %u\n"
+ "\tG-Scan: %u\n"
+ "\tPNO Complete: %u\n"
+ "\tPNO Match: %u\n",
+ sr_stats->suspends,
+ sr_stats->resumes,
+ sr_stats->suspend_fail[SUSPEND_FAIL_IPA],
+ sr_stats->suspend_fail[SUSPEND_FAIL_RADAR],
+ sr_stats->suspend_fail[SUSPEND_FAIL_ROAM],
+ sr_stats->suspend_fail[SUSPEND_FAIL_SCAN],
+ sr_stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP],
+ wow_stats.wow_ucast_wake_up_count,
+ wow_stats.wow_bcast_wake_up_count,
+ wow_stats.wow_ipv4_mcast_wake_up_count,
+ wow_stats.wow_ipv6_mcast_wake_up_count,
+ wow_stats.wow_ipv6_mcast_ra_stats,
+ wow_stats.wow_ipv6_mcast_ns_stats,
+ wow_stats.wow_ipv6_mcast_na_stats,
+ wow_stats.wow_icmpv4_count,
+ wow_stats.wow_icmpv6_count,
+ wow_stats.wow_rssi_breach_wake_up_count,
+ wow_stats.wow_low_rssi_wake_up_count,
+ wow_stats.wow_gscan_wake_up_count,
+ wow_stats.wow_pno_complete_wake_up_count,
+ wow_stats.wow_pno_match_wake_up_count);
+}
+
+/**
* hdd_wlan_list_fw_profile() - Get fw profiling points
* @length: Size of the data copied
* @buffer: Pointer to char buffer.
@@ -7871,6 +7969,18 @@ static int __iw_get_char_setnone(struct net_device *dev,
break;
}
+ case WE_GET_SUSPEND_RESUME_STATS:
+ {
+ ret = wlan_hdd_write_suspend_resume_stats(hdd_ctx, extra,
+ WE_MAX_STR_LEN);
+ if (ret >= 0) {
+ wrqu->data.length = ret;
+ ret = 0;
+ }
+
+ break;
+ }
+
case WE_LIST_FW_PROFILE:
hdd_wlan_list_fw_profile(&(wrqu->data.length),
extra, WE_MAX_STR_LEN);
@@ -8338,8 +8448,9 @@ static int __iw_get_char_setnone(struct net_device *dev,
break;
}
}
+
EXIT();
- return 0;
+ return ret;
}
static int iw_get_char_setnone(struct net_device *dev,
@@ -11741,6 +11852,10 @@ static const struct iw_priv_args we_private_args[] = {
0,
IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN,
"getStats"},
+ {WE_GET_SUSPEND_RESUME_STATS,
+ 0,
+ IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN,
+ "getSuspendStats"},
{WE_LIST_FW_PROFILE,
0,
IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN,