xref: /wlan-driver/qca-wifi-host-cmn/ipa/core/src/wlan_ipa_rm.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /* Include Files */
21*5113495bSYour Name #include "qdf_delayed_work.h"
22*5113495bSYour Name #include "wlan_ipa_core.h"
23*5113495bSYour Name #include "wlan_ipa_main.h"
24*5113495bSYour Name #include "cdp_txrx_ipa.h"
25*5113495bSYour Name #include "host_diag_core_event.h"
26*5113495bSYour Name #include "wlan_reg_services_api.h"
27*5113495bSYour Name 
wlan_ipa_set_perf_level(struct wlan_ipa_priv * ipa_ctx,uint64_t tx_packets,uint64_t rx_packets)28*5113495bSYour Name QDF_STATUS wlan_ipa_set_perf_level(struct wlan_ipa_priv *ipa_ctx,
29*5113495bSYour Name 				    uint64_t tx_packets,
30*5113495bSYour Name 				    uint64_t rx_packets)
31*5113495bSYour Name {
32*5113495bSYour Name 	int ret;
33*5113495bSYour Name 	uint32_t next_bw;
34*5113495bSYour Name 	uint64_t total_packets = tx_packets + rx_packets;
35*5113495bSYour Name 
36*5113495bSYour Name 	if ((!wlan_ipa_is_enabled(ipa_ctx->config)) ||
37*5113495bSYour Name 		(!wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config)))
38*5113495bSYour Name 		return 0;
39*5113495bSYour Name 
40*5113495bSYour Name 	if (total_packets > (ipa_ctx->config->bus_bw_high / 2))
41*5113495bSYour Name 		next_bw = ipa_ctx->config->ipa_bw_high;
42*5113495bSYour Name 	else if (total_packets > (ipa_ctx->config->bus_bw_medium / 2))
43*5113495bSYour Name 		next_bw = ipa_ctx->config->ipa_bw_medium;
44*5113495bSYour Name 	else
45*5113495bSYour Name 		next_bw = ipa_ctx->config->ipa_bw_low;
46*5113495bSYour Name 
47*5113495bSYour Name 	if (ipa_ctx->curr_cons_bw != next_bw) {
48*5113495bSYour Name 		ipa_debug("Requesting IPA perf curr: %d, next: %d",
49*5113495bSYour Name 			  ipa_ctx->curr_cons_bw, next_bw);
50*5113495bSYour Name 		ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc,
51*5113495bSYour Name 					     QDF_IPA_CLIENT_WLAN1_CONS,
52*5113495bSYour Name 					     next_bw, ipa_ctx->hdl);
53*5113495bSYour Name 		if (ret) {
54*5113495bSYour Name 			ipa_err("RM CONS set perf profile failed: %d", ret);
55*5113495bSYour Name 
56*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
57*5113495bSYour Name 		}
58*5113495bSYour Name 		ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc,
59*5113495bSYour Name 					     QDF_IPA_CLIENT_WLAN1_PROD,
60*5113495bSYour Name 					     next_bw, ipa_ctx->hdl);
61*5113495bSYour Name 		if (ret) {
62*5113495bSYour Name 			ipa_err("RM PROD set perf profile failed: %d", ret);
63*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
64*5113495bSYour Name 		}
65*5113495bSYour Name 		ipa_ctx->curr_cons_bw = next_bw;
66*5113495bSYour Name 		ipa_ctx->stats.num_cons_perf_req++;
67*5113495bSYour Name 	}
68*5113495bSYour Name 
69*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
70*5113495bSYour Name }
71*5113495bSYour Name 
72*5113495bSYour Name #ifdef QCA_IPA_LL_TX_FLOW_CONTROL
73*5113495bSYour Name static inline
wlan_ipa_update_perf_level(struct wlan_ipa_priv * ipa_ctx,int client)74*5113495bSYour Name QDF_STATUS wlan_ipa_update_perf_level(struct wlan_ipa_priv *ipa_ctx, int client)
75*5113495bSYour Name {
76*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
77*5113495bSYour Name 	qdf_freq_t low_2g, high_2g;
78*5113495bSYour Name 
79*5113495bSYour Name 	wlan_reg_get_freq_range(pdev, &low_2g, &high_2g, NULL, NULL);
80*5113495bSYour Name 
81*5113495bSYour Name 	if (low_2g != 0 || high_2g != 0) {
82*5113495bSYour Name 		return cdp_ipa_set_perf_level(
83*5113495bSYour Name 				ipa_ctx->dp_soc,
84*5113495bSYour Name 				client,
85*5113495bSYour Name 				WLAN_IPA_MAX_BANDWIDTH_2G, ipa_ctx->hdl);
86*5113495bSYour Name 	} else {
87*5113495bSYour Name 		return cdp_ipa_set_perf_level(
88*5113495bSYour Name 				ipa_ctx->dp_soc,
89*5113495bSYour Name 				client,
90*5113495bSYour Name 				WLAN_IPA_MAX_BANDWIDTH, ipa_ctx->hdl);
91*5113495bSYour Name 	}
92*5113495bSYour Name }
93*5113495bSYour Name #else
94*5113495bSYour Name static inline
wlan_ipa_update_perf_level(struct wlan_ipa_priv * ipa_ctx,int client)95*5113495bSYour Name QDF_STATUS wlan_ipa_update_perf_level(struct wlan_ipa_priv *ipa_ctx, int client)
96*5113495bSYour Name {
97*5113495bSYour Name 	return cdp_ipa_set_perf_level(ipa_ctx->dp_soc, client,
98*5113495bSYour Name 				      WLAN_IPA_MAX_BANDWIDTH, ipa_ctx->hdl);
99*5113495bSYour Name }
100*5113495bSYour Name #endif
101*5113495bSYour Name 
wlan_ipa_init_perf_level(struct wlan_ipa_priv * ipa_ctx)102*5113495bSYour Name QDF_STATUS wlan_ipa_init_perf_level(struct wlan_ipa_priv *ipa_ctx)
103*5113495bSYour Name {
104*5113495bSYour Name 	int ret;
105*5113495bSYour Name 
106*5113495bSYour Name 	/* Set lowest bandwidth to start with */
107*5113495bSYour Name 	if (wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config))
108*5113495bSYour Name 		return wlan_ipa_set_perf_level(ipa_ctx, 0, 0);
109*5113495bSYour Name 
110*5113495bSYour Name 	ipa_debug("IPA clk scaling disabled. Set perf level to maximum %d",
111*5113495bSYour Name 		  WLAN_IPA_MAX_BANDWIDTH);
112*5113495bSYour Name 
113*5113495bSYour Name 	ret = wlan_ipa_update_perf_level(ipa_ctx, QDF_IPA_CLIENT_WLAN1_CONS);
114*5113495bSYour Name 	if (ret) {
115*5113495bSYour Name 		ipa_err("CONS set perf profile failed: %d", ret);
116*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
117*5113495bSYour Name 	}
118*5113495bSYour Name 
119*5113495bSYour Name 	ret = wlan_ipa_update_perf_level(ipa_ctx, QDF_IPA_CLIENT_WLAN1_PROD);
120*5113495bSYour Name 	if (ret) {
121*5113495bSYour Name 		ipa_err("PROD set perf profile failed: %d", ret);
122*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
123*5113495bSYour Name 	}
124*5113495bSYour Name 
125*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
126*5113495bSYour Name }
127*5113495bSYour Name 
wlan_ipa_set_perf_level_bw_enabled(struct wlan_ipa_priv * ipa_ctx)128*5113495bSYour Name bool wlan_ipa_set_perf_level_bw_enabled(struct wlan_ipa_priv *ipa_ctx)
129*5113495bSYour Name {
130*5113495bSYour Name 	/*
131*5113495bSYour Name 	 * Do bandwidth-based IPA perf vote only when all below are met.
132*5113495bSYour Name 	 * a. IPA is enabled.
133*5113495bSYour Name 	 * b. IPA clk scaling is _not_ enabled.
134*5113495bSYour Name 	 * c. IPA force voting is enabled.
135*5113495bSYour Name 	 */
136*5113495bSYour Name 	return wlan_ipa_is_enabled(ipa_ctx->config) &&
137*5113495bSYour Name 	       !wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config) &&
138*5113495bSYour Name 	       ipa_ctx->config->ipa_force_voting;
139*5113495bSYour Name }
140*5113495bSYour Name 
wlan_ipa_set_perf_level_bw(struct wlan_ipa_priv * ipa_ctx,enum wlan_ipa_bw_level lvl)141*5113495bSYour Name void wlan_ipa_set_perf_level_bw(struct wlan_ipa_priv *ipa_ctx,
142*5113495bSYour Name 				enum wlan_ipa_bw_level lvl)
143*5113495bSYour Name {
144*5113495bSYour Name 	uint32_t max_mbps;
145*5113495bSYour Name 	int ret;
146*5113495bSYour Name 
147*5113495bSYour Name 	if (!wlan_ipa_set_perf_level_bw_enabled(ipa_ctx))
148*5113495bSYour Name 		return;
149*5113495bSYour Name 
150*5113495bSYour Name 	ipa_debug("Set perf level to %d", lvl);
151*5113495bSYour Name 
152*5113495bSYour Name 	if (lvl == WLAN_IPA_BW_LEVEL_HIGH)
153*5113495bSYour Name 		max_mbps = ipa_ctx->config->ipa_bw_high;
154*5113495bSYour Name 	else if (lvl == WLAN_IPA_BW_LEVEL_MEDIUM)
155*5113495bSYour Name 		max_mbps = ipa_ctx->config->ipa_bw_medium;
156*5113495bSYour Name 	else
157*5113495bSYour Name 		max_mbps = ipa_ctx->config->ipa_bw_low;
158*5113495bSYour Name 
159*5113495bSYour Name 	ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc,
160*5113495bSYour Name 				     QDF_IPA_CLIENT_WLAN1_CONS,
161*5113495bSYour Name 				     max_mbps,
162*5113495bSYour Name 				     ipa_ctx->hdl);
163*5113495bSYour Name 	if (ret) {
164*5113495bSYour Name 		ipa_err("CONS set perf profile failed: %d", ret);
165*5113495bSYour Name 		return;
166*5113495bSYour Name 	}
167*5113495bSYour Name 
168*5113495bSYour Name 	ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc,
169*5113495bSYour Name 				     QDF_IPA_CLIENT_WLAN1_PROD,
170*5113495bSYour Name 				     max_mbps,
171*5113495bSYour Name 				     ipa_ctx->hdl);
172*5113495bSYour Name 	if (ret)
173*5113495bSYour Name 		ipa_err("PROD set perf profile failed: %d", ret);
174*5113495bSYour Name }
175*5113495bSYour Name 
176*5113495bSYour Name #ifdef FEATURE_METERING
wlan_ipa_init_metering(struct wlan_ipa_priv * ipa_ctx)177*5113495bSYour Name void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx)
178*5113495bSYour Name {
179*5113495bSYour Name 	qdf_event_create(&ipa_ctx->ipa_uc_sharing_stats_comp);
180*5113495bSYour Name 	qdf_event_create(&ipa_ctx->ipa_uc_set_quota_comp);
181*5113495bSYour Name }
182*5113495bSYour Name #endif
183*5113495bSYour Name 
184*5113495bSYour Name #ifdef IPA_OPT_WIFI_DP
wlan_ipa_add_rem_flt_cb_event(struct wlan_ipa_priv * ipa_ctx)185*5113495bSYour Name void wlan_ipa_add_rem_flt_cb_event(struct wlan_ipa_priv *ipa_ctx)
186*5113495bSYour Name {
187*5113495bSYour Name 	qdf_event_create(&ipa_ctx->ipa_flt_evnt);
188*5113495bSYour Name }
189*5113495bSYour Name #endif
190*5113495bSYour Name 
191*5113495bSYour Name #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \
192*5113495bSYour Name 	!defined(CONFIG_IPA_WDI_UNIFIED_API)
193*5113495bSYour Name /**
194*5113495bSYour Name  * wlan_ipa_rm_cons_release() - WLAN consumer resource release handler
195*5113495bSYour Name  *
196*5113495bSYour Name  * Callback function registered with IPA that is called when IPA wants
197*5113495bSYour Name  * to release the WLAN consumer resource
198*5113495bSYour Name  *
199*5113495bSYour Name  * Return: 0 if the request is granted, negative errno otherwise
200*5113495bSYour Name  */
wlan_ipa_rm_cons_release(void)201*5113495bSYour Name static int wlan_ipa_rm_cons_release(void)
202*5113495bSYour Name {
203*5113495bSYour Name 	return 0;
204*5113495bSYour Name }
205*5113495bSYour Name 
206*5113495bSYour Name /**
207*5113495bSYour Name  * wlan_ipa_wdi_rm_request() - Request resource from IPA
208*5113495bSYour Name  * @ipa_ctx: IPA context
209*5113495bSYour Name  *
210*5113495bSYour Name  * Return: QDF_STATUS
211*5113495bSYour Name  */
wlan_ipa_wdi_rm_request(struct wlan_ipa_priv * ipa_ctx)212*5113495bSYour Name QDF_STATUS wlan_ipa_wdi_rm_request(struct wlan_ipa_priv *ipa_ctx)
213*5113495bSYour Name {
214*5113495bSYour Name 	int ret;
215*5113495bSYour Name 
216*5113495bSYour Name 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
217*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
218*5113495bSYour Name 
219*5113495bSYour Name 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
220*5113495bSYour Name 
221*5113495bSYour Name 	switch (ipa_ctx->rm_state) {
222*5113495bSYour Name 	case WLAN_IPA_RM_GRANTED:
223*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
224*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
225*5113495bSYour Name 	case WLAN_IPA_RM_GRANT_PENDING:
226*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
227*5113495bSYour Name 		return QDF_STATUS_E_PENDING;
228*5113495bSYour Name 	case WLAN_IPA_RM_RELEASED:
229*5113495bSYour Name 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANT_PENDING;
230*5113495bSYour Name 		break;
231*5113495bSYour Name 	}
232*5113495bSYour Name 
233*5113495bSYour Name 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
234*5113495bSYour Name 
235*5113495bSYour Name 	ret = qdf_ipa_rm_inactivity_timer_request_resource(
236*5113495bSYour Name 			QDF_IPA_RM_RESOURCE_WLAN_PROD);
237*5113495bSYour Name 
238*5113495bSYour Name 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
239*5113495bSYour Name 	if (ret == 0) {
240*5113495bSYour Name 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED;
241*5113495bSYour Name 		ipa_ctx->stats.num_rm_grant_imm++;
242*5113495bSYour Name 	}
243*5113495bSYour Name 
244*5113495bSYour Name 	if (ipa_ctx->wake_lock_released) {
245*5113495bSYour Name 		qdf_wake_lock_acquire(&ipa_ctx->wake_lock,
246*5113495bSYour Name 				      WIFI_POWER_EVENT_WAKELOCK_IPA);
247*5113495bSYour Name 		ipa_ctx->wake_lock_released = false;
248*5113495bSYour Name 	}
249*5113495bSYour Name 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
250*5113495bSYour Name 
251*5113495bSYour Name 	qdf_delayed_work_stop_sync(&ipa_ctx->wake_lock_work);
252*5113495bSYour Name 
253*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
254*5113495bSYour Name }
255*5113495bSYour Name 
wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv * ipa_ctx)256*5113495bSYour Name QDF_STATUS wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv *ipa_ctx)
257*5113495bSYour Name {
258*5113495bSYour Name 	int ret;
259*5113495bSYour Name 
260*5113495bSYour Name 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
261*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
262*5113495bSYour Name 
263*5113495bSYour Name 	if (qdf_atomic_read(&ipa_ctx->tx_ref_cnt))
264*5113495bSYour Name 		return QDF_STATUS_E_AGAIN;
265*5113495bSYour Name 
266*5113495bSYour Name 	qdf_spin_lock_bh(&ipa_ctx->pm_lock);
267*5113495bSYour Name 
268*5113495bSYour Name 	if (!qdf_nbuf_is_queue_empty(&ipa_ctx->pm_queue_head)) {
269*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
270*5113495bSYour Name 		return QDF_STATUS_E_AGAIN;
271*5113495bSYour Name 	}
272*5113495bSYour Name 	qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
273*5113495bSYour Name 
274*5113495bSYour Name 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
275*5113495bSYour Name 	switch (ipa_ctx->rm_state) {
276*5113495bSYour Name 	case WLAN_IPA_RM_GRANTED:
277*5113495bSYour Name 		break;
278*5113495bSYour Name 	case WLAN_IPA_RM_GRANT_PENDING:
279*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
280*5113495bSYour Name 		return QDF_STATUS_E_PENDING;
281*5113495bSYour Name 	case WLAN_IPA_RM_RELEASED:
282*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
283*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
284*5113495bSYour Name 	}
285*5113495bSYour Name 
286*5113495bSYour Name 	/* IPA driver returns immediately so set the state here to avoid any
287*5113495bSYour Name 	 * race condition.
288*5113495bSYour Name 	 */
289*5113495bSYour Name 	ipa_ctx->rm_state = WLAN_IPA_RM_RELEASED;
290*5113495bSYour Name 	ipa_ctx->stats.num_rm_release++;
291*5113495bSYour Name 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
292*5113495bSYour Name 
293*5113495bSYour Name 	ret = qdf_ipa_rm_inactivity_timer_release_resource(
294*5113495bSYour Name 				QDF_IPA_RM_RESOURCE_WLAN_PROD);
295*5113495bSYour Name 
296*5113495bSYour Name 	if (qdf_unlikely(ret != 0)) {
297*5113495bSYour Name 		qdf_spin_lock_bh(&ipa_ctx->rm_lock);
298*5113495bSYour Name 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED;
299*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
300*5113495bSYour Name 		QDF_ASSERT(0);
301*5113495bSYour Name 		ipa_warn("rm_inactivity_timer_release_resource ret fail");
302*5113495bSYour Name 	}
303*5113495bSYour Name 
304*5113495bSYour Name 	/*
305*5113495bSYour Name 	 * If wake_lock is released immediately, kernel would try to suspend
306*5113495bSYour Name 	 * immediately as well, Just avoid ping-pong between suspend-resume
307*5113495bSYour Name 	 * while there is healthy amount of data transfer going on by
308*5113495bSYour Name 	 * releasing the wake_lock after some delay.
309*5113495bSYour Name 	 */
310*5113495bSYour Name 	qdf_delayed_work_start(&ipa_ctx->wake_lock_work,
311*5113495bSYour Name 			       WLAN_IPA_RX_INACTIVITY_MSEC_DELAY);
312*5113495bSYour Name 
313*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
314*5113495bSYour Name }
315*5113495bSYour Name 
316*5113495bSYour Name /**
317*5113495bSYour Name  * wlan_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
318*5113495bSYour Name  * @ipa_ctx: IPA context
319*5113495bSYour Name  * @event: IPA RM event
320*5113495bSYour Name  *
321*5113495bSYour Name  * Return: None
322*5113495bSYour Name  */
323*5113495bSYour Name static void
wlan_ipa_uc_rm_notify_handler(struct wlan_ipa_priv * ipa_ctx,qdf_ipa_rm_event_t event)324*5113495bSYour Name wlan_ipa_uc_rm_notify_handler(struct wlan_ipa_priv *ipa_ctx,
325*5113495bSYour Name 			      qdf_ipa_rm_event_t event)
326*5113495bSYour Name {
327*5113495bSYour Name 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
328*5113495bSYour Name 		return;
329*5113495bSYour Name 
330*5113495bSYour Name 	ipa_debug("event code %d", event);
331*5113495bSYour Name 
332*5113495bSYour Name 	switch (event) {
333*5113495bSYour Name 	case QDF_IPA_RM_RESOURCE_GRANTED:
334*5113495bSYour Name 		/* Differed RM Granted */
335*5113495bSYour Name 		qdf_mutex_acquire(&ipa_ctx->ipa_lock);
336*5113495bSYour Name 		if ((!ipa_ctx->resource_unloading) &&
337*5113495bSYour Name 		    (!ipa_ctx->activated_fw_pipe)) {
338*5113495bSYour Name 			wlan_ipa_uc_enable_pipes(ipa_ctx);
339*5113495bSYour Name 			ipa_ctx->resource_loading = false;
340*5113495bSYour Name 		}
341*5113495bSYour Name 		qdf_mutex_release(&ipa_ctx->ipa_lock);
342*5113495bSYour Name 		break;
343*5113495bSYour Name 
344*5113495bSYour Name 	case QDF_IPA_RM_RESOURCE_RELEASED:
345*5113495bSYour Name 		/* Differed RM Released */
346*5113495bSYour Name 		ipa_ctx->resource_unloading = false;
347*5113495bSYour Name 		break;
348*5113495bSYour Name 
349*5113495bSYour Name 	default:
350*5113495bSYour Name 		ipa_err("invalid event code %d", event);
351*5113495bSYour Name 		break;
352*5113495bSYour Name 	}
353*5113495bSYour Name }
354*5113495bSYour Name 
355*5113495bSYour Name /**
356*5113495bSYour Name  * wlan_ipa_uc_rm_notify_defer() - Defer IPA uC notification
357*5113495bSYour Name  * * @data: IPA context
358*5113495bSYour Name  *
359*5113495bSYour Name  * This function is called when a resource manager event is received
360*5113495bSYour Name  * from firmware in interrupt context.  This function will defer the
361*5113495bSYour Name  * handling to the OL RX thread
362*5113495bSYour Name  *
363*5113495bSYour Name  * Return: None
364*5113495bSYour Name  */
wlan_ipa_uc_rm_notify_defer(void * data)365*5113495bSYour Name static void wlan_ipa_uc_rm_notify_defer(void *data)
366*5113495bSYour Name {
367*5113495bSYour Name 	struct wlan_ipa_priv *ipa_ctx = data;
368*5113495bSYour Name 	qdf_ipa_rm_event_t event;
369*5113495bSYour Name 	struct uc_rm_work_struct *uc_rm_work = &ipa_ctx->uc_rm_work;
370*5113495bSYour Name 
371*5113495bSYour Name 	event = uc_rm_work->event;
372*5113495bSYour Name 
373*5113495bSYour Name 	wlan_ipa_uc_rm_notify_handler(ipa_ctx, event);
374*5113495bSYour Name }
375*5113495bSYour Name 
376*5113495bSYour Name /**
377*5113495bSYour Name  * wlan_ipa_wake_lock_timer_func() - Wake lock work handler
378*5113495bSYour Name  * @data: IPA context
379*5113495bSYour Name  *
380*5113495bSYour Name  * When IPA resources are released in wlan_ipa_wdi_rm_try_release() we do
381*5113495bSYour Name  * not want to immediately release the wake lock since the system
382*5113495bSYour Name  * would then potentially try to suspend when there is a healthy data
383*5113495bSYour Name  * rate.  Deferred work is scheduled and this function handles the
384*5113495bSYour Name  * work.  When this function is called, if the IPA resource is still
385*5113495bSYour Name  * released then we release the wake lock.
386*5113495bSYour Name  *
387*5113495bSYour Name  * Return: None
388*5113495bSYour Name  */
wlan_ipa_wake_lock_timer_func(void * data)389*5113495bSYour Name static void wlan_ipa_wake_lock_timer_func(void *data)
390*5113495bSYour Name {
391*5113495bSYour Name 	struct wlan_ipa_priv *ipa_ctx = data;
392*5113495bSYour Name 
393*5113495bSYour Name 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
394*5113495bSYour Name 
395*5113495bSYour Name 	if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED)
396*5113495bSYour Name 		goto end;
397*5113495bSYour Name 
398*5113495bSYour Name 	ipa_ctx->wake_lock_released = true;
399*5113495bSYour Name 	qdf_wake_lock_release(&ipa_ctx->wake_lock,
400*5113495bSYour Name 			      WIFI_POWER_EVENT_WAKELOCK_IPA);
401*5113495bSYour Name 
402*5113495bSYour Name end:
403*5113495bSYour Name 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
404*5113495bSYour Name }
405*5113495bSYour Name 
406*5113495bSYour Name /**
407*5113495bSYour Name  * wlan_ipa_rm_cons_request() - WLAN consumer resource request handler
408*5113495bSYour Name  *
409*5113495bSYour Name  * Callback function registered with IPA that is called when IPA wants
410*5113495bSYour Name  * to access the WLAN consumer resource
411*5113495bSYour Name  *
412*5113495bSYour Name  * Return: 0 if the request is granted, negative errno otherwise
413*5113495bSYour Name  */
wlan_ipa_rm_cons_request(void)414*5113495bSYour Name static int wlan_ipa_rm_cons_request(void)
415*5113495bSYour Name {
416*5113495bSYour Name 	struct wlan_ipa_priv *ipa_ctx;
417*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
418*5113495bSYour Name 
419*5113495bSYour Name 	ipa_ctx = wlan_ipa_get_obj_context();
420*5113495bSYour Name 
421*5113495bSYour Name 	if (ipa_ctx->resource_loading) {
422*5113495bSYour Name 		ipa_err("IPA resource loading in progress");
423*5113495bSYour Name 		ipa_ctx->pending_cons_req = true;
424*5113495bSYour Name 		status = QDF_STATUS_E_PENDING;
425*5113495bSYour Name 	} else if (ipa_ctx->resource_unloading) {
426*5113495bSYour Name 		ipa_err("IPA resource unloading in progress");
427*5113495bSYour Name 		ipa_ctx->pending_cons_req = true;
428*5113495bSYour Name 		status = QDF_STATUS_E_PERM;
429*5113495bSYour Name 	}
430*5113495bSYour Name 
431*5113495bSYour Name 	return qdf_status_to_os_return(status);
432*5113495bSYour Name }
433*5113495bSYour Name 
434*5113495bSYour Name /**
435*5113495bSYour Name  * wlan_ipa_rm_notify() - IPA resource manager notifier callback
436*5113495bSYour Name  * @user_data: user data registered with IPA
437*5113495bSYour Name  * @event: the IPA resource manager event that occurred
438*5113495bSYour Name  * @data: the data associated with the event
439*5113495bSYour Name  *
440*5113495bSYour Name  * Return: None
441*5113495bSYour Name  */
wlan_ipa_rm_notify(void * user_data,qdf_ipa_rm_event_t event,unsigned long data)442*5113495bSYour Name static void wlan_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event,
443*5113495bSYour Name 			       unsigned long data)
444*5113495bSYour Name {
445*5113495bSYour Name 	struct wlan_ipa_priv *ipa_ctx = user_data;
446*5113495bSYour Name 
447*5113495bSYour Name 	if (qdf_unlikely(!ipa_ctx))
448*5113495bSYour Name 		return;
449*5113495bSYour Name 
450*5113495bSYour Name 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
451*5113495bSYour Name 		return;
452*5113495bSYour Name 
453*5113495bSYour Name 	ipa_debug("Evt: %d", event);
454*5113495bSYour Name 
455*5113495bSYour Name 	switch (event) {
456*5113495bSYour Name 	case QDF_IPA_RM_RESOURCE_GRANTED:
457*5113495bSYour Name 		if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
458*5113495bSYour Name 			/* RM Notification comes with ISR context
459*5113495bSYour Name 			 * it should be serialized into work queue to avoid
460*5113495bSYour Name 			 * ISR sleep problem
461*5113495bSYour Name 			 */
462*5113495bSYour Name 			ipa_ctx->uc_rm_work.event = event;
463*5113495bSYour Name 			qdf_sched_work(0, &ipa_ctx->uc_rm_work.work);
464*5113495bSYour Name 			break;
465*5113495bSYour Name 		}
466*5113495bSYour Name 		qdf_spin_lock_bh(&ipa_ctx->rm_lock);
467*5113495bSYour Name 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED;
468*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
469*5113495bSYour Name 		ipa_ctx->stats.num_rm_grant++;
470*5113495bSYour Name 		break;
471*5113495bSYour Name 
472*5113495bSYour Name 	case QDF_IPA_RM_RESOURCE_RELEASED:
473*5113495bSYour Name 		ipa_debug("RM Release");
474*5113495bSYour Name 		ipa_ctx->resource_unloading = false;
475*5113495bSYour Name 		break;
476*5113495bSYour Name 
477*5113495bSYour Name 	default:
478*5113495bSYour Name 		ipa_err("Unknown RM Evt: %d", event);
479*5113495bSYour Name 		break;
480*5113495bSYour Name 	}
481*5113495bSYour Name }
482*5113495bSYour Name 
wlan_ipa_wdi_setup_rm(struct wlan_ipa_priv * ipa_ctx)483*5113495bSYour Name QDF_STATUS wlan_ipa_wdi_setup_rm(struct wlan_ipa_priv *ipa_ctx)
484*5113495bSYour Name {
485*5113495bSYour Name 	qdf_ipa_rm_create_params_t create_params;
486*5113495bSYour Name 	QDF_STATUS status;
487*5113495bSYour Name 	int ret;
488*5113495bSYour Name 
489*5113495bSYour Name 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
490*5113495bSYour Name 		return 0;
491*5113495bSYour Name 
492*5113495bSYour Name 	qdf_create_work(0, &ipa_ctx->uc_rm_work.work,
493*5113495bSYour Name 			wlan_ipa_uc_rm_notify_defer, ipa_ctx);
494*5113495bSYour Name 	qdf_mem_zero(&create_params, sizeof(create_params));
495*5113495bSYour Name 	create_params.name = QDF_IPA_RM_RESOURCE_WLAN_PROD;
496*5113495bSYour Name 	create_params.reg_params.user_data = ipa_ctx;
497*5113495bSYour Name 	create_params.reg_params.notify_cb = wlan_ipa_rm_notify;
498*5113495bSYour Name 	create_params.floor_voltage = QDF_IPA_VOLTAGE_LEVEL;
499*5113495bSYour Name 
500*5113495bSYour Name 	ret = qdf_ipa_rm_create_resource(&create_params);
501*5113495bSYour Name 	if (ret) {
502*5113495bSYour Name 		ipa_err("Create RM resource failed: %d", ret);
503*5113495bSYour Name 		goto setup_rm_fail;
504*5113495bSYour Name 	}
505*5113495bSYour Name 
506*5113495bSYour Name 	qdf_mem_zero(&create_params, sizeof(create_params));
507*5113495bSYour Name 	create_params.name = QDF_IPA_RM_RESOURCE_WLAN_CONS;
508*5113495bSYour Name 	create_params.request_resource = wlan_ipa_rm_cons_request;
509*5113495bSYour Name 	create_params.release_resource = wlan_ipa_rm_cons_release;
510*5113495bSYour Name 	create_params.floor_voltage = QDF_IPA_VOLTAGE_LEVEL;
511*5113495bSYour Name 
512*5113495bSYour Name 	ret = qdf_ipa_rm_create_resource(&create_params);
513*5113495bSYour Name 	if (ret) {
514*5113495bSYour Name 		ipa_err("Create RM CONS resource failed: %d", ret);
515*5113495bSYour Name 		goto delete_prod;
516*5113495bSYour Name 	}
517*5113495bSYour Name 
518*5113495bSYour Name 	qdf_ipa_rm_add_dependency(QDF_IPA_RM_RESOURCE_WLAN_PROD,
519*5113495bSYour Name 				  QDF_IPA_RM_RESOURCE_APPS_CONS);
520*5113495bSYour Name 
521*5113495bSYour Name 	ret = qdf_ipa_rm_inactivity_timer_init(QDF_IPA_RM_RESOURCE_WLAN_PROD,
522*5113495bSYour Name 					WLAN_IPA_RX_INACTIVITY_MSEC_DELAY);
523*5113495bSYour Name 	if (ret) {
524*5113495bSYour Name 		ipa_err("Timer init failed: %d", ret);
525*5113495bSYour Name 		goto timer_init_failed;
526*5113495bSYour Name 	}
527*5113495bSYour Name 
528*5113495bSYour Name 	status = qdf_delayed_work_create(&ipa_ctx->wake_lock_work,
529*5113495bSYour Name 					 wlan_ipa_wake_lock_timer_func,
530*5113495bSYour Name 					 ipa_ctx);
531*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
532*5113495bSYour Name 		goto timer_destroy;
533*5113495bSYour Name 
534*5113495bSYour Name 	qdf_wake_lock_create(&ipa_ctx->wake_lock, "wlan_ipa");
535*5113495bSYour Name 	qdf_spinlock_create(&ipa_ctx->rm_lock);
536*5113495bSYour Name 	ipa_ctx->rm_state = WLAN_IPA_RM_RELEASED;
537*5113495bSYour Name 	ipa_ctx->wake_lock_released = true;
538*5113495bSYour Name 	qdf_atomic_set(&ipa_ctx->tx_ref_cnt, 0);
539*5113495bSYour Name 
540*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
541*5113495bSYour Name 
542*5113495bSYour Name timer_destroy:
543*5113495bSYour Name 	qdf_ipa_rm_inactivity_timer_destroy(QDF_IPA_RM_RESOURCE_WLAN_PROD);
544*5113495bSYour Name 
545*5113495bSYour Name timer_init_failed:
546*5113495bSYour Name 	qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_APPS_CONS);
547*5113495bSYour Name 
548*5113495bSYour Name delete_prod:
549*5113495bSYour Name 	qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_PROD);
550*5113495bSYour Name 
551*5113495bSYour Name setup_rm_fail:
552*5113495bSYour Name 	return QDF_STATUS_E_FAILURE;
553*5113495bSYour Name }
554*5113495bSYour Name 
wlan_ipa_wdi_destroy_rm(struct wlan_ipa_priv * ipa_ctx)555*5113495bSYour Name void wlan_ipa_wdi_destroy_rm(struct wlan_ipa_priv *ipa_ctx)
556*5113495bSYour Name {
557*5113495bSYour Name 	int ret;
558*5113495bSYour Name 
559*5113495bSYour Name 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
560*5113495bSYour Name 		return;
561*5113495bSYour Name 
562*5113495bSYour Name 	qdf_wake_lock_destroy(&ipa_ctx->wake_lock);
563*5113495bSYour Name 	qdf_delayed_work_destroy(&ipa_ctx->wake_lock_work);
564*5113495bSYour Name 	qdf_cancel_work(&ipa_ctx->uc_rm_work.work);
565*5113495bSYour Name 	qdf_spinlock_destroy(&ipa_ctx->rm_lock);
566*5113495bSYour Name 
567*5113495bSYour Name 	qdf_ipa_rm_inactivity_timer_destroy(QDF_IPA_RM_RESOURCE_WLAN_PROD);
568*5113495bSYour Name 
569*5113495bSYour Name 	ret = qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_CONS);
570*5113495bSYour Name 	if (ret)
571*5113495bSYour Name 		ipa_err("RM CONS resource delete failed %d", ret);
572*5113495bSYour Name 
573*5113495bSYour Name 	ret = qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_PROD);
574*5113495bSYour Name 	if (ret)
575*5113495bSYour Name 		ipa_err("RM PROD resource delete failed %d", ret);
576*5113495bSYour Name }
577*5113495bSYour Name 
wlan_ipa_is_rm_released(struct wlan_ipa_priv * ipa_ctx)578*5113495bSYour Name bool wlan_ipa_is_rm_released(struct wlan_ipa_priv *ipa_ctx)
579*5113495bSYour Name {
580*5113495bSYour Name 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
581*5113495bSYour Name 
582*5113495bSYour Name 	if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED) {
583*5113495bSYour Name 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
584*5113495bSYour Name 		return false;
585*5113495bSYour Name 	}
586*5113495bSYour Name 
587*5113495bSYour Name 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
588*5113495bSYour Name 
589*5113495bSYour Name 	return true;
590*5113495bSYour Name }
591*5113495bSYour Name #endif /* CONFIG_IPA_WDI_UNIFIED_API */
592