xref: /wlan-driver/qca-wifi-host-cmn/dp/wifi3.0/dp_umac_reset.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for any
5*5113495bSYour Name  * purpose with or without fee is hereby granted, provided that the above
6*5113495bSYour Name  * copyright notice and this permission notice appear in all copies.
7*5113495bSYour Name  *
8*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*5113495bSYour Name  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*5113495bSYour Name  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*5113495bSYour Name  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*5113495bSYour Name  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*5113495bSYour Name  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*5113495bSYour Name  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*5113495bSYour Name  */
16*5113495bSYour Name #include <dp_internal.h>
17*5113495bSYour Name #include <wlan_cfg.h>
18*5113495bSYour Name #include <hif.h>
19*5113495bSYour Name #include <dp_htt.h>
20*5113495bSYour Name 
21*5113495bSYour Name /**
22*5113495bSYour Name  * dp_get_umac_reset_intr_ctx() - Get the interrupt context to be used by
23*5113495bSYour Name  * UMAC reset feature
24*5113495bSYour Name  * @soc: DP soc object
25*5113495bSYour Name  * @intr_ctx: Interrupt context variable to be populated by this API
26*5113495bSYour Name  *
27*5113495bSYour Name  * Return: QDF_STATUS of operation
28*5113495bSYour Name  */
dp_get_umac_reset_intr_ctx(struct dp_soc * soc,int * intr_ctx)29*5113495bSYour Name static QDF_STATUS dp_get_umac_reset_intr_ctx(struct dp_soc *soc, int *intr_ctx)
30*5113495bSYour Name {
31*5113495bSYour Name 	int umac_reset_mask, i;
32*5113495bSYour Name 
33*5113495bSYour Name 	/**
34*5113495bSYour Name 	 * Go over all the contexts and check which interrupt context has
35*5113495bSYour Name 	 * the UMAC reset mask set.
36*5113495bSYour Name 	 */
37*5113495bSYour Name 	for (i = 0; i < wlan_cfg_get_num_contexts(soc->wlan_cfg_ctx); i++) {
38*5113495bSYour Name 		umac_reset_mask = wlan_cfg_get_umac_reset_intr_mask(
39*5113495bSYour Name 					soc->wlan_cfg_ctx, i);
40*5113495bSYour Name 
41*5113495bSYour Name 		if (umac_reset_mask) {
42*5113495bSYour Name 			*intr_ctx = i;
43*5113495bSYour Name 			return QDF_STATUS_SUCCESS;
44*5113495bSYour Name 		}
45*5113495bSYour Name 	}
46*5113495bSYour Name 
47*5113495bSYour Name 	*intr_ctx = -1;
48*5113495bSYour Name 	return QDF_STATUS_E_FAILURE;
49*5113495bSYour Name }
50*5113495bSYour Name 
51*5113495bSYour Name /**
52*5113495bSYour Name  * dp_umac_reset_send_setup_cmd(): Send the UMAC reset setup command
53*5113495bSYour Name  * @soc: dp soc object
54*5113495bSYour Name  *
55*5113495bSYour Name  * Return: QDF_STATUS of operation
56*5113495bSYour Name  */
57*5113495bSYour Name static QDF_STATUS
dp_umac_reset_send_setup_cmd(struct dp_soc * soc)58*5113495bSYour Name dp_umac_reset_send_setup_cmd(struct dp_soc *soc)
59*5113495bSYour Name {
60*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
61*5113495bSYour Name 	int msi_vector_count, ret;
62*5113495bSYour Name 	uint32_t msi_base_data, msi_vector_start;
63*5113495bSYour Name 	struct dp_htt_umac_reset_setup_cmd_params params;
64*5113495bSYour Name 
65*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
66*5113495bSYour Name 	qdf_mem_zero(&params, sizeof(params));
67*5113495bSYour Name 	ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP",
68*5113495bSYour Name 					  &msi_vector_count, &msi_base_data,
69*5113495bSYour Name 					  &msi_vector_start);
70*5113495bSYour Name 	if (ret) {
71*5113495bSYour Name 		params.msi_data = UMAC_RESET_IPC;
72*5113495bSYour Name 	} else {
73*5113495bSYour Name 		params.msi_data = (umac_reset_ctx->intr_offset %
74*5113495bSYour Name 				  msi_vector_count) + msi_base_data;
75*5113495bSYour Name 	}
76*5113495bSYour Name 
77*5113495bSYour Name 	params.shmem_addr_low =
78*5113495bSYour Name 		qdf_get_lower_32_bits(umac_reset_ctx->shmem_paddr_aligned);
79*5113495bSYour Name 	params.shmem_addr_high =
80*5113495bSYour Name 		qdf_get_upper_32_bits(umac_reset_ctx->shmem_paddr_aligned);
81*5113495bSYour Name 
82*5113495bSYour Name 	return dp_htt_umac_reset_send_setup_cmd(soc, &params);
83*5113495bSYour Name }
84*5113495bSYour Name 
dp_soc_umac_reset_init(struct cdp_soc_t * txrx_soc)85*5113495bSYour Name QDF_STATUS dp_soc_umac_reset_init(struct cdp_soc_t *txrx_soc)
86*5113495bSYour Name {
87*5113495bSYour Name 	struct dp_soc *soc = (struct dp_soc *)txrx_soc;
88*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
89*5113495bSYour Name 	size_t alloc_size;
90*5113495bSYour Name 	QDF_STATUS status;
91*5113495bSYour Name 
92*5113495bSYour Name 	if (!soc) {
93*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
94*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
95*5113495bSYour Name 	}
96*5113495bSYour Name 
97*5113495bSYour Name 	if (!soc->features.umac_hw_reset_support) {
98*5113495bSYour Name 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
99*5113495bSYour Name 		return QDF_STATUS_E_NOSUPPORT;
100*5113495bSYour Name 	}
101*5113495bSYour Name 
102*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
103*5113495bSYour Name 	qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx));
104*5113495bSYour Name 
105*5113495bSYour Name 	umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER;
106*5113495bSYour Name 	umac_reset_ctx->shmem_exp_magic_num = DP_UMAC_RESET_SHMEM_MAGIC_NUM;
107*5113495bSYour Name 
108*5113495bSYour Name 	status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset);
109*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
110*5113495bSYour Name 		dp_umac_reset_err("No interrupt assignment");
111*5113495bSYour Name 		return status;
112*5113495bSYour Name 	}
113*5113495bSYour Name 
114*5113495bSYour Name 	alloc_size = sizeof(htt_umac_hang_recovery_msg_shmem_t) +
115*5113495bSYour Name 			DP_UMAC_RESET_SHMEM_ALIGN - 1;
116*5113495bSYour Name 	umac_reset_ctx->shmem_vaddr_unaligned =
117*5113495bSYour Name 	    qdf_mem_alloc_consistent(soc->osdev, soc->osdev->dev,
118*5113495bSYour Name 				     alloc_size,
119*5113495bSYour Name 				     &umac_reset_ctx->shmem_paddr_unaligned);
120*5113495bSYour Name 	if (!umac_reset_ctx->shmem_vaddr_unaligned) {
121*5113495bSYour Name 		dp_umac_reset_err("shmem allocation failed");
122*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
123*5113495bSYour Name 	}
124*5113495bSYour Name 
125*5113495bSYour Name 	umac_reset_ctx->shmem_vaddr_aligned = (void *)(uintptr_t)qdf_roundup(
126*5113495bSYour Name 		(uint64_t)(uintptr_t)umac_reset_ctx->shmem_vaddr_unaligned,
127*5113495bSYour Name 		DP_UMAC_RESET_SHMEM_ALIGN);
128*5113495bSYour Name 	umac_reset_ctx->shmem_paddr_aligned = qdf_roundup(
129*5113495bSYour Name 		(uint64_t)umac_reset_ctx->shmem_paddr_unaligned,
130*5113495bSYour Name 		DP_UMAC_RESET_SHMEM_ALIGN);
131*5113495bSYour Name 	umac_reset_ctx->shmem_size = alloc_size;
132*5113495bSYour Name 
133*5113495bSYour Name 	/* Write the magic number to the shared memory */
134*5113495bSYour Name 	umac_reset_ctx->shmem_vaddr_aligned->magic_num =
135*5113495bSYour Name 		DP_UMAC_RESET_SHMEM_MAGIC_NUM;
136*5113495bSYour Name 
137*5113495bSYour Name 	/* Attach the interrupts */
138*5113495bSYour Name 	status = dp_umac_reset_interrupt_attach(soc);
139*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
140*5113495bSYour Name 		dp_umac_reset_err("Interrupt attach failed");
141*5113495bSYour Name 		qdf_mem_free_consistent(soc->osdev, soc->osdev->dev,
142*5113495bSYour Name 					umac_reset_ctx->shmem_size,
143*5113495bSYour Name 					umac_reset_ctx->shmem_vaddr_unaligned,
144*5113495bSYour Name 					umac_reset_ctx->shmem_paddr_unaligned,
145*5113495bSYour Name 					0);
146*5113495bSYour Name 		return status;
147*5113495bSYour Name 	}
148*5113495bSYour Name 
149*5113495bSYour Name 	/* Send the setup cmd to the target */
150*5113495bSYour Name 	return dp_umac_reset_send_setup_cmd(soc);
151*5113495bSYour Name }
152*5113495bSYour Name 
153*5113495bSYour Name /**
154*5113495bSYour Name  * dp_umac_reset_get_rx_event_from_shmem() - Extract the Rx event from the
155*5113495bSYour Name  *                                           shared memory
156*5113495bSYour Name  * @umac_reset_ctx: UMAC reset context
157*5113495bSYour Name  *
158*5113495bSYour Name  * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event
159*5113495bSYour Name  */
160*5113495bSYour Name static enum umac_reset_rx_event
dp_umac_reset_get_rx_event_from_shmem(struct dp_soc_umac_reset_ctx * umac_reset_ctx)161*5113495bSYour Name dp_umac_reset_get_rx_event_from_shmem(
162*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx)
163*5113495bSYour Name {
164*5113495bSYour Name 	htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr;
165*5113495bSYour Name 	uint32_t t2h_msg;
166*5113495bSYour Name 	uint8_t num_events = 0;
167*5113495bSYour Name 	enum umac_reset_rx_event rx_event;
168*5113495bSYour Name 
169*5113495bSYour Name 	shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned;
170*5113495bSYour Name 	if (!shmem_vaddr) {
171*5113495bSYour Name 		dp_umac_reset_err("Shared memory address is NULL");
172*5113495bSYour Name 		goto err;
173*5113495bSYour Name 	}
174*5113495bSYour Name 
175*5113495bSYour Name 	if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) {
176*5113495bSYour Name 		dp_umac_reset_err("Shared memory got corrupted");
177*5113495bSYour Name 		goto err;
178*5113495bSYour Name 	}
179*5113495bSYour Name 
180*5113495bSYour Name 	/* Read the shared memory into a local variable */
181*5113495bSYour Name 	t2h_msg = shmem_vaddr->t2h_msg;
182*5113495bSYour Name 
183*5113495bSYour Name 	/* Clear the shared memory right away */
184*5113495bSYour Name 	shmem_vaddr->t2h_msg = 0;
185*5113495bSYour Name 
186*5113495bSYour Name 	dp_umac_reset_debug("shmem value - t2h_msg: 0x%x", t2h_msg);
187*5113495bSYour Name 
188*5113495bSYour Name 	rx_event = UMAC_RESET_RX_EVENT_NONE;
189*5113495bSYour Name 
190*5113495bSYour Name 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_INITIATE_UMAC_RECOVERY_GET(t2h_msg)) {
191*5113495bSYour Name 		rx_event |= UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY;
192*5113495bSYour Name 		num_events++;
193*5113495bSYour Name 	}
194*5113495bSYour Name 
195*5113495bSYour Name 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_INITIATE_TARGET_RECOVERY_SYNC_USING_UMAC_GET(t2h_msg)) {
196*5113495bSYour Name 		rx_event |= UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC;
197*5113495bSYour Name 		num_events++;
198*5113495bSYour Name 	}
199*5113495bSYour Name 
200*5113495bSYour Name 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_PRE_RESET_GET(t2h_msg)) {
201*5113495bSYour Name 		rx_event |= UMAC_RESET_RX_EVENT_DO_PRE_RESET;
202*5113495bSYour Name 		num_events++;
203*5113495bSYour Name 	}
204*5113495bSYour Name 
205*5113495bSYour Name 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_START_GET(t2h_msg)) {
206*5113495bSYour Name 		rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_START;
207*5113495bSYour Name 		num_events++;
208*5113495bSYour Name 	}
209*5113495bSYour Name 
210*5113495bSYour Name 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_COMPLETE_GET(t2h_msg)) {
211*5113495bSYour Name 		rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE;
212*5113495bSYour Name 		num_events++;
213*5113495bSYour Name 	}
214*5113495bSYour Name 
215*5113495bSYour Name 	dp_umac_reset_debug("deduced rx event: 0x%x", rx_event);
216*5113495bSYour Name 	/* There should not be more than 1 event */
217*5113495bSYour Name 	if (num_events > 1) {
218*5113495bSYour Name 		dp_umac_reset_err("Multiple events(0x%x) got posted", rx_event);
219*5113495bSYour Name 		goto err;
220*5113495bSYour Name 	}
221*5113495bSYour Name 
222*5113495bSYour Name 	return rx_event;
223*5113495bSYour Name err:
224*5113495bSYour Name 	qdf_assert_always(0);
225*5113495bSYour Name 	return UMAC_RESET_RX_EVENT_ERROR;
226*5113495bSYour Name }
227*5113495bSYour Name 
228*5113495bSYour Name /**
229*5113495bSYour Name  * dp_umac_reset_peek_rx_event_from_shmem() - Peek the Rx event from the
230*5113495bSYour Name  *                                        shared memory without clearing the bit
231*5113495bSYour Name  * @umac_reset_ctx: UMAC reset context
232*5113495bSYour Name  *
233*5113495bSYour Name  * Return: true if the shared memory has any valid bits set
234*5113495bSYour Name  */
dp_umac_reset_peek_rx_event_from_shmem(struct dp_soc_umac_reset_ctx * umac_reset_ctx)235*5113495bSYour Name static inline bool dp_umac_reset_peek_rx_event_from_shmem(
236*5113495bSYour Name 				struct dp_soc_umac_reset_ctx *umac_reset_ctx)
237*5113495bSYour Name {
238*5113495bSYour Name 	htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr;
239*5113495bSYour Name 
240*5113495bSYour Name 	shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned;
241*5113495bSYour Name 	if (!shmem_vaddr) {
242*5113495bSYour Name 		dp_umac_reset_debug("Shared memory address is NULL");
243*5113495bSYour Name 		goto err;
244*5113495bSYour Name 	}
245*5113495bSYour Name 
246*5113495bSYour Name 	if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) {
247*5113495bSYour Name 		dp_umac_reset_debug("Shared memory got corrupted");
248*5113495bSYour Name 		goto err;
249*5113495bSYour Name 	}
250*5113495bSYour Name 
251*5113495bSYour Name 	/* Read the shared memory into a local variable */
252*5113495bSYour Name 	return !!shmem_vaddr->t2h_msg;
253*5113495bSYour Name 
254*5113495bSYour Name err:
255*5113495bSYour Name 	return false;
256*5113495bSYour Name }
257*5113495bSYour Name 
258*5113495bSYour Name /**
259*5113495bSYour Name  * dp_umac_reset_get_rx_event() - Extract the Rx event
260*5113495bSYour Name  * @umac_reset_ctx: UMAC reset context
261*5113495bSYour Name  *
262*5113495bSYour Name  * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event
263*5113495bSYour Name  */
264*5113495bSYour Name static inline enum umac_reset_rx_event
dp_umac_reset_get_rx_event(struct dp_soc_umac_reset_ctx * umac_reset_ctx)265*5113495bSYour Name dp_umac_reset_get_rx_event(struct dp_soc_umac_reset_ctx *umac_reset_ctx)
266*5113495bSYour Name {
267*5113495bSYour Name 	return dp_umac_reset_get_rx_event_from_shmem(umac_reset_ctx);
268*5113495bSYour Name }
269*5113495bSYour Name 
270*5113495bSYour Name /**
271*5113495bSYour Name  * dp_umac_reset_validate_n_update_state_machine_on_rx() - Validate the state
272*5113495bSYour Name  * machine for a given rx event and update the state machine
273*5113495bSYour Name  * @umac_reset_ctx: UMAC reset context
274*5113495bSYour Name  * @rx_event: Rx event
275*5113495bSYour Name  * @current_exp_state: Expected state
276*5113495bSYour Name  * @next_state: The state to which the state machine needs to be updated
277*5113495bSYour Name  *
278*5113495bSYour Name  * Return: QDF_STATUS of operation
279*5113495bSYour Name  */
280*5113495bSYour Name QDF_STATUS
dp_umac_reset_validate_n_update_state_machine_on_rx(struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_rx_event rx_event,enum umac_reset_state current_exp_state,enum umac_reset_state next_state)281*5113495bSYour Name dp_umac_reset_validate_n_update_state_machine_on_rx(
282*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx,
283*5113495bSYour Name 	enum umac_reset_rx_event rx_event,
284*5113495bSYour Name 	enum umac_reset_state current_exp_state,
285*5113495bSYour Name 	enum umac_reset_state next_state)
286*5113495bSYour Name {
287*5113495bSYour Name 	if (umac_reset_ctx->current_state != current_exp_state) {
288*5113495bSYour Name 		dp_umac_reset_err("state machine validation failed on rx event: %d, current state is %d",
289*5113495bSYour Name 				  rx_event,
290*5113495bSYour Name 				  umac_reset_ctx->current_state);
291*5113495bSYour Name 
292*5113495bSYour Name 		if ((rx_event != UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY) &&
293*5113495bSYour Name 		    (rx_event != UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC))
294*5113495bSYour Name 			qdf_assert_always(0);
295*5113495bSYour Name 
296*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
297*5113495bSYour Name 	}
298*5113495bSYour Name 
299*5113495bSYour Name 	/* Update the state */
300*5113495bSYour Name 	umac_reset_ctx->current_state = next_state;
301*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
302*5113495bSYour Name }
303*5113495bSYour Name 
dp_umac_reset_peek_rx_event(void * dp_ctx)304*5113495bSYour Name static bool dp_umac_reset_peek_rx_event(void *dp_ctx)
305*5113495bSYour Name {
306*5113495bSYour Name 	struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx;
307*5113495bSYour Name 	struct dp_soc *soc = int_ctx->soc;
308*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx = &soc->umac_reset_ctx;
309*5113495bSYour Name 
310*5113495bSYour Name 	return dp_umac_reset_peek_rx_event_from_shmem(umac_reset_ctx);
311*5113495bSYour Name }
312*5113495bSYour Name 
313*5113495bSYour Name /**
314*5113495bSYour Name  * dp_check_umac_reset_in_progress() - Check if Umac reset is in progress
315*5113495bSYour Name  * @soc: dp soc handle
316*5113495bSYour Name  *
317*5113495bSYour Name  * Return: true if Umac reset is in progress or false otherwise
318*5113495bSYour Name  */
dp_check_umac_reset_in_progress(struct dp_soc * soc)319*5113495bSYour Name bool dp_check_umac_reset_in_progress(struct dp_soc *soc)
320*5113495bSYour Name {
321*5113495bSYour Name 	return !!soc->umac_reset_ctx.intr_ctx_bkp;
322*5113495bSYour Name }
323*5113495bSYour Name 
324*5113495bSYour Name 
325*5113495bSYour Name #if !defined(QCA_SUPPORT_DP_GLOBAL_CTX) || \
326*5113495bSYour Name 	(defined(QCA_SUPPORT_DP_GLOBAL_CTX) && \
327*5113495bSYour Name 	!defined(WLAN_FEATURE_11BE_MLO) || !defined(WLAN_MLO_MULTI_CHIP))
dp_get_global_tx_desc_cleanup_flag(struct dp_soc * soc)328*5113495bSYour Name bool dp_get_global_tx_desc_cleanup_flag(struct dp_soc *soc)
329*5113495bSYour Name {
330*5113495bSYour Name 	return true;
331*5113495bSYour Name }
332*5113495bSYour Name 
dp_reset_global_tx_desc_cleanup_flag(struct dp_soc * soc)333*5113495bSYour Name void dp_reset_global_tx_desc_cleanup_flag(struct dp_soc *soc)
334*5113495bSYour Name {
335*5113495bSYour Name }
336*5113495bSYour Name #endif
337*5113495bSYour Name 
338*5113495bSYour Name #if !defined(WLAN_FEATURE_11BE_MLO) || !defined(WLAN_MLO_MULTI_CHIP)
339*5113495bSYour Name /**
340*5113495bSYour Name  * dp_umac_reset_initiate_umac_recovery() - Initiate Umac reset session
341*5113495bSYour Name  * @soc: dp soc handle
342*5113495bSYour Name  * @umac_reset_ctx: Umac reset context
343*5113495bSYour Name  * @rx_event: Rx event received
344*5113495bSYour Name  * @is_target_recovery: Flag to indicate if it is triggered for target recovery
345*5113495bSYour Name  *
346*5113495bSYour Name  * Return: status
347*5113495bSYour Name  */
dp_umac_reset_initiate_umac_recovery(struct dp_soc * soc,struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_rx_event rx_event,bool is_target_recovery)348*5113495bSYour Name static QDF_STATUS dp_umac_reset_initiate_umac_recovery(struct dp_soc *soc,
349*5113495bSYour Name 				struct dp_soc_umac_reset_ctx *umac_reset_ctx,
350*5113495bSYour Name 				enum umac_reset_rx_event rx_event,
351*5113495bSYour Name 				bool is_target_recovery)
352*5113495bSYour Name {
353*5113495bSYour Name 	return dp_umac_reset_validate_n_update_state_machine_on_rx(
354*5113495bSYour Name 					umac_reset_ctx, rx_event,
355*5113495bSYour Name 					UMAC_RESET_STATE_WAIT_FOR_TRIGGER,
356*5113495bSYour Name 					UMAC_RESET_STATE_DO_TRIGGER_RECEIVED);
357*5113495bSYour Name }
358*5113495bSYour Name 
359*5113495bSYour Name /**
360*5113495bSYour Name  * dp_umac_reset_complete_umac_recovery() - Complete Umac reset session
361*5113495bSYour Name  * @soc: dp soc handle
362*5113495bSYour Name  *
363*5113495bSYour Name  * Return: void
364*5113495bSYour Name  */
dp_umac_reset_complete_umac_recovery(struct dp_soc * soc)365*5113495bSYour Name static void dp_umac_reset_complete_umac_recovery(struct dp_soc *soc)
366*5113495bSYour Name {
367*5113495bSYour Name 	dp_umac_reset_alert("Umac reset was handled successfully on soc %pK",
368*5113495bSYour Name 			    soc);
369*5113495bSYour Name }
370*5113495bSYour Name 
371*5113495bSYour Name /**
372*5113495bSYour Name  * dp_umac_reset_handle_action_cb() - Function to call action callback
373*5113495bSYour Name  * @soc: dp soc handle
374*5113495bSYour Name  * @umac_reset_ctx: Umac reset context
375*5113495bSYour Name  * @action: Action to call the callback for
376*5113495bSYour Name  *
377*5113495bSYour Name  * Return: QDF_STATUS status
378*5113495bSYour Name  */
dp_umac_reset_handle_action_cb(struct dp_soc * soc,struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_action action)379*5113495bSYour Name static QDF_STATUS dp_umac_reset_handle_action_cb(struct dp_soc *soc,
380*5113495bSYour Name 				struct dp_soc_umac_reset_ctx *umac_reset_ctx,
381*5113495bSYour Name 				enum umac_reset_action action)
382*5113495bSYour Name {
383*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
384*5113495bSYour Name 
385*5113495bSYour Name 	if (!umac_reset_ctx->rx_actions.cb[action]) {
386*5113495bSYour Name 		dp_umac_reset_err("rx callback is NULL");
387*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
388*5113495bSYour Name 	}
389*5113495bSYour Name 
390*5113495bSYour Name 	status = umac_reset_ctx->rx_actions.cb[action](soc);
391*5113495bSYour Name 
392*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
393*5113495bSYour Name }
394*5113495bSYour Name 
395*5113495bSYour Name /**
396*5113495bSYour Name  * dp_umac_reset_post_tx_cmd() - Iterate partner socs and post Tx command
397*5113495bSYour Name  * @umac_reset_ctx: UMAC reset context
398*5113495bSYour Name  * @tx_cmd: Tx command to be posted
399*5113495bSYour Name  *
400*5113495bSYour Name  * Return: QDF status of operation
401*5113495bSYour Name  */
402*5113495bSYour Name static QDF_STATUS
dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx * umac_reset_ctx,enum umac_reset_tx_cmd tx_cmd)403*5113495bSYour Name dp_umac_reset_post_tx_cmd(struct dp_soc_umac_reset_ctx *umac_reset_ctx,
404*5113495bSYour Name 			  enum umac_reset_tx_cmd tx_cmd)
405*5113495bSYour Name {
406*5113495bSYour Name 	struct dp_soc *soc = container_of(umac_reset_ctx, struct dp_soc,
407*5113495bSYour Name 					  umac_reset_ctx);
408*5113495bSYour Name 
409*5113495bSYour Name 	dp_umac_reset_post_tx_cmd_via_shmem(soc, &tx_cmd, 0);
410*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
411*5113495bSYour Name }
412*5113495bSYour Name 
413*5113495bSYour Name /**
414*5113495bSYour Name  * dp_umac_reset_initiator_check() - Check if soc is the Umac reset initiator
415*5113495bSYour Name  * @soc: dp soc handle
416*5113495bSYour Name  *
417*5113495bSYour Name  * Return: true if the soc is initiator or false otherwise
418*5113495bSYour Name  */
dp_umac_reset_initiator_check(struct dp_soc * soc)419*5113495bSYour Name static bool dp_umac_reset_initiator_check(struct dp_soc *soc)
420*5113495bSYour Name {
421*5113495bSYour Name 	return true;
422*5113495bSYour Name }
423*5113495bSYour Name 
424*5113495bSYour Name /**
425*5113495bSYour Name  * dp_umac_reset_target_recovery_check() - Check if this is for target recovery
426*5113495bSYour Name  * @soc: dp soc handle
427*5113495bSYour Name  *
428*5113495bSYour Name  * Return: true if the session is for target recovery or false otherwise
429*5113495bSYour Name  */
dp_umac_reset_target_recovery_check(struct dp_soc * soc)430*5113495bSYour Name static bool dp_umac_reset_target_recovery_check(struct dp_soc *soc)
431*5113495bSYour Name {
432*5113495bSYour Name 	return false;
433*5113495bSYour Name }
434*5113495bSYour Name 
435*5113495bSYour Name /**
436*5113495bSYour Name  * dp_umac_reset_is_soc_ignored() - Check if this soc is to be ignored
437*5113495bSYour Name  * @soc: dp soc handle
438*5113495bSYour Name  *
439*5113495bSYour Name  * Return: true if the soc is ignored or false otherwise
440*5113495bSYour Name  */
dp_umac_reset_is_soc_ignored(struct dp_soc * soc)441*5113495bSYour Name static bool dp_umac_reset_is_soc_ignored(struct dp_soc *soc)
442*5113495bSYour Name {
443*5113495bSYour Name 	return false;
444*5113495bSYour Name }
445*5113495bSYour Name #endif
446*5113495bSYour Name 
447*5113495bSYour Name /**
448*5113495bSYour Name  * dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset
449*5113495bSYour Name  * @dp_ctx: Interrupt context corresponding to UMAC reset
450*5113495bSYour Name  *
451*5113495bSYour Name  * Return: 0 incase of success, else failure
452*5113495bSYour Name  */
dp_umac_reset_rx_event_handler(void * dp_ctx)453*5113495bSYour Name static int dp_umac_reset_rx_event_handler(void *dp_ctx)
454*5113495bSYour Name {
455*5113495bSYour Name 	struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx;
456*5113495bSYour Name 	struct dp_soc *soc = int_ctx->soc;
457*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
458*5113495bSYour Name 	enum umac_reset_rx_event rx_event;
459*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
460*5113495bSYour Name 	enum umac_reset_action action = UMAC_RESET_ACTION_NONE;
461*5113495bSYour Name 	bool target_recovery = false;
462*5113495bSYour Name 
463*5113495bSYour Name 	if (!soc) {
464*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
465*5113495bSYour Name 		goto exit;
466*5113495bSYour Name 	}
467*5113495bSYour Name 
468*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
469*5113495bSYour Name 
470*5113495bSYour Name 	dp_umac_reset_debug("enter");
471*5113495bSYour Name 	rx_event = dp_umac_reset_get_rx_event(umac_reset_ctx);
472*5113495bSYour Name 
473*5113495bSYour Name 	if (umac_reset_ctx->pending_action) {
474*5113495bSYour Name 		if (rx_event != UMAC_RESET_RX_EVENT_NONE) {
475*5113495bSYour Name 			dp_umac_reset_err("Invalid value(%u) for Rx event when "
476*5113495bSYour Name 					  "action %u is pending\n", rx_event,
477*5113495bSYour Name 					  umac_reset_ctx->pending_action);
478*5113495bSYour Name 			qdf_assert_always(0);
479*5113495bSYour Name 		}
480*5113495bSYour Name 	}
481*5113495bSYour Name 
482*5113495bSYour Name 	switch (rx_event) {
483*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_NONE:
484*5113495bSYour Name 		if (umac_reset_ctx->pending_action)
485*5113495bSYour Name 			action = umac_reset_ctx->pending_action;
486*5113495bSYour Name 		else
487*5113495bSYour Name 			dp_umac_reset_err("Not a UMAC reset event!!");
488*5113495bSYour Name 
489*5113495bSYour Name 		status = QDF_STATUS_SUCCESS;
490*5113495bSYour Name 		break;
491*5113495bSYour Name 
492*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC:
493*5113495bSYour Name 		target_recovery = true;
494*5113495bSYour Name 		/* Fall through */
495*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY:
496*5113495bSYour Name 		status =
497*5113495bSYour Name 		dp_umac_reset_initiate_umac_recovery(soc, umac_reset_ctx,
498*5113495bSYour Name 						     rx_event, target_recovery);
499*5113495bSYour Name 
500*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS)
501*5113495bSYour Name 			break;
502*5113495bSYour Name 
503*5113495bSYour Name 		umac_reset_ctx->ts.trigger_start =
504*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
505*5113495bSYour Name 
506*5113495bSYour Name 		action = UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY;
507*5113495bSYour Name 
508*5113495bSYour Name 		break;
509*5113495bSYour Name 
510*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_PRE_RESET:
511*5113495bSYour Name 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
512*5113495bSYour Name 			umac_reset_ctx, rx_event,
513*5113495bSYour Name 			UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET,
514*5113495bSYour Name 			UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED);
515*5113495bSYour Name 
516*5113495bSYour Name 		umac_reset_ctx->ts.pre_reset_start =
517*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
518*5113495bSYour Name 
519*5113495bSYour Name 		action = UMAC_RESET_ACTION_DO_PRE_RESET;
520*5113495bSYour Name 		break;
521*5113495bSYour Name 
522*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_START:
523*5113495bSYour Name 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
524*5113495bSYour Name 			umac_reset_ctx, rx_event,
525*5113495bSYour Name 			UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START,
526*5113495bSYour Name 			UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED);
527*5113495bSYour Name 
528*5113495bSYour Name 		umac_reset_ctx->ts.post_reset_start =
529*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
530*5113495bSYour Name 
531*5113495bSYour Name 		action = UMAC_RESET_ACTION_DO_POST_RESET_START;
532*5113495bSYour Name 		break;
533*5113495bSYour Name 
534*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE:
535*5113495bSYour Name 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
536*5113495bSYour Name 			umac_reset_ctx, rx_event,
537*5113495bSYour Name 			UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE,
538*5113495bSYour Name 			UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED);
539*5113495bSYour Name 
540*5113495bSYour Name 		umac_reset_ctx->ts.post_reset_complete_start =
541*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
542*5113495bSYour Name 
543*5113495bSYour Name 		action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE;
544*5113495bSYour Name 		break;
545*5113495bSYour Name 
546*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_ERROR:
547*5113495bSYour Name 		dp_umac_reset_err("Error Rx event");
548*5113495bSYour Name 		goto exit;
549*5113495bSYour Name 
550*5113495bSYour Name 	default:
551*5113495bSYour Name 		dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event);
552*5113495bSYour Name 		goto exit;
553*5113495bSYour Name 	}
554*5113495bSYour Name 
555*5113495bSYour Name 	/* Call the handler for this event */
556*5113495bSYour Name 	if (QDF_IS_STATUS_SUCCESS(status)) {
557*5113495bSYour Name 		dp_umac_reset_handle_action_cb(soc, umac_reset_ctx, action);
558*5113495bSYour Name 	}
559*5113495bSYour Name 
560*5113495bSYour Name exit:
561*5113495bSYour Name 	return qdf_status_to_os_return(status);
562*5113495bSYour Name }
563*5113495bSYour Name 
dp_umac_reset_interrupt_attach(struct dp_soc * soc)564*5113495bSYour Name QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc)
565*5113495bSYour Name {
566*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
567*5113495bSYour Name 	int msi_vector_count, ret;
568*5113495bSYour Name 	uint32_t msi_base_data, msi_vector_start;
569*5113495bSYour Name 	uint32_t umac_reset_vector, umac_reset_irq;
570*5113495bSYour Name 	QDF_STATUS status;
571*5113495bSYour Name 
572*5113495bSYour Name 	if (!soc) {
573*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
574*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
575*5113495bSYour Name 	}
576*5113495bSYour Name 
577*5113495bSYour Name 	if (!soc->features.umac_hw_reset_support) {
578*5113495bSYour Name 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
579*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
580*5113495bSYour Name 	}
581*5113495bSYour Name 
582*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
583*5113495bSYour Name 
584*5113495bSYour Name 	if (pld_get_enable_intx(soc->osdev->dev)) {
585*5113495bSYour Name 		dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode");
586*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
587*5113495bSYour Name 	}
588*5113495bSYour Name 
589*5113495bSYour Name 	ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP",
590*5113495bSYour Name 					  &msi_vector_count, &msi_base_data,
591*5113495bSYour Name 					  &msi_vector_start);
592*5113495bSYour Name 	if (ret) {
593*5113495bSYour Name 		/* UMAC reset uses IPC interrupt for AHB devices */
594*5113495bSYour Name 		status = hif_get_umac_reset_irq(soc->hif_handle,
595*5113495bSYour Name 						&umac_reset_irq);
596*5113495bSYour Name 		if (status) {
597*5113495bSYour Name 			dp_umac_reset_err("get_umac_reset_irq failed status %d",
598*5113495bSYour Name 					  status);
599*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
600*5113495bSYour Name 		}
601*5113495bSYour Name 	} else {
602*5113495bSYour Name 		if (umac_reset_ctx->intr_offset < 0 ||
603*5113495bSYour Name 		    umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) {
604*5113495bSYour Name 			dp_umac_reset_err("Invalid interrupt offset: %d",
605*5113495bSYour Name 					  umac_reset_ctx->intr_offset);
606*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
607*5113495bSYour Name 		}
608*5113495bSYour Name 
609*5113495bSYour Name 		umac_reset_vector = msi_vector_start +
610*5113495bSYour Name 			       (umac_reset_ctx->intr_offset % msi_vector_count);
611*5113495bSYour Name 
612*5113495bSYour Name 		/* Get IRQ number */
613*5113495bSYour Name 		umac_reset_irq = pld_get_msi_irq(soc->osdev->dev,
614*5113495bSYour Name 						 umac_reset_vector);
615*5113495bSYour Name 	}
616*5113495bSYour Name 
617*5113495bSYour Name 	/* Finally register to this IRQ from HIF layer */
618*5113495bSYour Name 	return hif_register_umac_reset_handler(
619*5113495bSYour Name 				soc->hif_handle,
620*5113495bSYour Name 				dp_umac_reset_peek_rx_event,
621*5113495bSYour Name 				dp_umac_reset_rx_event_handler,
622*5113495bSYour Name 				&soc->intr_ctx[umac_reset_ctx->intr_offset],
623*5113495bSYour Name 				umac_reset_irq);
624*5113495bSYour Name }
625*5113495bSYour Name 
dp_umac_reset_interrupt_detach(struct dp_soc * soc)626*5113495bSYour Name QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc)
627*5113495bSYour Name {
628*5113495bSYour Name 	if (!soc) {
629*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
630*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
631*5113495bSYour Name 	}
632*5113495bSYour Name 
633*5113495bSYour Name 	if (!soc->features.umac_hw_reset_support) {
634*5113495bSYour Name 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
635*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
636*5113495bSYour Name 	}
637*5113495bSYour Name 
638*5113495bSYour Name 	return hif_unregister_umac_reset_handler(soc->hif_handle);
639*5113495bSYour Name }
640*5113495bSYour Name 
dp_umac_reset_register_rx_action_callback(struct dp_soc * soc,QDF_STATUS (* handler)(struct dp_soc * soc),enum umac_reset_action action)641*5113495bSYour Name QDF_STATUS dp_umac_reset_register_rx_action_callback(
642*5113495bSYour Name 			struct dp_soc *soc,
643*5113495bSYour Name 			QDF_STATUS (*handler)(struct dp_soc *soc),
644*5113495bSYour Name 			enum umac_reset_action action)
645*5113495bSYour Name {
646*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
647*5113495bSYour Name 
648*5113495bSYour Name 	if (!soc) {
649*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
650*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
651*5113495bSYour Name 	}
652*5113495bSYour Name 
653*5113495bSYour Name 	if (!soc->features.umac_hw_reset_support) {
654*5113495bSYour Name 		dp_umac_reset_info("Target doesn't support UMAC HW reset");
655*5113495bSYour Name 		return QDF_STATUS_E_NOSUPPORT;
656*5113495bSYour Name 	}
657*5113495bSYour Name 
658*5113495bSYour Name 	if (action >= UMAC_RESET_ACTION_MAX) {
659*5113495bSYour Name 		dp_umac_reset_err("invalid action: %d", action);
660*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
661*5113495bSYour Name 	}
662*5113495bSYour Name 
663*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
664*5113495bSYour Name 
665*5113495bSYour Name 	umac_reset_ctx->rx_actions.cb[action] = handler;
666*5113495bSYour Name 
667*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
668*5113495bSYour Name }
669*5113495bSYour Name 
670*5113495bSYour Name /**
671*5113495bSYour Name  * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory
672*5113495bSYour Name  * @soc: DP soc object
673*5113495bSYour Name  * @ctxt: Tx command to be posted
674*5113495bSYour Name  * @chip_id: Chip id of the mlo soc
675*5113495bSYour Name  *
676*5113495bSYour Name  * Return: None
677*5113495bSYour Name  */
678*5113495bSYour Name void
dp_umac_reset_post_tx_cmd_via_shmem(struct dp_soc * soc,void * ctxt,int chip_id)679*5113495bSYour Name dp_umac_reset_post_tx_cmd_via_shmem(struct dp_soc *soc, void *ctxt, int chip_id)
680*5113495bSYour Name {
681*5113495bSYour Name 	enum umac_reset_tx_cmd tx_cmd = *((enum umac_reset_tx_cmd *)ctxt);
682*5113495bSYour Name 	htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr;
683*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx = &soc->umac_reset_ctx;
684*5113495bSYour Name 	bool initiator;
685*5113495bSYour Name 	QDF_STATUS status;
686*5113495bSYour Name 
687*5113495bSYour Name 	if (dp_umac_reset_is_soc_ignored(soc)) {
688*5113495bSYour Name 		dp_umac_reset_debug("Skipping soc (chip id %d)", chip_id);
689*5113495bSYour Name 		return;
690*5113495bSYour Name 	}
691*5113495bSYour Name 
692*5113495bSYour Name 	shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned;
693*5113495bSYour Name 	if (!shmem_vaddr) {
694*5113495bSYour Name 		dp_umac_reset_err("Shared memory address is NULL");
695*5113495bSYour Name 		return;
696*5113495bSYour Name 	}
697*5113495bSYour Name 
698*5113495bSYour Name 	dp_umac_reset_debug("Sending txcmd %u for chip id %u", tx_cmd, chip_id);
699*5113495bSYour Name 
700*5113495bSYour Name 	switch (tx_cmd) {
701*5113495bSYour Name 	case UMAC_RESET_TX_CMD_TRIGGER_DONE:
702*5113495bSYour Name 		/* Send htt message to the partner soc */
703*5113495bSYour Name 		initiator = dp_umac_reset_initiator_check(soc);
704*5113495bSYour Name 		if (!initiator)
705*5113495bSYour Name 			umac_reset_ctx->current_state =
706*5113495bSYour Name 					UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET;
707*5113495bSYour Name 
708*5113495bSYour Name 		status = dp_htt_umac_reset_send_start_pre_reset_cmd(soc,
709*5113495bSYour Name 								    initiator,
710*5113495bSYour Name 				!dp_umac_reset_target_recovery_check(soc));
711*5113495bSYour Name 
712*5113495bSYour Name 		if (status != QDF_STATUS_SUCCESS) {
713*5113495bSYour Name 			dp_umac_reset_err("Unable to send Umac trigger");
714*5113495bSYour Name 			qdf_assert_always(0);
715*5113495bSYour Name 		} else {
716*5113495bSYour Name 			dp_umac_reset_debug("Sent trigger for soc (chip_id %d)",
717*5113495bSYour Name 					    chip_id);
718*5113495bSYour Name 		}
719*5113495bSYour Name 
720*5113495bSYour Name 		umac_reset_ctx->ts.trigger_done = qdf_get_log_timestamp_usecs();
721*5113495bSYour Name 		break;
722*5113495bSYour Name 
723*5113495bSYour Name 	case UMAC_RESET_TX_CMD_PRE_RESET_DONE:
724*5113495bSYour Name 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET(
725*5113495bSYour Name 			shmem_vaddr->h2t_msg, 1);
726*5113495bSYour Name 
727*5113495bSYour Name 		umac_reset_ctx->ts.pre_reset_done =
728*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
729*5113495bSYour Name 		break;
730*5113495bSYour Name 
731*5113495bSYour Name 	case UMAC_RESET_TX_CMD_POST_RESET_START_DONE:
732*5113495bSYour Name 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_START_DONE_SET(
733*5113495bSYour Name 			shmem_vaddr->h2t_msg, 1);
734*5113495bSYour Name 
735*5113495bSYour Name 		umac_reset_ctx->ts.post_reset_done =
736*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
737*5113495bSYour Name 		break;
738*5113495bSYour Name 
739*5113495bSYour Name 	case UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE:
740*5113495bSYour Name 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_COMPLETE_DONE_SET(
741*5113495bSYour Name 			shmem_vaddr->h2t_msg, 1);
742*5113495bSYour Name 
743*5113495bSYour Name 		umac_reset_ctx->ts.post_reset_complete_done =
744*5113495bSYour Name 						qdf_get_log_timestamp_usecs();
745*5113495bSYour Name 		break;
746*5113495bSYour Name 
747*5113495bSYour Name 	default:
748*5113495bSYour Name 		dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd);
749*5113495bSYour Name 		return;
750*5113495bSYour Name 	}
751*5113495bSYour Name 
752*5113495bSYour Name 	return;
753*5113495bSYour Name }
754*5113495bSYour Name 
755*5113495bSYour Name /**
756*5113495bSYour Name  * dp_umac_reset_notify_target() - Notify the target about completion of action.
757*5113495bSYour Name  * @umac_reset_ctx: UMAC reset context
758*5113495bSYour Name  *
759*5113495bSYour Name  * This API figures out the Tx command that needs to be posted based on the
760*5113495bSYour Name  * current state in the state machine. Also, updates the state machine once the
761*5113495bSYour Name  * Tx command has been posted.
762*5113495bSYour Name  *
763*5113495bSYour Name  * Return: QDF status of operation
764*5113495bSYour Name  */
765*5113495bSYour Name static QDF_STATUS
dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx * umac_reset_ctx)766*5113495bSYour Name dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx)
767*5113495bSYour Name {
768*5113495bSYour Name 	enum umac_reset_state next_state;
769*5113495bSYour Name 	enum umac_reset_tx_cmd tx_cmd;
770*5113495bSYour Name 	QDF_STATUS status;
771*5113495bSYour Name 
772*5113495bSYour Name 	switch (umac_reset_ctx->current_state) {
773*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_TRIGGER_DONE:
774*5113495bSYour Name 		tx_cmd = UMAC_RESET_TX_CMD_TRIGGER_DONE;
775*5113495bSYour Name 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET;
776*5113495bSYour Name 		break;
777*5113495bSYour Name 
778*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_PRE_RESET_DONE:
779*5113495bSYour Name 		tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE;
780*5113495bSYour Name 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START;
781*5113495bSYour Name 		break;
782*5113495bSYour Name 
783*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE:
784*5113495bSYour Name 		tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_START_DONE;
785*5113495bSYour Name 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE;
786*5113495bSYour Name 		break;
787*5113495bSYour Name 
788*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE:
789*5113495bSYour Name 		tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE;
790*5113495bSYour Name 		next_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER;
791*5113495bSYour Name 		break;
792*5113495bSYour Name 
793*5113495bSYour Name 	default:
794*5113495bSYour Name 		dp_umac_reset_err("Invalid state(%d) during Tx",
795*5113495bSYour Name 				  umac_reset_ctx->current_state);
796*5113495bSYour Name 		qdf_assert_always(0);
797*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
798*5113495bSYour Name 	}
799*5113495bSYour Name 
800*5113495bSYour Name 	/*
801*5113495bSYour Name 	 * Update the state machine before sending the command to firmware
802*5113495bSYour Name 	 * as we might get the response from firmware even before the state
803*5113495bSYour Name 	 * is updated.
804*5113495bSYour Name 	 */
805*5113495bSYour Name 	umac_reset_ctx->current_state = next_state;
806*5113495bSYour Name 
807*5113495bSYour Name 	status = dp_umac_reset_post_tx_cmd(umac_reset_ctx, tx_cmd);
808*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
809*5113495bSYour Name 		dp_umac_reset_err("Couldn't post Tx cmd");
810*5113495bSYour Name 		qdf_assert_always(0);
811*5113495bSYour Name 		return status;
812*5113495bSYour Name 	}
813*5113495bSYour Name 
814*5113495bSYour Name 	return status;
815*5113495bSYour Name }
816*5113495bSYour Name 
817*5113495bSYour Name /**
818*5113495bSYour Name  * dp_umac_reset_notify_completion() - Notify that a given action has been
819*5113495bSYour Name  * completed
820*5113495bSYour Name  * @soc: DP soc object
821*5113495bSYour Name  * @next_state: The state to which the state machine needs to be updated due to
822*5113495bSYour Name  * this completion
823*5113495bSYour Name  *
824*5113495bSYour Name  * Return: QDF status of operation
825*5113495bSYour Name  */
dp_umac_reset_notify_completion(struct dp_soc * soc,enum umac_reset_state next_state)826*5113495bSYour Name static QDF_STATUS dp_umac_reset_notify_completion(
827*5113495bSYour Name 		struct dp_soc *soc,
828*5113495bSYour Name 		enum umac_reset_state next_state)
829*5113495bSYour Name {
830*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
831*5113495bSYour Name 
832*5113495bSYour Name 	if (!soc) {
833*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
834*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
835*5113495bSYour Name 	}
836*5113495bSYour Name 
837*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
838*5113495bSYour Name 
839*5113495bSYour Name 	/* Update the state first */
840*5113495bSYour Name 	umac_reset_ctx->current_state = next_state;
841*5113495bSYour Name 
842*5113495bSYour Name 	return dp_umac_reset_notify_target(umac_reset_ctx);
843*5113495bSYour Name }
844*5113495bSYour Name 
dp_umac_wait_for_quiescent_state(struct dp_soc * soc)845*5113495bSYour Name static void dp_umac_wait_for_quiescent_state(struct dp_soc *soc)
846*5113495bSYour Name {
847*5113495bSYour Name 	enum umac_reset_state current_state;
848*5113495bSYour Name 
849*5113495bSYour Name 	do {
850*5113495bSYour Name 		msleep(10);
851*5113495bSYour Name 		barrier();
852*5113495bSYour Name 		current_state = soc->umac_reset_ctx.current_state;
853*5113495bSYour Name 
854*5113495bSYour Name 	} while ((current_state == UMAC_RESET_STATE_DO_TRIGGER_RECEIVED) ||
855*5113495bSYour Name 	(current_state == UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED) ||
856*5113495bSYour Name 	(current_state == UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED) ||
857*5113495bSYour Name 	(current_state == UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED));
858*5113495bSYour Name }
859*5113495bSYour Name 
dp_umac_reset_notify_action_completion(struct dp_soc * soc,enum umac_reset_action action)860*5113495bSYour Name QDF_STATUS dp_umac_reset_notify_action_completion(
861*5113495bSYour Name 		struct dp_soc *soc,
862*5113495bSYour Name 		enum umac_reset_action action)
863*5113495bSYour Name {
864*5113495bSYour Name 	enum umac_reset_state next_state;
865*5113495bSYour Name 
866*5113495bSYour Name 	if (!soc) {
867*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
868*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
869*5113495bSYour Name 	}
870*5113495bSYour Name 
871*5113495bSYour Name 	if (!soc->features.umac_hw_reset_support) {
872*5113495bSYour Name 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
873*5113495bSYour Name 		return QDF_STATUS_E_NOSUPPORT;
874*5113495bSYour Name 	}
875*5113495bSYour Name 
876*5113495bSYour Name 	switch (action) {
877*5113495bSYour Name 	case UMAC_RESET_ACTION_DO_TRIGGER_RECOVERY:
878*5113495bSYour Name 		next_state = UMAC_RESET_STATE_HOST_TRIGGER_DONE;
879*5113495bSYour Name 		break;
880*5113495bSYour Name 
881*5113495bSYour Name 	case UMAC_RESET_ACTION_DO_PRE_RESET:
882*5113495bSYour Name 		next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE;
883*5113495bSYour Name 		break;
884*5113495bSYour Name 
885*5113495bSYour Name 	case UMAC_RESET_ACTION_DO_POST_RESET_START:
886*5113495bSYour Name 		next_state = UMAC_RESET_STATE_HOST_POST_RESET_START_DONE;
887*5113495bSYour Name 		break;
888*5113495bSYour Name 
889*5113495bSYour Name 	case UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE:
890*5113495bSYour Name 		next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE;
891*5113495bSYour Name 		break;
892*5113495bSYour Name 
893*5113495bSYour Name 	case UMAC_RESET_ACTION_ABORT:
894*5113495bSYour Name 		next_state = UMAC_RESET_STATE_WAIT_FOR_TRIGGER;
895*5113495bSYour Name 		break;
896*5113495bSYour Name 
897*5113495bSYour Name 	default:
898*5113495bSYour Name 		dp_umac_reset_err("Invalid action: %u", action);
899*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
900*5113495bSYour Name 	}
901*5113495bSYour Name 
902*5113495bSYour Name 	return dp_umac_reset_notify_completion(soc, next_state);
903*5113495bSYour Name }
904*5113495bSYour Name 
905*5113495bSYour Name /**
906*5113495bSYour Name  * dp_soc_umac_reset_deinit() - Deinitialize the umac reset module
907*5113495bSYour Name  * @txrx_soc: DP soc object
908*5113495bSYour Name  *
909*5113495bSYour Name  * Return: QDF status of operation
910*5113495bSYour Name  */
dp_soc_umac_reset_deinit(struct cdp_soc_t * txrx_soc)911*5113495bSYour Name QDF_STATUS dp_soc_umac_reset_deinit(struct cdp_soc_t *txrx_soc)
912*5113495bSYour Name {
913*5113495bSYour Name 	struct dp_soc *soc = (struct dp_soc *)txrx_soc;
914*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
915*5113495bSYour Name 	qdf_nbuf_t nbuf_list;
916*5113495bSYour Name 
917*5113495bSYour Name 	if (!soc) {
918*5113495bSYour Name 		dp_umac_reset_err("DP SOC is null");
919*5113495bSYour Name 		return QDF_STATUS_E_NULL_VALUE;
920*5113495bSYour Name 	}
921*5113495bSYour Name 
922*5113495bSYour Name 	if (!soc->features.umac_hw_reset_support) {
923*5113495bSYour Name 		dp_umac_reset_info("No target support for UMAC reset feature");
924*5113495bSYour Name 		return QDF_STATUS_E_NOSUPPORT;
925*5113495bSYour Name 	}
926*5113495bSYour Name 
927*5113495bSYour Name 	if (dp_check_umac_reset_in_progress(soc)) {
928*5113495bSYour Name 		dp_umac_reset_info("Cleaning up Umac reset context");
929*5113495bSYour Name 		dp_umac_wait_for_quiescent_state(soc);
930*5113495bSYour Name 		dp_resume_reo_send_cmd(soc);
931*5113495bSYour Name 		dp_umac_reset_notify_action_completion(soc,
932*5113495bSYour Name 						       UMAC_RESET_ACTION_ABORT);
933*5113495bSYour Name 	}
934*5113495bSYour Name 
935*5113495bSYour Name 	nbuf_list = soc->umac_reset_ctx.nbuf_list;
936*5113495bSYour Name 	soc->umac_reset_ctx.nbuf_list = NULL;
937*5113495bSYour Name 
938*5113495bSYour Name 	while (nbuf_list) {
939*5113495bSYour Name 		qdf_nbuf_t nbuf = nbuf_list->next;
940*5113495bSYour Name 
941*5113495bSYour Name 		qdf_nbuf_free(nbuf_list);
942*5113495bSYour Name 		nbuf_list = nbuf;
943*5113495bSYour Name 	}
944*5113495bSYour Name 
945*5113495bSYour Name 	dp_umac_reset_interrupt_detach(soc);
946*5113495bSYour Name 
947*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
948*5113495bSYour Name 	qdf_mem_free_consistent(soc->osdev, soc->osdev->dev,
949*5113495bSYour Name 				umac_reset_ctx->shmem_size,
950*5113495bSYour Name 				umac_reset_ctx->shmem_vaddr_unaligned,
951*5113495bSYour Name 				umac_reset_ctx->shmem_paddr_unaligned,
952*5113495bSYour Name 				0);
953*5113495bSYour Name 
954*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
955*5113495bSYour Name }
956*5113495bSYour Name 
dp_umac_reset_current_state_to_str(enum umac_reset_state current_state)957*5113495bSYour Name static inline const char *dp_umac_reset_current_state_to_str(
958*5113495bSYour Name 		enum umac_reset_state current_state)
959*5113495bSYour Name {
960*5113495bSYour Name 	switch (current_state) {
961*5113495bSYour Name 	case UMAC_RESET_STATE_WAIT_FOR_TRIGGER:
962*5113495bSYour Name 		return "UMAC_RESET_STATE_WAIT_FOR_TRIGGER";
963*5113495bSYour Name 	case UMAC_RESET_STATE_DO_TRIGGER_RECEIVED:
964*5113495bSYour Name 		return "UMAC_RESET_STATE_DO_TRIGGER_RECEIVED";
965*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_TRIGGER_DONE:
966*5113495bSYour Name 		return "UMAC_RESET_STATE_HOST_TRIGGER_DONE";
967*5113495bSYour Name 	case UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET:
968*5113495bSYour Name 		return "UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET";
969*5113495bSYour Name 	case UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED:
970*5113495bSYour Name 		return "UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED";
971*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_PRE_RESET_DONE:
972*5113495bSYour Name 		return "UMAC_RESET_STATE_HOST_PRE_RESET_DONE";
973*5113495bSYour Name 	case UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START:
974*5113495bSYour Name 		return "UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START";
975*5113495bSYour Name 	case UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED:
976*5113495bSYour Name 		return "UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED";
977*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE:
978*5113495bSYour Name 		return "UMAC_RESET_STATE_HOST_POST_RESET_START_DONE";
979*5113495bSYour Name 	case UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE:
980*5113495bSYour Name 		return "UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE";
981*5113495bSYour Name 	case UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED:
982*5113495bSYour Name 		return "UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED";
983*5113495bSYour Name 	case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE:
984*5113495bSYour Name 		return "UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE";
985*5113495bSYour Name 	default:
986*5113495bSYour Name 		return "Invalid UMAC Reset state";
987*5113495bSYour Name 	}
988*5113495bSYour Name }
989*5113495bSYour Name 
dp_umac_reset_pending_action_to_str(enum umac_reset_rx_event pending_action)990*5113495bSYour Name static inline const char *dp_umac_reset_pending_action_to_str(
991*5113495bSYour Name 		enum umac_reset_rx_event pending_action)
992*5113495bSYour Name {
993*5113495bSYour Name 	switch (pending_action) {
994*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_NONE:
995*5113495bSYour Name 		return "UMAC_RESET_RX_EVENT_NONE";
996*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY:
997*5113495bSYour Name 		return "UMAC_RESET_RX_EVENT_DO_TRIGGER_RECOVERY";
998*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC:
999*5113495bSYour Name 		return "UMAC_RESET_RX_EVENT_DO_TRIGGER_TR_SYNC";
1000*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_PRE_RESET:
1001*5113495bSYour Name 		return "UMAC_RESET_RX_EVENT_DO_PRE_RESET";
1002*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_START:
1003*5113495bSYour Name 		return "UMAC_RESET_RX_EVENT_DO_POST_RESET_START";
1004*5113495bSYour Name 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE:
1005*5113495bSYour Name 		return "UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE";
1006*5113495bSYour Name 	default:
1007*5113495bSYour Name 		return "Invalid pending action";
1008*5113495bSYour Name 	}
1009*5113495bSYour Name }
1010*5113495bSYour Name 
dp_umac_reset_stats_print(struct dp_soc * soc)1011*5113495bSYour Name QDF_STATUS dp_umac_reset_stats_print(struct dp_soc *soc)
1012*5113495bSYour Name {
1013*5113495bSYour Name 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
1014*5113495bSYour Name 
1015*5113495bSYour Name 	umac_reset_ctx = &soc->umac_reset_ctx;
1016*5113495bSYour Name 
1017*5113495bSYour Name 	DP_UMAC_RESET_PRINT_STATS("UMAC reset stats for soc:%pK\n"
1018*5113495bSYour Name 		  "\t\ttrigger time                  :%llu us\n"
1019*5113495bSYour Name 		  "\t\tPre_reset time                :%llu us\n"
1020*5113495bSYour Name 		  "\t\tPost_reset time               :%llu us\n"
1021*5113495bSYour Name 		  "\t\tPost_reset_complete time      :%llu us\n"
1022*5113495bSYour Name 		  "\t\tCurrent state                 :%s\n"
1023*5113495bSYour Name 		  "\t\tPending action                :%s",
1024*5113495bSYour Name 		  soc,
1025*5113495bSYour Name 		  umac_reset_ctx->ts.trigger_done -
1026*5113495bSYour Name 		  umac_reset_ctx->ts.trigger_start,
1027*5113495bSYour Name 		  umac_reset_ctx->ts.pre_reset_done -
1028*5113495bSYour Name 		  umac_reset_ctx->ts.pre_reset_start,
1029*5113495bSYour Name 		  umac_reset_ctx->ts.post_reset_done -
1030*5113495bSYour Name 		  umac_reset_ctx->ts.post_reset_start,
1031*5113495bSYour Name 		  umac_reset_ctx->ts.post_reset_complete_done -
1032*5113495bSYour Name 		  umac_reset_ctx->ts.post_reset_complete_start,
1033*5113495bSYour Name 		  dp_umac_reset_current_state_to_str(
1034*5113495bSYour Name 			  umac_reset_ctx->current_state),
1035*5113495bSYour Name 		  dp_umac_reset_pending_action_to_str(
1036*5113495bSYour Name 			  umac_reset_ctx->pending_action));
1037*5113495bSYour Name 
1038*5113495bSYour Name 	return dp_mlo_umac_reset_stats_print(soc);
1039*5113495bSYour Name }
1040