xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_umac_reset.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2022 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_types.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 	ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP",
67 					  &msi_vector_count, &msi_base_data,
68 					  &msi_vector_start);
69 	if (ret)
70 		return QDF_STATUS_E_FAILURE;
71 
72 	qdf_mem_zero(&params, sizeof(params));
73 	params.msi_data = (umac_reset_ctx->intr_offset % msi_vector_count) +
74 				msi_base_data;
75 	params.shmem_addr_low =
76 		qdf_get_lower_32_bits(umac_reset_ctx->shmem_paddr_aligned);
77 	params.shmem_addr_high =
78 		qdf_get_upper_32_bits(umac_reset_ctx->shmem_paddr_aligned);
79 
80 	return dp_htt_umac_reset_send_setup_cmd(soc, &params);
81 }
82 
83 QDF_STATUS dp_soc_umac_reset_init(struct dp_soc *soc)
84 {
85 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
86 	size_t alloc_size;
87 	QDF_STATUS status;
88 
89 	if (!soc) {
90 		dp_umac_reset_err("DP SOC is null");
91 		return QDF_STATUS_E_NULL_VALUE;
92 	}
93 
94 	if (!soc->features.umac_hw_reset_support) {
95 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
96 		return QDF_STATUS_E_NOSUPPORT;
97 	}
98 
99 	umac_reset_ctx = &soc->umac_reset_ctx;
100 	qdf_mem_zero(umac_reset_ctx, sizeof(*umac_reset_ctx));
101 
102 	umac_reset_ctx->current_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET;
103 	umac_reset_ctx->shmem_exp_magic_num = DP_UMAC_RESET_SHMEM_MAGIC_NUM;
104 
105 	status = dp_get_umac_reset_intr_ctx(soc, &umac_reset_ctx->intr_offset);
106 	if (QDF_IS_STATUS_ERROR(status)) {
107 		dp_umac_reset_err("No interrupt assignment");
108 		return status;
109 	}
110 
111 	alloc_size = sizeof(htt_umac_hang_recovery_msg_shmem_t) +
112 			DP_UMAC_RESET_SHMEM_ALIGN - 1;
113 	umac_reset_ctx->shmem_vaddr_unaligned =
114 	    qdf_mem_alloc_consistent(soc->osdev, soc->osdev->dev,
115 				     alloc_size,
116 				     &umac_reset_ctx->shmem_paddr_unaligned);
117 	if (!umac_reset_ctx->shmem_vaddr_unaligned) {
118 		dp_umac_reset_err("shmem allocation failed");
119 		return QDF_STATUS_E_NOMEM;
120 	}
121 
122 	umac_reset_ctx->shmem_vaddr_aligned = (void *)(uintptr_t)qdf_roundup(
123 		(uint64_t)(uintptr_t)umac_reset_ctx->shmem_vaddr_unaligned,
124 		DP_UMAC_RESET_SHMEM_ALIGN);
125 	umac_reset_ctx->shmem_paddr_aligned = qdf_roundup(
126 		(uint64_t)umac_reset_ctx->shmem_paddr_unaligned,
127 		DP_UMAC_RESET_SHMEM_ALIGN);
128 	umac_reset_ctx->shmem_size = alloc_size;
129 
130 	/* Write the magic number to the shared memory */
131 	umac_reset_ctx->shmem_vaddr_aligned->magic_num =
132 		DP_UMAC_RESET_SHMEM_MAGIC_NUM;
133 
134 	/* Attach the interrupts */
135 	status = dp_umac_reset_interrupt_attach(soc);
136 	if (QDF_IS_STATUS_ERROR(status)) {
137 		dp_umac_reset_err("Interrupt attach failed");
138 		qdf_mem_free_consistent(soc->osdev, soc->osdev->dev,
139 					umac_reset_ctx->shmem_size,
140 					umac_reset_ctx->shmem_vaddr_unaligned,
141 					umac_reset_ctx->shmem_paddr_unaligned,
142 					0);
143 		return status;
144 	}
145 
146 	/* Send the setup cmd to the target */
147 	return dp_umac_reset_send_setup_cmd(soc);
148 }
149 
150 QDF_STATUS dp_soc_umac_reset_deinit(struct cdp_soc_t *txrx_soc)
151 {
152 	struct dp_soc *soc = (struct dp_soc *)txrx_soc;
153 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
154 
155 	if (!soc) {
156 		dp_umac_reset_err("DP SOC is null");
157 		return QDF_STATUS_E_NULL_VALUE;
158 	}
159 
160 	if (!soc->features.umac_hw_reset_support) {
161 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
162 		return QDF_STATUS_E_NOSUPPORT;
163 	}
164 
165 	dp_umac_reset_interrupt_detach(soc);
166 
167 	umac_reset_ctx = &soc->umac_reset_ctx;
168 	qdf_mem_free_consistent(soc->osdev, soc->osdev->dev,
169 				umac_reset_ctx->shmem_size,
170 				umac_reset_ctx->shmem_vaddr_unaligned,
171 				umac_reset_ctx->shmem_paddr_unaligned,
172 				0);
173 
174 	return QDF_STATUS_SUCCESS;
175 }
176 
177 /**
178  * dp_umac_reset_get_rx_event() - Extract the Rx event from the shared memory
179  * @umac_reset_ctx: UMAC reset context
180  *
181  * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event
182  */
183 static enum umac_reset_rx_event
184 dp_umac_reset_get_rx_event_from_shmem(
185 	struct dp_soc_umac_reset_ctx *umac_reset_ctx)
186 {
187 	htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr;
188 	uint32_t t2h_msg;
189 	uint8_t num_events = 0;
190 	enum umac_reset_rx_event rx_event;
191 
192 	shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned;
193 	if (!shmem_vaddr) {
194 		dp_umac_reset_err("Shared memory address is NULL");
195 		goto err;
196 	}
197 
198 	if (shmem_vaddr->magic_num != umac_reset_ctx->shmem_exp_magic_num) {
199 		dp_umac_reset_err("Shared memory got corrupted");
200 		goto err;
201 	}
202 
203 	/* Read the shared memory into a local variable */
204 	t2h_msg = shmem_vaddr->t2h_msg;
205 
206 	/* Clear the shared memory right away */
207 	shmem_vaddr->t2h_msg = 0;
208 
209 	dp_umac_reset_debug("shmem value - t2h_msg: 0x%x", t2h_msg);
210 
211 	rx_event = UMAC_RESET_RX_EVENT_NONE;
212 
213 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_PRE_RESET_GET(t2h_msg)) {
214 		rx_event |= UMAC_RESET_RX_EVENT_DO_PRE_RESET;
215 		num_events++;
216 	}
217 
218 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_START_GET(t2h_msg)) {
219 		rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_START;
220 		num_events++;
221 	}
222 
223 	if (HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_DO_POST_RESET_COMPLETE_GET(t2h_msg)) {
224 		rx_event |= UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE;
225 		num_events++;
226 	}
227 
228 	dp_umac_reset_debug("deduced rx event: 0x%x", rx_event);
229 	/* There should not be more than 1 event */
230 	if (num_events > 1) {
231 		dp_umac_reset_err("Multiple events(0x%x) got posted", rx_event);
232 		goto err;
233 	}
234 
235 	return rx_event;
236 err:
237 	qdf_assert_always(0);
238 	return UMAC_RESET_RX_EVENT_ERROR;
239 }
240 
241 /**
242  * dp_umac_reset_get_rx_event() - Extract the Rx event
243  * @umac_reset_ctx: UMAC reset context
244  *
245  * Return: Extracted Rx event in the form of enumeration umac_reset_rx_event
246  */
247 static inline enum umac_reset_rx_event
248 dp_umac_reset_get_rx_event(struct dp_soc_umac_reset_ctx *umac_reset_ctx)
249 {
250 	return dp_umac_reset_get_rx_event_from_shmem(umac_reset_ctx);
251 }
252 
253 /**
254  * dp_umac_reset_validate_n_update_state_machine_on_rx() - Validate the state
255  * machine for a given rx event and update the state machine
256  * @umac_reset_ctx: UMAC reset context
257  * @rx_event: Rx event
258  * @current_exp_state: Expected state
259  * @next_state: The state to which the state machine needs to be updated
260  *
261  * Return: QDF_STATUS of operation
262  */
263 static QDF_STATUS
264 dp_umac_reset_validate_n_update_state_machine_on_rx(
265 	struct dp_soc_umac_reset_ctx *umac_reset_ctx,
266 	enum umac_reset_rx_event rx_event,
267 	enum umac_reset_state current_exp_state,
268 	enum umac_reset_state next_state)
269 {
270 	if (umac_reset_ctx->current_state != current_exp_state) {
271 		dp_umac_reset_err("state machine validation failed on rx event: %d, current state is %d",
272 				  rx_event,
273 				  umac_reset_ctx->current_state);
274 		qdf_assert_always(0);
275 		return QDF_STATUS_E_FAILURE;
276 	}
277 
278 	/* Update the state */
279 	umac_reset_ctx->current_state = next_state;
280 	return QDF_STATUS_SUCCESS;
281 }
282 
283 /**
284  * dp_umac_reset_rx_event_handler() - Main Rx event handler for UMAC reset
285  * @dp_ctx: Interrupt context corresponding to UMAC reset
286  *
287  * Return: 0 incase of success, else failure
288  */
289 static int dp_umac_reset_rx_event_handler(void *dp_ctx)
290 {
291 	struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx;
292 	struct dp_soc *soc = int_ctx->soc;
293 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
294 	enum umac_reset_rx_event rx_event;
295 	QDF_STATUS status = QDF_STATUS_E_INVAL;
296 	enum umac_reset_action action;
297 
298 	if (!soc) {
299 		dp_umac_reset_err("DP SOC is null");
300 		goto exit;
301 	}
302 
303 	umac_reset_ctx = &soc->umac_reset_ctx;
304 
305 	dp_umac_reset_debug("enter");
306 	rx_event = dp_umac_reset_get_rx_event(umac_reset_ctx);
307 
308 	switch (rx_event) {
309 	case UMAC_RESET_RX_EVENT_NONE:
310 		/* This interrupt is not meant for us, so exit */
311 		dp_umac_reset_debug("Not a UMAC reset event");
312 		status = QDF_STATUS_SUCCESS;
313 		goto exit;
314 
315 	case UMAC_RESET_RX_EVENT_DO_PRE_RESET:
316 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
317 			umac_reset_ctx, rx_event,
318 			UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET,
319 			UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED);
320 
321 		action = UMAC_RESET_ACTION_DO_PRE_RESET;
322 		break;
323 
324 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_START:
325 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
326 			umac_reset_ctx, rx_event,
327 			UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START,
328 			UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED);
329 
330 		action = UMAC_RESET_ACTION_DO_POST_RESET_START;
331 		break;
332 
333 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE:
334 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
335 			umac_reset_ctx, rx_event,
336 			UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE,
337 			UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED);
338 
339 		action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE;
340 		break;
341 
342 	case UMAC_RESET_RX_EVENT_ERROR:
343 		dp_umac_reset_err("Error Rx event");
344 		goto exit;
345 
346 	default:
347 		dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event);
348 		goto exit;
349 	}
350 
351 	/* Call the handler for this event */
352 	if (QDF_IS_STATUS_SUCCESS(status)) {
353 		if (!umac_reset_ctx->rx_actions.cb[action]) {
354 			dp_umac_reset_err("rx callback is NULL");
355 			goto exit;
356 		}
357 
358 		status = umac_reset_ctx->rx_actions.cb[action](soc);
359 	}
360 
361 exit:
362 	return qdf_status_to_os_return(status);
363 }
364 
365 QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc)
366 {
367 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
368 	int msi_vector_count, ret;
369 	uint32_t msi_base_data, msi_vector_start;
370 	uint32_t umac_reset_vector, umac_reset_irq;
371 
372 	if (!soc) {
373 		dp_umac_reset_err("DP SOC is null");
374 		return QDF_STATUS_E_NULL_VALUE;
375 	}
376 
377 	if (!soc->features.umac_hw_reset_support) {
378 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
379 		return QDF_STATUS_SUCCESS;
380 	}
381 
382 	umac_reset_ctx = &soc->umac_reset_ctx;
383 
384 	if (pld_get_enable_intx(soc->osdev->dev)) {
385 		dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode");
386 		return QDF_STATUS_E_FAILURE;
387 	}
388 
389 	ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP",
390 					  &msi_vector_count, &msi_base_data,
391 					  &msi_vector_start);
392 	if (ret) {
393 		dp_umac_reset_err("UMAC reset is only supported in MSI interrupt mode");
394 		return QDF_STATUS_E_FAILURE;
395 	}
396 
397 	if (umac_reset_ctx->intr_offset < 0 ||
398 	    umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) {
399 		dp_umac_reset_err("Invalid interrupt offset");
400 		return QDF_STATUS_E_FAILURE;
401 	}
402 
403 	umac_reset_vector = msi_vector_start +
404 			       (umac_reset_ctx->intr_offset % msi_vector_count);
405 
406 	/* Get IRQ number */
407 	umac_reset_irq = pld_get_msi_irq(soc->osdev->dev, umac_reset_vector);
408 
409 	/* Finally register to this IRQ from HIF layer */
410 	return hif_register_umac_reset_handler(
411 				soc->hif_handle,
412 				dp_umac_reset_rx_event_handler,
413 				&soc->intr_ctx[umac_reset_ctx->intr_offset],
414 				umac_reset_irq);
415 }
416 
417 QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc)
418 {
419 	if (!soc) {
420 		dp_umac_reset_err("DP SOC is null");
421 		return QDF_STATUS_E_NULL_VALUE;
422 	}
423 
424 	if (!soc->features.umac_hw_reset_support) {
425 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
426 		return QDF_STATUS_SUCCESS;
427 	}
428 
429 	return hif_unregister_umac_reset_handler(soc->hif_handle);
430 }
431 
432 QDF_STATUS dp_umac_reset_register_rx_action_callback(
433 			struct dp_soc *soc,
434 			QDF_STATUS (*handler)(struct dp_soc *soc),
435 			enum umac_reset_action action)
436 {
437 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
438 
439 	if (!soc) {
440 		dp_umac_reset_err("DP SOC is null");
441 		return QDF_STATUS_E_NULL_VALUE;
442 	}
443 
444 	if (!soc->features.umac_hw_reset_support) {
445 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
446 		return QDF_STATUS_E_NOSUPPORT;
447 	}
448 
449 	if (action >= UMAC_RESET_ACTION_MAX) {
450 		dp_umac_reset_err("invalid action: %d", action);
451 		return QDF_STATUS_E_INVAL;
452 	}
453 
454 	umac_reset_ctx = &soc->umac_reset_ctx;
455 
456 	umac_reset_ctx->rx_actions.cb[action] = handler;
457 
458 	return QDF_STATUS_SUCCESS;
459 }
460 
461 /**
462  * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory
463  * @umac_reset_ctx: UMAC reset context
464  * @tx_cmd: Tx command to be posted
465  *
466  * Return: QDF status of operation
467  */
468 static QDF_STATUS
469 dp_umac_reset_post_tx_cmd_via_shmem(
470 	struct dp_soc_umac_reset_ctx *umac_reset_ctx,
471 	enum umac_reset_tx_cmd tx_cmd)
472 {
473 	htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr;
474 
475 	shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned;
476 	if (!shmem_vaddr) {
477 		dp_umac_reset_err("Shared memory address is NULL");
478 		return QDF_STATUS_E_NULL_VALUE;
479 	}
480 
481 	switch (tx_cmd) {
482 	case UMAC_RESET_TX_CMD_PRE_RESET_DONE:
483 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET(
484 			shmem_vaddr->h2t_msg, 1);
485 		break;
486 
487 	case UMAC_RESET_TX_CMD_POST_RESET_START_DONE:
488 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_START_DONE_SET(
489 			shmem_vaddr->h2t_msg, 1);
490 		break;
491 
492 	case UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE:
493 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_COMPLETE_DONE_SET(
494 			shmem_vaddr->h2t_msg, 1);
495 		break;
496 
497 	default:
498 		dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd);
499 		return QDF_STATUS_E_FAILURE;
500 	}
501 
502 	return QDF_STATUS_SUCCESS;
503 }
504 
505 /**
506  * dp_umac_reset_notify_target() - Notify the target about completion of action.
507  * @umac_reset_ctx: UMAC reset context
508  *
509  * This API figures out the Tx command that needs to be posted based on the
510  * current state in the state machine. Also, updates the state machine once the
511  * Tx command has been posted.
512  *
513  * Return: QDF status of operation
514  */
515 static QDF_STATUS
516 dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx)
517 {
518 	enum umac_reset_state next_state;
519 	enum umac_reset_tx_cmd tx_cmd;
520 	QDF_STATUS status;
521 
522 	switch (umac_reset_ctx->current_state) {
523 	case UMAC_RESET_STATE_HOST_PRE_RESET_DONE:
524 		tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE;
525 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START;
526 		break;
527 
528 	case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE:
529 		tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_START_DONE;
530 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE;
531 		break;
532 
533 	case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE:
534 		tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE;
535 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET;
536 		break;
537 
538 	default:
539 		dp_umac_reset_err("Invalid state(%d) during Tx",
540 				  umac_reset_ctx->current_state);
541 		qdf_assert_always(0);
542 		return QDF_STATUS_E_FAILURE;
543 	}
544 
545 	status = dp_umac_reset_post_tx_cmd_via_shmem(umac_reset_ctx, tx_cmd);
546 	if (QDF_IS_STATUS_ERROR(status)) {
547 		dp_umac_reset_err("Couldn't post Tx cmd");
548 		qdf_assert_always(0);
549 		return status;
550 	}
551 
552 	/* Update the state machine */
553 	umac_reset_ctx->current_state = next_state;
554 
555 	return status;
556 }
557 
558 /**
559  * dp_umac_reset_notify_completion() - Notify that a given action has been
560  * completed
561  * @soc: DP soc object
562  * @next_state: The state to which the state machine needs to be updated due to
563  * this completion
564  *
565  * Return: QDF status of operation
566  */
567 static QDF_STATUS dp_umac_reset_notify_completion(
568 		struct dp_soc *soc,
569 		enum umac_reset_state next_state)
570 {
571 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
572 
573 	if (!soc) {
574 		dp_umac_reset_err("DP SOC is null");
575 		return QDF_STATUS_E_NULL_VALUE;
576 	}
577 
578 	umac_reset_ctx = &soc->umac_reset_ctx;
579 
580 	/* Update the state first */
581 	umac_reset_ctx->current_state = next_state;
582 
583 	return dp_umac_reset_notify_target(umac_reset_ctx);
584 }
585 
586 QDF_STATUS dp_umac_reset_notify_action_completion(
587 		struct dp_soc *soc,
588 		enum umac_reset_action action)
589 {
590 	enum umac_reset_state next_state;
591 
592 	if (!soc) {
593 		dp_umac_reset_err("DP SOC is null");
594 		return QDF_STATUS_E_NULL_VALUE;
595 	}
596 
597 	if (!soc->features.umac_hw_reset_support) {
598 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
599 		return QDF_STATUS_E_NOSUPPORT;
600 	}
601 
602 	switch (action) {
603 	case UMAC_RESET_ACTION_DO_PRE_RESET:
604 		next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE;
605 		break;
606 
607 	case UMAC_RESET_ACTION_DO_POST_RESET_START:
608 		next_state = UMAC_RESET_STATE_HOST_POST_RESET_START_DONE;
609 		break;
610 
611 	case UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE:
612 		next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE;
613 		break;
614 
615 	default:
616 		dp_umac_reset_err("Invalid action");
617 		return QDF_STATUS_E_FAILURE;
618 	}
619 
620 	return dp_umac_reset_notify_completion(soc, next_state);
621 }
622