qcacmn: Antenna power save when 1x1 client is connected

Enable Green AP when only 1x1 clients are connected.

Change-Id: I5dd180bb56eaba337454dbe1d3a7f8135be9102f
diff --git a/umac/green_ap/core/src/wlan_green_ap_main.c b/umac/green_ap/core/src/wlan_green_ap_main.c
index 492778a..f0fc6b7 100644
--- a/umac/green_ap/core/src/wlan_green_ap_main.c
+++ b/umac/green_ap/core/src/wlan_green_ap_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -183,6 +183,15 @@
 			green_ap_ctx->num_nodes--;
 		break;
 
+	case WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT:
+		green_ap_ctx->num_nodes_multistream++;
+		break;
+
+	case WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT:
+		if (green_ap_ctx->num_nodes_multistream)
+			green_ap_ctx->num_nodes_multistream--;
+		break;
+
 	case WLAN_GREEN_AP_PS_START_EVENT:
 	case WLAN_GREEN_AP_PS_STOP_EVENT:
 	case WLAN_GREEN_AP_PS_ON_EVENT:
@@ -216,8 +225,13 @@
 	/* handle the green ap ps state */
 	switch (green_ap_ctx->ps_state) {
 	case WLAN_GREEN_AP_PS_IDLE_STATE:
-		if (green_ap_ctx->num_nodes) {
-			/* Active nodes present, Switchoff the power save */
+		if ((green_ap_ctx->num_nodes &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
+		    (green_ap_ctx->num_nodes_multistream &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
+			/*
+			 * Multistream nodes present, switchoff the power save
+			 */
 			green_ap_info("Transition to OFF from IDLE");
 			wlan_green_ap_ps_event_state_update(
 					green_ap_ctx,
@@ -236,7 +250,10 @@
 		break;
 
 	case WLAN_GREEN_AP_PS_OFF_STATE:
-		if (!green_ap_ctx->num_nodes) {
+		if ((!green_ap_ctx->num_nodes &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
+		    (!green_ap_ctx->num_nodes_multistream &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
 			green_ap_info("Transition to WAIT from OFF");
 			wlan_green_ap_ps_event_state_update(
 						green_ap_ctx,
@@ -248,7 +265,10 @@
 		break;
 
 	case WLAN_GREEN_AP_PS_WAIT_STATE:
-		if (!green_ap_ctx->num_nodes) {
+		if ((!green_ap_ctx->num_nodes &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
+		    (!green_ap_ctx->num_nodes_multistream &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
 			if ((channel == 0) || (channel_flags == 0)) {
 				/*
 				 * Stay in the current state and restart the
@@ -282,7 +302,10 @@
 		break;
 
 	case WLAN_GREEN_AP_PS_ON_STATE:
-		if (green_ap_ctx->num_nodes) {
+		if ((green_ap_ctx->num_nodes &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
+		    (green_ap_ctx->num_nodes_multistream &&
+		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
 			qdf_timer_stop(&green_ap_ctx->ps_timer);
 			if (green_ap_tx_ops->ps_on_off_send(
 					green_ap_ctx->pdev, false, pdev_id)) {
diff --git a/umac/green_ap/core/src/wlan_green_ap_main_i.h b/umac/green_ap/core/src/wlan_green_ap_main_i.h
index b29205e..664531d 100644
--- a/umac/green_ap/core/src/wlan_green_ap_main_i.h
+++ b/umac/green_ap/core/src/wlan_green_ap_main_i.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -83,6 +83,8 @@
  * @WLAN_GREEN_AP_PS_STOP_EVENT  - Stop
  * @WLAN_GREEN_AP_ADD_STA_EVENT  - Sta assoc
  * @WLAN_GREEN_AP_DEL_STA_EVENT  - Sta disassoc
+ * @WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT - Multistream sta assoc
+ * @WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT - Multistream sta disassoc
  * @WLAN_GREEN_AP_PS_ON_EVENT    - PS on
  * @WLAN_GREEN_AP_PS_OFF_EVENT   - PS off
  */
@@ -91,6 +93,8 @@
 	WLAN_GREEN_AP_PS_STOP_EVENT,
 	WLAN_GREEN_AP_ADD_STA_EVENT,
 	WLAN_GREEN_AP_DEL_STA_EVENT,
+	WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT,
+	WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT,
 	WLAN_GREEN_AP_PS_ON_EVENT,
 	WLAN_GREEN_AP_PS_WAIT_EVENT,
 };
@@ -99,9 +103,11 @@
  * struct wlan_pdev_green_ap_ctx - green ap context
  * @pdev - Pdev pointer
  * @ps_enable  - Enable PS
+ * @ps_mode - No sta or Multistream sta mode
  * @ps_on_time - PS on time, once enabled
  * @ps_trans_time - PS transition time
  * @num_nodes - Number of nodes associated to radio
+ * @num_nodes_multistream - Multistream nodes associated to radio
  * @ps_state - PS state
  * @ps_event - PS event
  * @ps_timer - Timer
@@ -111,9 +117,11 @@
 struct wlan_pdev_green_ap_ctx {
 	struct wlan_objmgr_pdev *pdev;
 	uint8_t ps_enable;
+	uint8_t ps_mode;
 	uint8_t ps_on_time;
 	uint32_t ps_trans_time;
 	uint32_t num_nodes;
+	uint32_t num_nodes_multistream;
 	enum wlan_green_ap_ps_state ps_state;
 	enum wlan_green_ap_ps_event ps_event;
 	qdf_timer_t ps_timer;
diff --git a/umac/green_ap/dispatcher/inc/wlan_green_ap_api.h b/umac/green_ap/dispatcher/inc/wlan_green_ap_api.h
index a4877bd..70eb595 100644
--- a/umac/green_ap/dispatcher/inc/wlan_green_ap_api.h
+++ b/umac/green_ap/dispatcher/inc/wlan_green_ap_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -27,6 +27,10 @@
 #include <wlan_objmgr_pdev_obj.h>
 #include <qdf_status.h>
 
+/* Green ap mode of operation */
+#define WLAN_GREEN_AP_MODE_NO_STA       1 /* PS if no sta connected */
+#define WLAN_GREEN_AP_MODE_NUM_STREAM   2 /* PS if 1x1 clients only connected */
+
 /**
  * struct wlan_green_ap_egap_params - enhance green ap params
  * @fw_egap_support: fw enhance green ap support
@@ -110,6 +114,16 @@
 QDF_STATUS wlan_green_ap_add_sta(struct wlan_objmgr_pdev *pdev);
 
 /**
+ * wlan_green_ap_add_multistream_sta() - On association
+ * @pdev: pdev pointer
+ *
+ * Call this function when new multistream node is associated
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS wlan_green_ap_add_multistream_sta(struct wlan_objmgr_pdev *pdev);
+
+/**
  * wlan_green_ap_del_sta() - On disassociation
  * @pdev: pdev pointer
  *
@@ -120,6 +134,16 @@
 QDF_STATUS wlan_green_ap_del_sta(struct wlan_objmgr_pdev *pdev);
 
 /**
+ * wlan_green_ap_del_multistream_sta() - On disassociation
+ * @pdev: pdev pointer
+ *
+ * Call this function when new multistream node is disassociated
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS wlan_green_ap_del_multistream_sta(struct wlan_objmgr_pdev *pdev);
+
+/**
  * wlan_green_ap_is_ps_enabled() - is power save enabled
  * @pdev: pdev pointer
  *
diff --git a/umac/green_ap/dispatcher/src/wlan_green_ap_api.c b/umac/green_ap/dispatcher/src/wlan_green_ap_api.c
index e8cb236..70cd45b 100644
--- a/umac/green_ap/dispatcher/src/wlan_green_ap_api.c
+++ b/umac/green_ap/dispatcher/src/wlan_green_ap_api.c
@@ -80,7 +80,9 @@
 
 	green_ap_ctx->ps_state = WLAN_GREEN_AP_PS_IDLE_STATE;
 	green_ap_ctx->ps_event = WLAN_GREEN_AP_PS_WAIT_EVENT;
+	green_ap_ctx->ps_mode = WLAN_GREEN_AP_MODE_NO_STA;
 	green_ap_ctx->num_nodes = 0;
+	green_ap_ctx->num_nodes_multistream = 0;
 	green_ap_ctx->ps_on_time = WLAN_GREEN_AP_PS_ON_TIME;
 	green_ap_ctx->ps_trans_time = WLAN_GREEN_AP_PS_TRANS_TIME;
 
@@ -361,6 +363,36 @@
 				      WLAN_GREEN_AP_ADD_STA_EVENT);
 }
 
+QDF_STATUS wlan_green_ap_add_multistream_sta(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
+
+	if (!pdev) {
+		green_ap_err("pdev context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
+			pdev, WLAN_UMAC_COMP_GREEN_AP);
+	if (!green_ap_ctx) {
+		green_ap_err("green ap context obtained is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	green_ap_debug("Green AP add multistream sta received");
+
+	qdf_spin_lock_bh(&green_ap_ctx->lock);
+	if (wlan_is_egap_enabled(green_ap_ctx)) {
+		qdf_spin_unlock_bh(&green_ap_ctx->lock);
+		green_ap_debug("enhanced green ap support is enabled");
+		return QDF_STATUS_SUCCESS;
+	}
+	qdf_spin_unlock_bh(&green_ap_ctx->lock);
+
+	return wlan_green_ap_state_mc(green_ap_ctx,
+			WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT);
+}
+
 QDF_STATUS wlan_green_ap_del_sta(struct wlan_objmgr_pdev *pdev)
 {
 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
@@ -391,6 +423,36 @@
 				      WLAN_GREEN_AP_DEL_STA_EVENT);
 }
 
+QDF_STATUS wlan_green_ap_del_multistream_sta(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
+
+	if (!pdev) {
+		green_ap_err("pdev context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
+			pdev, WLAN_UMAC_COMP_GREEN_AP);
+	if (!green_ap_ctx) {
+		green_ap_err("green ap context obtained is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	green_ap_debug("Green AP del multistream sta received");
+
+	qdf_spin_lock_bh(&green_ap_ctx->lock);
+	if (wlan_is_egap_enabled(green_ap_ctx)) {
+		qdf_spin_unlock_bh(&green_ap_ctx->lock);
+		green_ap_info("enhanced green ap support is enabled");
+		return QDF_STATUS_SUCCESS;
+	}
+	qdf_spin_unlock_bh(&green_ap_ctx->lock);
+
+	return wlan_green_ap_state_mc(green_ap_ctx,
+			WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT);
+}
+
 bool wlan_green_ap_is_ps_enabled(struct wlan_objmgr_pdev *pdev)
 {
 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
diff --git a/umac/green_ap/dispatcher/src/wlan_green_ap_ucfg_api.c b/umac/green_ap/dispatcher/src/wlan_green_ap_ucfg_api.c
index 1885fa0..5d84587 100644
--- a/umac/green_ap/dispatcher/src/wlan_green_ap_ucfg_api.c
+++ b/umac/green_ap/dispatcher/src/wlan_green_ap_ucfg_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -79,6 +79,11 @@
 	}
 
 	green_ap_ctx->ps_enable = value;
+	if (value == WLAN_GREEN_AP_MODE_NUM_STREAM)
+		green_ap_ctx->ps_mode = WLAN_GREEN_AP_MODE_NUM_STREAM;
+	else
+		green_ap_ctx->ps_mode = WLAN_GREEN_AP_MODE_NO_STA;
+
 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
 
 	return QDF_STATUS_SUCCESS;