dp_umac_reset.c 28 KB

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