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