Forráskód Böngészése

qcacld-3.0: Implement User defined OPM mode

Allow userspace to configure power save inactivity timeout and
opm speculative wake interval through vendor NL interface.
STA enters into power save mode(PM=1) after TX/RX inactivity of
time duration specified by QCA_WLAN_VENDOR_ATTR_CONFIG_PS_ITO
in milliseconds.

STA speculatively wakes up to look for buffered data by AP at
QCA_WLAN_VENDOR_ATTR_CONFIG_SPEC_WAKE_INTERVAL interval after
entering into power save. If configured zero, STA wakes up at
upcoming DTIM beacon.

Change-Id: I86cbd35d6f61ae600b4784bd95209fac62021941
CRs-Fixed: 3567042
Vishal Miskin 1 éve
szülő
commit
268783d48e

+ 15 - 2
core/hdd/inc/wlan_hdd_power.h

@@ -499,13 +499,26 @@ int wlan_hdd_ipv6_changed(struct notifier_block *nb,
  * hdd_set_power_config() - set power config to firmware
  * @hddctx: HDD context
  * @adapter: HDD adapter
- * @power: new power config value
+ * @opm_mode: pointer to vendor opm_mode
  *
  * Return: 0 on success; Errno on failure
  */
 int hdd_set_power_config(struct hdd_context *hddctx,
-			 struct hdd_adapter *adapter, uint8_t power);
+			 struct hdd_adapter *adapter,
+			 enum qca_wlan_vendor_opm_mode *opm_mode);
 
+/**
+ * hdd_set_power_config_params() - set power config parameters
+ * @hddctx: HDD context
+ * @adapter: HDD adapter
+ * @ps_ito: power save inactivitiy duration in ms
+ * @spec_wake: power save speculative wake duration in ms
+ *
+ * Return: 0 on success; Errno on failure
+ */
+int hdd_set_power_config_params(struct hdd_context *hddctx,
+				struct hdd_adapter *adapter,
+				uint16_t ps_ito, uint16_t spec_wake);
 #ifdef FEATURE_WLAN_DIAG_SUPPORT
 /**
  * hdd_wlan_suspend_resume_event()- send suspend/resume state

+ 69 - 8
core/hdd/src/wlan_hdd_cfg80211.c

@@ -8254,6 +8254,9 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_NSS] = {.type = NLA_U8 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT] = {
 		.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO] = {.type = NLA_U16 },
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL] = {
+		.type = NLA_U16 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE] = {
 		.type = NLA_U8 },
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS] = {.type = NLA_U8 },
@@ -9540,21 +9543,82 @@ hdd_config_udp_qos_upgrade_threshold(struct wlan_hdd_link_info *link_info,
 	return hdd_set_udp_qos_upgrade_config(adapter, priority);
 }
 
+static enum powersave_mode
+hdd_vendor_opm_to_pmo_opm(enum qca_wlan_vendor_opm_mode opm_mode)
+{
+	switch (opm_mode) {
+	case QCA_WLAN_VENDOR_OPM_MODE_DISABLE:
+		return PMO_PS_ADVANCED_POWER_SAVE_DISABLE;
+	case QCA_WLAN_VENDOR_OPM_MODE_ENABLE:
+		return PMO_PS_ADVANCED_POWER_SAVE_ENABLE;
+	case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED:
+		return PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED;
+	default:
+		hdd_debug("Invalid opm_mode: %d", opm_mode);
+		return PMO_PS_ADVANCED_POWER_SAVE_DISABLE;
+	}
+}
+
 static int hdd_config_power(struct wlan_hdd_link_info *link_info,
-			    const struct nlattr *attr)
+			    struct nlattr *tb[])
 {
 	struct hdd_adapter *adapter = link_info->adapter;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
-	uint8_t power;
+	struct wlan_objmgr_vdev *vdev;
+	enum qca_wlan_vendor_opm_mode opm_mode;
+	struct pmo_ps_params ps_params = {0};
+	struct nlattr *power_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER];
+	struct nlattr *opm_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT];
+	struct nlattr *ps_ito_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO];
+	struct nlattr *spec_wake_attr =
+		tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL];
+	int ret;
+
+	if (!power_attr && !opm_attr)
+		return 0;
+
+	if (power_attr && opm_attr) {
+		hdd_err_rl("Invalid OPM set attribute");
+		return -EINVAL;
+	}
 
 	if (!ucfg_pmo_get_default_power_save_mode(hdd_ctx->psoc)) {
 		hdd_err_rl("OPM power save is disabled in ini");
 		return -EINVAL;
 	}
 
-	power = nla_get_u8(attr);
+	opm_mode = power_attr ? nla_get_u8(power_attr) : nla_get_u8(opm_attr);
+	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED)
+		if (!ps_ito_attr || !spec_wake_attr) {
+			hdd_err_rl("Invalid User defined OPM attributes");
+			return -EINVAL;
+		}
+
+	ret = hdd_set_power_config(hdd_ctx, adapter, &opm_mode);
+	if (ret)
+		return ret;
+
+	ps_params.opm_mode = hdd_vendor_opm_to_pmo_opm(opm_mode);
+	if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) {
+		ps_params.ps_ito = nla_get_u16(ps_ito_attr);
+		ps_params.spec_wake = nla_get_u16(spec_wake_attr);
+		ret = hdd_set_power_config_params(hdd_ctx, adapter,
+						  ps_params.ps_ito,
+						  ps_params.spec_wake);
+		if (ret)
+			return ret;
+	}
 
-	return hdd_set_power_config(hdd_ctx, adapter, power);
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_POWER_ID);
+	if (vdev) {
+		ucfg_pmo_set_ps_params(vdev, &ps_params);
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID);
+	}
+
+	return 0;
 }
 
 static int hdd_config_stats_avg_factor(struct wlan_hdd_link_info *link_info,
@@ -11562,8 +11626,6 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_config_lro},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE,
 	 hdd_config_scan_enable},
-	{QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER,
-	 hdd_config_power},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR,
 	 hdd_config_stats_avg_factor},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME,
@@ -11630,8 +11692,6 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_set_dynamic_bw},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_NSS,
 	 hdd_set_nss},
-	{QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT,
-	 hdd_config_power},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE,
 	 hdd_config_udp_qos_upgrade_threshold},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY,
@@ -12392,6 +12452,7 @@ static const interdependent_setter_fn interdependent_setters[] = {
 	hdd_config_tx_rx_nss,
 	hdd_process_generic_set_cmd,
 	hdd_config_phy_mode,
+	hdd_config_power,
 };
 
 /**

+ 50 - 9
core/hdd/src/wlan_hdd_power.c

@@ -3397,9 +3397,31 @@ int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy,
 	return errno;
 }
 
+/**
+ * hdd_convert_opm_mode() - convert opm with equivalent wma opm
+ * @opm_mode: Optimized power management mode
+ *
+ * Return: enum wma_sta_ps_scheme_cfg
+ */
+static enum wma_sta_ps_scheme_cfg
+hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode)
+{
+	switch (opm_mode) {
+	case QCA_WLAN_VENDOR_OPM_MODE_DISABLE:
+		return WMA_STA_PS_OPM_CONSERVATIVE;
+	case QCA_WLAN_VENDOR_OPM_MODE_ENABLE:
+		return WMA_STA_PS_OPM_AGGRESSIVE;
+	case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED:
+		return WMA_STA_PS_USER_DEF;
+	default:
+		hdd_err("Invalid opm_mode: %d", opm_mode);
+		return WMA_STA_PS_OPM_CONSERVATIVE;
+	}
+}
+
 int hdd_set_power_config(struct hdd_context *hddctx,
 			 struct hdd_adapter *adapter,
-			 uint8_t power)
+			 enum qca_wlan_vendor_opm_mode *opm_mode)
 {
 	QDF_STATUS status;
 
@@ -3410,29 +3432,48 @@ int hdd_set_power_config(struct hdd_context *hddctx,
 		return -EINVAL;
 	}
 
-	if (power > PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED ||
-	    power < PMO_PS_ADVANCED_POWER_SAVE_DISABLE) {
-		hdd_err("invalid power value: %d", power);
+	if (*opm_mode > QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED ||
+	    *opm_mode < QCA_WLAN_VENDOR_OPM_MODE_DISABLE) {
+		hdd_err("invalid power value: %d", *opm_mode);
 		return -EINVAL;
 	}
 
 	if (ucfg_pmo_get_max_ps_poll(hddctx->psoc)) {
 		hdd_info("Disable advanced power save since max ps poll is enabled");
-		power = PMO_PS_ADVANCED_POWER_SAVE_DISABLE;
+		*opm_mode = QCA_WLAN_VENDOR_OPM_MODE_DISABLE;
 	}
 
-	status = wma_set_power_config(adapter->deflink->vdev_id, power);
+	status = wma_set_power_config(adapter->deflink->vdev_id,
+				      hdd_convert_opm_mode(*opm_mode));
 	if (status != QDF_STATUS_SUCCESS) {
 		hdd_err("failed to configure power: %d", status);
 		return -EINVAL;
 	}
 
-	/* cache latest userspace power save config to reapply after SSR */
-	ucfg_pmo_set_power_save_mode(hddctx->psoc, power);
-
 	return 0;
 }
 
+int hdd_set_power_config_params(struct hdd_context *hddctx,
+				struct hdd_adapter *adapter,
+				uint16_t ps_ito, uint16_t spec_wake)
+{
+	QDF_STATUS status;
+
+	status = wma_set_power_config_ito(adapter->deflink->vdev_id, ps_ito);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("failed to configure power ito: %d", status);
+		return -EINVAL;
+	}
+
+	status = wma_set_power_config_spec_wake(adapter->deflink->vdev_id,
+						spec_wake);
+	if (status != QDF_STATUS_SUCCESS) {
+		hdd_err("failed to configure power spec wake: %d", status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
 
 #ifdef WLAN_SUSPEND_RESUME_TEST
 static struct net_device *g_dev;

+ 31 - 1
core/wma/inc/wma_api.h

@@ -101,6 +101,17 @@ struct wma_ps_params {
 	uint16_t spec_wake;
 };
 
+/**
+ * enum wma_sta_ps_scheme_cfg - STA power save schemes
+ * @WMA_STA_PS_OPM_CONSERVATIVE - Conservative OPM mode
+ * @WMA_STA_PS_OPM_AGGRESSIVE - Aggressive OPM mode
+ * @WMA_STA_PS_USER_DEF - User defined OPM mode
+ */
+enum wma_sta_ps_scheme_cfg {
+	WMA_STA_PS_OPM_CONSERVATIVE = 0,
+	WMA_STA_PS_OPM_AGGRESSIVE = 1,
+	WMA_STA_PS_USER_DEF = 2,
+};
 
 #define VDEV_CMD 1
 #define PDEV_CMD 2
@@ -446,7 +457,26 @@ QDF_STATUS wma_send_coex_config_cmd(WMA_HANDLE wma_handle,
  *
  * Return: QDF_STATUS_SUCCESS on success, error number otherwise
  */
-QDF_STATUS wma_set_power_config(uint8_t vdev_id, enum powersave_mode power);
+QDF_STATUS wma_set_power_config(uint8_t vdev_id,
+				enum wma_sta_ps_scheme_cfg power);
+
+/**
+ * wma_set_power_config_ito() - update power save inactivity timeout
+ * @vdev_id:	the Id of the vdev to configure
+ * @ps_ito:	new power save inactivity timeout in milliseconds
+ *
+ * Return: QDF_STATUS_SUCCESS on success, error number otherwise
+ */
+QDF_STATUS wma_set_power_config_ito(uint8_t vdev_id, uint16_t ps_ito);
+
+/**
+ * wma_set_power_config_spec_wake() - update opm speculative wake interval
+ * @vdev_id:	the Id of the vdev to configure
+ * @spec_wake:	new opm speculative wake interval in milliseconds
+ *
+ * Return: QDF_STATUS_SUCCESS on success, error number otherwise
+ */
+QDF_STATUS wma_set_power_config_spec_wake(uint8_t vdev_id, uint16_t spec_wake);
 
 #ifdef FEATURE_WLAN_D0WOW
 static inline bool wma_d0_wow_is_supported(void)

+ 53 - 2
core/wma/src/wma_power.c

@@ -810,7 +810,30 @@ void wma_disable_sta_ps_mode(tpDisablePsParams ps_req)
 	}
 }
 
-QDF_STATUS wma_set_power_config(uint8_t vdev_id, enum powersave_mode power)
+/**
+ * wma_convert_opm_mode() - convert opm with equivalent wmi opm
+ * @opm_mode: Optimized power management mode
+ *
+ * Return: enum wmi_sta_ps_scheme_cfg
+ */
+static enum wmi_sta_ps_scheme_cfg
+wma_convert_opm_mode(enum wma_sta_ps_scheme_cfg opm_mode)
+{
+	switch (opm_mode) {
+	case WMA_STA_PS_OPM_CONSERVATIVE:
+		return WMI_STA_PS_OPM_CONSERVATIVE;
+	case WMA_STA_PS_OPM_AGGRESSIVE:
+		return WMI_STA_PS_OPM_AGGRESSIVE;
+	case WMA_STA_PS_USER_DEF:
+		return WMI_STA_PS_USER_DEF;
+	default:
+		wma_err("Invalid opm_mode: %d", opm_mode);
+		return WMI_STA_PS_OPM_CONSERVATIVE;
+	}
+}
+
+QDF_STATUS wma_set_power_config(uint8_t vdev_id,
+				enum wma_sta_ps_scheme_cfg power)
 {
 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
 
@@ -821,7 +844,35 @@ QDF_STATUS wma_set_power_config(uint8_t vdev_id, enum powersave_mode power)
 	return wma_unified_set_sta_ps_param(wma->wmi_handle,
 					    vdev_id,
 					    WMI_STA_PS_ENABLE_OPM,
-					    power);
+					    wma_convert_opm_mode(power));
+}
+
+QDF_STATUS wma_set_power_config_ito(uint8_t vdev_id, uint16_t ps_ito)
+{
+	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+
+	if (!wma) {
+		wma_err("wma_handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
+					   WMI_STA_PS_PARAM_INACTIVITY_TIME,
+					   ps_ito);
+}
+
+QDF_STATUS wma_set_power_config_spec_wake(uint8_t vdev_id, uint16_t spec_wake)
+{
+	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+
+	if (!wma) {
+		wma_err("wma_handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
+			WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL,
+			spec_wake);
 }
 
 void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req)