Ver código fonte

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
Dustin Brown 8 anos atrás
pai
commit
d932248600

+ 13 - 2
core/hdd/inc/wlan_hdd_main.h

@@ -1305,6 +1305,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  */
@@ -1581,8 +1593,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 */

+ 2 - 0
core/hdd/src/wlan_hdd_driver_ops.c

@@ -637,6 +637,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;
 

+ 32 - 20
core/hdd/src/wlan_hdd_power.c

@@ -1701,19 +1701,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);
 }
 
@@ -1732,30 +1733,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 control path scheduler */
@@ -1780,14 +1789,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) &&
@@ -1810,15 +1818,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;
 }
 
 /**

+ 117 - 2
core/hdd/src/wlan_hdd_wext.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -384,6 +384,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>
@@ -1080,6 +1103,81 @@ void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length,
 	*length = len + 1;
 }
 
+/**
+ * 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
@@ -7616,6 +7714,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);
@@ -8083,8 +8193,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,
@@ -11154,6 +11265,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,