diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index fbc147a6de..fe912809f8 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -4827,6 +4827,52 @@ enum dot11p_mode {
#define CFG_RX_WAKELOCK_TIMEOUT_MIN (0)
#define CFG_RX_WAKELOCK_TIMEOUT_MAX (100)
+/*
+ *
+ * g_max_sched_scan_plan_int - pno sched max scan plan interval.
+ * @Min: 1
+ * @Max: 7200
+ * @Default: 3600
+ *
+ * This ini is used to set max sched scan plan interval for pno scan
+ * (value in seconds).
+ *
+ * Related: gPNOScanSupport
+ *
+ * Supported Feature: PNO scan
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_MAX_SCHED_SCAN_PLAN_INT_NAME "g_max_sched_scan_plan_int"
+#define CFG_MAX_SCHED_SCAN_PLAN_INT_MIN (1)
+#define CFG_MAX_SCHED_SCAN_PLAN_INT_MAX (7200)
+#define CFG_MAX_SCHED_SCAN_PLAN_INT_DEFAULT (3600)
+
+/*
+ *
+ * g_max_sched_scan_plan_iterations - pno sched max scan plan iterations.
+ * @Min: 1
+ * @Max: 100
+ * @Default: 10
+ *
+ * This ini is used to set max sched scan plan iterations for pno scan
+ * (value in seconds).
+ *
+ * Related: gPNOScanSupport
+ *
+ * Supported Feature: PNO scan
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_NAME "g_max_sched_scan_plan_iterations"
+#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MIN (1)
+#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MAX (100)
+#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_DEFAULT (10)
+
/*---------------------------------------------------------------------------
Type declarations
-------------------------------------------------------------------------*/
@@ -5503,6 +5549,8 @@ struct hdd_config {
uint8_t sap_max_inactivity_override;
bool fw_timeout_crash;
uint32_t rx_wakelock_timeout;
+ uint32_t max_sched_scan_plan_interval;
+ uint32_t max_sched_scan_plan_iterations;
};
#define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var))
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index 8a828643f2..e92e511819 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/core/hdd/src/wlan_hdd_cfg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -4075,7 +4075,19 @@ REG_TABLE_ENTRY g_registry_table[] = {
VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
CFG_RX_WAKELOCK_TIMEOUT_DEFAULT,
CFG_RX_WAKELOCK_TIMEOUT_MIN,
- CFG_RX_WAKELOCK_TIMEOUT_MAX)
+ CFG_RX_WAKELOCK_TIMEOUT_MAX),
+ REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_INT_NAME, WLAN_PARAM_Integer,
+ struct hdd_config, max_sched_scan_plan_interval,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_MAX_SCHED_SCAN_PLAN_INT_DEFAULT,
+ CFG_MAX_SCHED_SCAN_PLAN_INT_MIN,
+ CFG_MAX_SCHED_SCAN_PLAN_INT_MAX),
+ REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_ITRNS_NAME, WLAN_PARAM_Integer,
+ struct hdd_config, max_sched_scan_plan_iterations,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+ CFG_MAX_SCHED_SCAN_PLAN_ITRNS_DEFAULT,
+ CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MIN,
+ CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MAX),
};
/**
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 81e1b45f0e..bf4b33a674 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -8684,6 +8684,41 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
#endif
};
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0)) || \
+ defined(CFG80211_MULTI_SCAN_PLAN_BACKPORT)) && \
+ defined(FEATURE_WLAN_SCAN_PNO)
+/**
+ * hdd_config_sched_scan_plans_to_wiphy() - configure sched scan plans to wiphy
+ * @wiphy: pointer to wiphy
+ * @config: pointer to config
+ *
+ * Return: None
+ */
+static void hdd_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy,
+ struct hdd_config *config)
+{
+ if (config->configPNOScanSupport) {
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+ wiphy->max_sched_scan_ssids = SIR_PNO_MAX_SUPP_NETWORKS;
+ wiphy->max_match_sets = SIR_PNO_MAX_SUPP_NETWORKS;
+ wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH;
+ wiphy->max_sched_scan_plans = SIR_PNO_MAX_PLAN_REQUEST;
+ if (config->max_sched_scan_plan_interval)
+ wiphy->max_sched_scan_plan_interval =
+ config->max_sched_scan_plan_interval;
+ if (config->max_sched_scan_plan_iterations)
+ wiphy->max_sched_scan_plan_iterations =
+ config->max_sched_scan_plan_iterations;
+ }
+}
+#else
+static void hdd_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy,
+ struct hdd_config *config)
+{
+}
+#endif
+
+
/**
* hdd_cfg80211_wiphy_alloc() - Allocate wiphy context
* @priv_size: Size of the hdd context.
@@ -8830,17 +8865,7 @@ int wlan_hdd_cfg80211_init(struct device *dev,
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
#endif
-#ifdef FEATURE_WLAN_SCAN_PNO
- if (pCfg->configPNOScanSupport) {
- wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
- wiphy->max_sched_scan_ssids = SIR_PNO_MAX_SUPP_NETWORKS;
- wiphy->max_match_sets = SIR_PNO_MAX_SUPP_NETWORKS;
- wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || defined(WITH_BACKPORTS)
- wiphy->max_sched_scan_plans = SIR_PNO_MAX_PLAN_REQUEST;
-#endif
- }
-#endif /*FEATURE_WLAN_SCAN_PNO */
+ hdd_config_sched_scan_plans_to_wiphy(wiphy, pCfg);
#if defined QCA_WIFI_FTM
if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) {
diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c
index 3e75abaaa8..7d8abfae0f 100644
--- a/core/hdd/src/wlan_hdd_scan.c
+++ b/core/hdd/src/wlan_hdd_scan.c
@@ -2298,6 +2298,70 @@ static QDF_STATUS wlan_hdd_is_pno_allowed(hdd_adapter_t *adapter)
}
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \
+ defined(CFG80211_MULTI_SCAN_PLAN_BACKPORT)) && \
+ defined(FEATURE_WLAN_SCAN_PNO)
+/**
+ * hdd_config_sched_scan_plan() - configures the sched scan plans
+ * from the framework.
+ * @pno_req: pointer to PNO scan request
+ * @request: pointer to scan request from framework
+ *
+ * Return: None
+ */
+static void hdd_config_sched_scan_plan(tpSirPNOScanReq pno_req,
+ struct cfg80211_sched_scan_request *request,
+ hdd_context_t *hdd_ctx)
+{
+ /*
+ * As of now max 2 scan plans were supported by firmware
+ * if number of scan plan supported by firmware increased below logic
+ * must change.
+ */
+ if (request->n_scan_plans == SIR_PNO_MAX_PLAN_REQUEST) {
+ pno_req->fast_scan_period =
+ request->scan_plans[0].interval * MSEC_PER_SEC;
+ pno_req->fast_scan_max_cycles =
+ request->scan_plans[0].iterations;
+ pno_req->slow_scan_period =
+ request->scan_plans[1].interval * MSEC_PER_SEC;
+ hdd_notice("Base scan interval: %d sec, scan cycles: %d, slow scan interval %d",
+ request->scan_plans[0].interval,
+ request->scan_plans[0].iterations,
+ request->scan_plans[1].interval);
+ } else if (request->n_scan_plans == 1) {
+ pno_req->fast_scan_period =
+ request->scan_plans[0].interval * MSEC_PER_SEC;
+ /*
+ * if only one scan plan is configured from framework
+ * then both fast and slow scan should be configured with the
+ * same value that is why fast scan cycles are hardcoded to one
+ */
+ pno_req->fast_scan_max_cycles = 1;
+ pno_req->slow_scan_period =
+ request->scan_plans[0].interval * MSEC_PER_SEC;
+ } else {
+ hdd_err("Invalid number of scan plans %d !!",
+ request->n_scan_plans);
+ }
+}
+#else
+static void hdd_config_sched_scan_plan(tpSirPNOScanReq pno_req,
+ struct cfg80211_sched_scan_request *request,
+ hdd_context_t *hdd_ctx)
+{
+ pno_req->fast_scan_period = request->interval;
+ pno_req->fast_scan_max_cycles =
+ hdd_ctx->config->configPNOScanTimerRepeatValue;
+ pno_req->slow_scan_period =
+ hdd_ctx->config->pno_slow_scan_multiplier *
+ pno_req->fast_scan_period;
+ hdd_notice("Base scan interval: %d sec PNOScanTimerRepeatValue: %d",
+ (request->interval / 1000),
+ hdd_ctx->config->configPNOScanTimerRepeatValue);
+}
+#endif
+
/**
* __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start
* @wiphy: Pointer to wiphy
@@ -2524,27 +2588,7 @@ static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy,
* switches slow_scan_period. This is less frequent scans and firmware
* shall be in slow_scan_period mode until next PNO Start.
*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || defined(WITH_BACKPORTS)
- if (WARN_ON(request->n_scan_plans > SIR_PNO_MAX_PLAN_REQUEST)) {
- ret = -EINVAL;
- goto error;
- }
-
- /* TBD: only one sched_scan plan we can support now, so we only
- * retrieve the first plan and ignore the rest of them.
- * If there are more than 1 sched_pan request we can support, the
- * PnoRequet structure will also need to be revised.
- */
- pPnoRequest->fast_scan_period = request->scan_plans[0].interval *
- MSEC_PER_SEC;
-#else
- pPnoRequest->fast_scan_period = request->interval;
-#endif
- pPnoRequest->fast_scan_max_cycles =
- config->configPNOScanTimerRepeatValue;
- pPnoRequest->slow_scan_period =
- config->pno_slow_scan_multiplier *
- pPnoRequest->fast_scan_period;
+ hdd_config_sched_scan_plan(pPnoRequest, request, pHddCtx);
hdd_info("Base scan interval: %d sec PNOScanTimerRepeatValue: %d",
(pPnoRequest->fast_scan_period / 1000),
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 9f7fbd7daf..598b0a6e68 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -2825,7 +2825,7 @@ typedef struct sAniIbssRouteTable {
/* Set PNO */
-#define SIR_PNO_MAX_PLAN_REQUEST 1
+#define SIR_PNO_MAX_PLAN_REQUEST 2
#define SIR_PNO_MAX_NETW_CHANNELS 26
#define SIR_PNO_MAX_NETW_CHANNELS_EX 60
#define SIR_PNO_MAX_SUPP_NETWORKS 16