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(¶ms, 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, ¶ms);
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