dp_umac_reset.c 28 KB

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