xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_umac_reset.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
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 		umac_reset_ctx->ts.pre_reset_start =
317 						qdf_get_log_timestamp_usecs();
318 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
319 			umac_reset_ctx, rx_event,
320 			UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET,
321 			UMAC_RESET_STATE_DO_PRE_RESET_RECEIVED);
322 
323 		action = UMAC_RESET_ACTION_DO_PRE_RESET;
324 		break;
325 
326 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_START:
327 		umac_reset_ctx->ts.post_reset_start =
328 						qdf_get_log_timestamp_usecs();
329 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
330 			umac_reset_ctx, rx_event,
331 			UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START,
332 			UMAC_RESET_STATE_DO_POST_RESET_START_RECEIVED);
333 
334 		action = UMAC_RESET_ACTION_DO_POST_RESET_START;
335 		break;
336 
337 	case UMAC_RESET_RX_EVENT_DO_POST_RESET_COMPELTE:
338 		umac_reset_ctx->ts.post_reset_complete_start =
339 						qdf_get_log_timestamp_usecs();
340 		status = dp_umac_reset_validate_n_update_state_machine_on_rx(
341 			umac_reset_ctx, rx_event,
342 			UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE,
343 			UMAC_RESET_STATE_DO_POST_RESET_COMPLETE_RECEIVED);
344 
345 		action = UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE;
346 		break;
347 
348 	case UMAC_RESET_RX_EVENT_ERROR:
349 		dp_umac_reset_err("Error Rx event");
350 		goto exit;
351 
352 	default:
353 		dp_umac_reset_err("Invalid value(%u) for Rx event", rx_event);
354 		goto exit;
355 	}
356 
357 	/* Call the handler for this event */
358 	if (QDF_IS_STATUS_SUCCESS(status)) {
359 		if (!umac_reset_ctx->rx_actions.cb[action]) {
360 			dp_umac_reset_err("rx callback is NULL");
361 			goto exit;
362 		}
363 
364 		status = umac_reset_ctx->rx_actions.cb[action](soc);
365 	}
366 
367 exit:
368 	return qdf_status_to_os_return(status);
369 }
370 
371 QDF_STATUS dp_umac_reset_interrupt_attach(struct dp_soc *soc)
372 {
373 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
374 	int msi_vector_count, ret;
375 	uint32_t msi_base_data, msi_vector_start;
376 	uint32_t umac_reset_vector, umac_reset_irq;
377 
378 	if (!soc) {
379 		dp_umac_reset_err("DP SOC is null");
380 		return QDF_STATUS_E_NULL_VALUE;
381 	}
382 
383 	if (!soc->features.umac_hw_reset_support) {
384 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
385 		return QDF_STATUS_SUCCESS;
386 	}
387 
388 	umac_reset_ctx = &soc->umac_reset_ctx;
389 
390 	if (pld_get_enable_intx(soc->osdev->dev)) {
391 		dp_umac_reset_err("UMAC reset is not supported in legacy interrupt mode");
392 		return QDF_STATUS_E_FAILURE;
393 	}
394 
395 	ret = pld_get_user_msi_assignment(soc->osdev->dev, "DP",
396 					  &msi_vector_count, &msi_base_data,
397 					  &msi_vector_start);
398 	if (ret) {
399 		dp_umac_reset_err("UMAC reset is only supported in MSI interrupt mode");
400 		return QDF_STATUS_E_FAILURE;
401 	}
402 
403 	if (umac_reset_ctx->intr_offset < 0 ||
404 	    umac_reset_ctx->intr_offset >= WLAN_CFG_INT_NUM_CONTEXTS) {
405 		dp_umac_reset_err("Invalid interrupt offset");
406 		return QDF_STATUS_E_FAILURE;
407 	}
408 
409 	umac_reset_vector = msi_vector_start +
410 			       (umac_reset_ctx->intr_offset % msi_vector_count);
411 
412 	/* Get IRQ number */
413 	umac_reset_irq = pld_get_msi_irq(soc->osdev->dev, umac_reset_vector);
414 
415 	/* Finally register to this IRQ from HIF layer */
416 	return hif_register_umac_reset_handler(
417 				soc->hif_handle,
418 				dp_umac_reset_rx_event_handler,
419 				&soc->intr_ctx[umac_reset_ctx->intr_offset],
420 				umac_reset_irq);
421 }
422 
423 QDF_STATUS dp_umac_reset_interrupt_detach(struct dp_soc *soc)
424 {
425 	if (!soc) {
426 		dp_umac_reset_err("DP SOC is null");
427 		return QDF_STATUS_E_NULL_VALUE;
428 	}
429 
430 	if (!soc->features.umac_hw_reset_support) {
431 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
432 		return QDF_STATUS_SUCCESS;
433 	}
434 
435 	return hif_unregister_umac_reset_handler(soc->hif_handle);
436 }
437 
438 QDF_STATUS dp_umac_reset_register_rx_action_callback(
439 			struct dp_soc *soc,
440 			QDF_STATUS (*handler)(struct dp_soc *soc),
441 			enum umac_reset_action action)
442 {
443 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
444 
445 	if (!soc) {
446 		dp_umac_reset_err("DP SOC is null");
447 		return QDF_STATUS_E_NULL_VALUE;
448 	}
449 
450 	if (!soc->features.umac_hw_reset_support) {
451 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
452 		return QDF_STATUS_E_NOSUPPORT;
453 	}
454 
455 	if (action >= UMAC_RESET_ACTION_MAX) {
456 		dp_umac_reset_err("invalid action: %d", action);
457 		return QDF_STATUS_E_INVAL;
458 	}
459 
460 	umac_reset_ctx = &soc->umac_reset_ctx;
461 
462 	umac_reset_ctx->rx_actions.cb[action] = handler;
463 
464 	return QDF_STATUS_SUCCESS;
465 }
466 
467 /**
468  * dp_umac_reset_post_tx_cmd_via_shmem() - Post Tx command using shared memory
469  * @umac_reset_ctx: UMAC reset context
470  * @tx_cmd: Tx command to be posted
471  *
472  * Return: QDF status of operation
473  */
474 static QDF_STATUS
475 dp_umac_reset_post_tx_cmd_via_shmem(
476 	struct dp_soc_umac_reset_ctx *umac_reset_ctx,
477 	enum umac_reset_tx_cmd tx_cmd)
478 {
479 	htt_umac_hang_recovery_msg_shmem_t *shmem_vaddr;
480 
481 	shmem_vaddr = umac_reset_ctx->shmem_vaddr_aligned;
482 	if (!shmem_vaddr) {
483 		dp_umac_reset_err("Shared memory address is NULL");
484 		return QDF_STATUS_E_NULL_VALUE;
485 	}
486 
487 	switch (tx_cmd) {
488 	case UMAC_RESET_TX_CMD_PRE_RESET_DONE:
489 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_PRE_RESET_DONE_SET(
490 			shmem_vaddr->h2t_msg, 1);
491 
492 		umac_reset_ctx->ts.pre_reset_done =
493 						qdf_get_log_timestamp_usecs();
494 		break;
495 
496 	case UMAC_RESET_TX_CMD_POST_RESET_START_DONE:
497 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_START_DONE_SET(
498 			shmem_vaddr->h2t_msg, 1);
499 
500 		umac_reset_ctx->ts.post_reset_done =
501 						qdf_get_log_timestamp_usecs();
502 		break;
503 
504 	case UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE:
505 		HTT_UMAC_HANG_RECOVERY_MSG_SHMEM_POST_RESET_COMPLETE_DONE_SET(
506 			shmem_vaddr->h2t_msg, 1);
507 
508 		umac_reset_ctx->ts.post_reset_complete_done =
509 						qdf_get_log_timestamp_usecs();
510 		break;
511 
512 	default:
513 		dp_umac_reset_err("Invalid tx cmd: %d", tx_cmd);
514 		return QDF_STATUS_E_FAILURE;
515 	}
516 
517 	return QDF_STATUS_SUCCESS;
518 }
519 
520 /**
521  * dp_umac_reset_notify_target() - Notify the target about completion of action.
522  * @umac_reset_ctx: UMAC reset context
523  *
524  * This API figures out the Tx command that needs to be posted based on the
525  * current state in the state machine. Also, updates the state machine once the
526  * Tx command has been posted.
527  *
528  * Return: QDF status of operation
529  */
530 static QDF_STATUS
531 dp_umac_reset_notify_target(struct dp_soc_umac_reset_ctx *umac_reset_ctx)
532 {
533 	enum umac_reset_state next_state;
534 	enum umac_reset_tx_cmd tx_cmd;
535 	QDF_STATUS status;
536 
537 	switch (umac_reset_ctx->current_state) {
538 	case UMAC_RESET_STATE_HOST_PRE_RESET_DONE:
539 		tx_cmd = UMAC_RESET_TX_CMD_PRE_RESET_DONE;
540 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_START;
541 		break;
542 
543 	case UMAC_RESET_STATE_HOST_POST_RESET_START_DONE:
544 		tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_START_DONE;
545 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_POST_RESET_COMPLETE;
546 		break;
547 
548 	case UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE:
549 		tx_cmd = UMAC_RESET_TX_CMD_POST_RESET_COMPLETE_DONE;
550 		next_state = UMAC_RESET_STATE_WAIT_FOR_DO_PRE_RESET;
551 		break;
552 
553 	default:
554 		dp_umac_reset_err("Invalid state(%d) during Tx",
555 				  umac_reset_ctx->current_state);
556 		qdf_assert_always(0);
557 		return QDF_STATUS_E_FAILURE;
558 	}
559 
560 	status = dp_umac_reset_post_tx_cmd_via_shmem(umac_reset_ctx, tx_cmd);
561 	if (QDF_IS_STATUS_ERROR(status)) {
562 		dp_umac_reset_err("Couldn't post Tx cmd");
563 		qdf_assert_always(0);
564 		return status;
565 	}
566 
567 	/* Update the state machine */
568 	umac_reset_ctx->current_state = next_state;
569 
570 	return status;
571 }
572 
573 /**
574  * dp_umac_reset_notify_completion() - Notify that a given action has been
575  * completed
576  * @soc: DP soc object
577  * @next_state: The state to which the state machine needs to be updated due to
578  * this completion
579  *
580  * Return: QDF status of operation
581  */
582 static QDF_STATUS dp_umac_reset_notify_completion(
583 		struct dp_soc *soc,
584 		enum umac_reset_state next_state)
585 {
586 	struct dp_soc_umac_reset_ctx *umac_reset_ctx;
587 
588 	if (!soc) {
589 		dp_umac_reset_err("DP SOC is null");
590 		return QDF_STATUS_E_NULL_VALUE;
591 	}
592 
593 	umac_reset_ctx = &soc->umac_reset_ctx;
594 
595 	/* Update the state first */
596 	umac_reset_ctx->current_state = next_state;
597 
598 	return dp_umac_reset_notify_target(umac_reset_ctx);
599 }
600 
601 QDF_STATUS dp_umac_reset_notify_action_completion(
602 		struct dp_soc *soc,
603 		enum umac_reset_action action)
604 {
605 	enum umac_reset_state next_state;
606 
607 	if (!soc) {
608 		dp_umac_reset_err("DP SOC is null");
609 		return QDF_STATUS_E_NULL_VALUE;
610 	}
611 
612 	if (!soc->features.umac_hw_reset_support) {
613 		dp_umac_reset_info("Target doesn't support the UMAC HW reset feature");
614 		return QDF_STATUS_E_NOSUPPORT;
615 	}
616 
617 	switch (action) {
618 	case UMAC_RESET_ACTION_DO_PRE_RESET:
619 		next_state = UMAC_RESET_STATE_HOST_PRE_RESET_DONE;
620 		break;
621 
622 	case UMAC_RESET_ACTION_DO_POST_RESET_START:
623 		next_state = UMAC_RESET_STATE_HOST_POST_RESET_START_DONE;
624 		break;
625 
626 	case UMAC_RESET_ACTION_DO_POST_RESET_COMPLETE:
627 		next_state = UMAC_RESET_STATE_HOST_POST_RESET_COMPLETE_DONE;
628 		break;
629 
630 	default:
631 		dp_umac_reset_err("Invalid action");
632 		return QDF_STATUS_E_FAILURE;
633 	}
634 
635 	return dp_umac_reset_notify_completion(soc, next_state);
636 }
637