evgpeutil.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /******************************************************************************
  3. *
  4. * Module Name: evgpeutil - GPE utilities
  5. *
  6. * Copyright (C) 2000 - 2022, Intel Corp.
  7. *
  8. *****************************************************************************/
  9. #include <acpi/acpi.h>
  10. #include "accommon.h"
  11. #include "acevents.h"
  12. #define _COMPONENT ACPI_EVENTS
  13. ACPI_MODULE_NAME("evgpeutil")
  14. #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
  15. /*******************************************************************************
  16. *
  17. * FUNCTION: acpi_ev_walk_gpe_list
  18. *
  19. * PARAMETERS: gpe_walk_callback - Routine called for each GPE block
  20. * context - Value passed to callback
  21. *
  22. * RETURN: Status
  23. *
  24. * DESCRIPTION: Walk the GPE lists.
  25. *
  26. ******************************************************************************/
  27. acpi_status
  28. acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context)
  29. {
  30. struct acpi_gpe_block_info *gpe_block;
  31. struct acpi_gpe_xrupt_info *gpe_xrupt_info;
  32. acpi_status status = AE_OK;
  33. acpi_cpu_flags flags;
  34. ACPI_FUNCTION_TRACE(ev_walk_gpe_list);
  35. flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  36. /* Walk the interrupt level descriptor list */
  37. gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
  38. while (gpe_xrupt_info) {
  39. /* Walk all Gpe Blocks attached to this interrupt level */
  40. gpe_block = gpe_xrupt_info->gpe_block_list_head;
  41. while (gpe_block) {
  42. /* One callback per GPE block */
  43. status =
  44. gpe_walk_callback(gpe_xrupt_info, gpe_block,
  45. context);
  46. if (ACPI_FAILURE(status)) {
  47. if (status == AE_CTRL_END) { /* Callback abort */
  48. status = AE_OK;
  49. }
  50. goto unlock_and_exit;
  51. }
  52. gpe_block = gpe_block->next;
  53. }
  54. gpe_xrupt_info = gpe_xrupt_info->next;
  55. }
  56. unlock_and_exit:
  57. acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
  58. return_ACPI_STATUS(status);
  59. }
  60. /*******************************************************************************
  61. *
  62. * FUNCTION: acpi_ev_get_gpe_device
  63. *
  64. * PARAMETERS: GPE_WALK_CALLBACK
  65. *
  66. * RETURN: Status
  67. *
  68. * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
  69. * block device. NULL if the GPE is one of the FADT-defined GPEs.
  70. *
  71. ******************************************************************************/
  72. acpi_status
  73. acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
  74. struct acpi_gpe_block_info *gpe_block, void *context)
  75. {
  76. struct acpi_gpe_device_info *info = context;
  77. /* Increment Index by the number of GPEs in this block */
  78. info->next_block_base_index += gpe_block->gpe_count;
  79. if (info->index < info->next_block_base_index) {
  80. /*
  81. * The GPE index is within this block, get the node. Leave the node
  82. * NULL for the FADT-defined GPEs
  83. */
  84. if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
  85. info->gpe_device = gpe_block->node;
  86. }
  87. info->status = AE_OK;
  88. return (AE_CTRL_END);
  89. }
  90. return (AE_OK);
  91. }
  92. /*******************************************************************************
  93. *
  94. * FUNCTION: acpi_ev_get_gpe_xrupt_block
  95. *
  96. * PARAMETERS: interrupt_number - Interrupt for a GPE block
  97. * gpe_xrupt_block - Where the block is returned
  98. *
  99. * RETURN: Status
  100. *
  101. * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
  102. * block per unique interrupt level used for GPEs. Should be
  103. * called only when the GPE lists are semaphore locked and not
  104. * subject to change.
  105. *
  106. ******************************************************************************/
  107. acpi_status
  108. acpi_ev_get_gpe_xrupt_block(u32 interrupt_number,
  109. struct acpi_gpe_xrupt_info **gpe_xrupt_block)
  110. {
  111. struct acpi_gpe_xrupt_info *next_gpe_xrupt;
  112. struct acpi_gpe_xrupt_info *gpe_xrupt;
  113. acpi_status status;
  114. acpi_cpu_flags flags;
  115. ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block);
  116. /* No need for lock since we are not changing any list elements here */
  117. next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
  118. while (next_gpe_xrupt) {
  119. if (next_gpe_xrupt->interrupt_number == interrupt_number) {
  120. *gpe_xrupt_block = next_gpe_xrupt;
  121. return_ACPI_STATUS(AE_OK);
  122. }
  123. next_gpe_xrupt = next_gpe_xrupt->next;
  124. }
  125. /* Not found, must allocate a new xrupt descriptor */
  126. gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));
  127. if (!gpe_xrupt) {
  128. return_ACPI_STATUS(AE_NO_MEMORY);
  129. }
  130. gpe_xrupt->interrupt_number = interrupt_number;
  131. /* Install new interrupt descriptor with spin lock */
  132. flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  133. if (acpi_gbl_gpe_xrupt_list_head) {
  134. next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
  135. while (next_gpe_xrupt->next) {
  136. next_gpe_xrupt = next_gpe_xrupt->next;
  137. }
  138. next_gpe_xrupt->next = gpe_xrupt;
  139. gpe_xrupt->previous = next_gpe_xrupt;
  140. } else {
  141. acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;
  142. }
  143. acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
  144. /* Install new interrupt handler if not SCI_INT */
  145. if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
  146. status = acpi_os_install_interrupt_handler(interrupt_number,
  147. acpi_ev_gpe_xrupt_handler,
  148. gpe_xrupt);
  149. if (ACPI_FAILURE(status)) {
  150. ACPI_EXCEPTION((AE_INFO, status,
  151. "Could not install GPE interrupt handler at level 0x%X",
  152. interrupt_number));
  153. return_ACPI_STATUS(status);
  154. }
  155. }
  156. *gpe_xrupt_block = gpe_xrupt;
  157. return_ACPI_STATUS(AE_OK);
  158. }
  159. /*******************************************************************************
  160. *
  161. * FUNCTION: acpi_ev_delete_gpe_xrupt
  162. *
  163. * PARAMETERS: gpe_xrupt - A GPE interrupt info block
  164. *
  165. * RETURN: Status
  166. *
  167. * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated
  168. * interrupt handler if not the SCI interrupt.
  169. *
  170. ******************************************************************************/
  171. acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
  172. {
  173. acpi_status status;
  174. acpi_cpu_flags flags;
  175. ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt);
  176. /* We never want to remove the SCI interrupt handler */
  177. if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
  178. gpe_xrupt->gpe_block_list_head = NULL;
  179. return_ACPI_STATUS(AE_OK);
  180. }
  181. /* Disable this interrupt */
  182. status =
  183. acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number,
  184. acpi_ev_gpe_xrupt_handler);
  185. if (ACPI_FAILURE(status)) {
  186. return_ACPI_STATUS(status);
  187. }
  188. /* Unlink the interrupt block with lock */
  189. flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  190. if (gpe_xrupt->previous) {
  191. gpe_xrupt->previous->next = gpe_xrupt->next;
  192. } else {
  193. /* No previous, update list head */
  194. acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
  195. }
  196. if (gpe_xrupt->next) {
  197. gpe_xrupt->next->previous = gpe_xrupt->previous;
  198. }
  199. acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
  200. /* Free the block */
  201. ACPI_FREE(gpe_xrupt);
  202. return_ACPI_STATUS(AE_OK);
  203. }
  204. /*******************************************************************************
  205. *
  206. * FUNCTION: acpi_ev_delete_gpe_handlers
  207. *
  208. * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
  209. * gpe_block - Gpe Block info
  210. *
  211. * RETURN: Status
  212. *
  213. * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
  214. * Used only prior to termination.
  215. *
  216. ******************************************************************************/
  217. acpi_status
  218. acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
  219. struct acpi_gpe_block_info *gpe_block,
  220. void *context)
  221. {
  222. struct acpi_gpe_event_info *gpe_event_info;
  223. struct acpi_gpe_notify_info *notify;
  224. struct acpi_gpe_notify_info *next;
  225. u32 i;
  226. u32 j;
  227. ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);
  228. /* Examine each GPE Register within the block */
  229. for (i = 0; i < gpe_block->register_count; i++) {
  230. /* Now look at the individual GPEs in this byte register */
  231. for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
  232. gpe_event_info = &gpe_block->event_info[((acpi_size)i *
  233. ACPI_GPE_REGISTER_WIDTH)
  234. + j];
  235. if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
  236. ACPI_GPE_DISPATCH_HANDLER) ||
  237. (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
  238. ACPI_GPE_DISPATCH_RAW_HANDLER)) {
  239. /* Delete an installed handler block */
  240. ACPI_FREE(gpe_event_info->dispatch.handler);
  241. gpe_event_info->dispatch.handler = NULL;
  242. gpe_event_info->flags &=
  243. ~ACPI_GPE_DISPATCH_MASK;
  244. } else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)
  245. == ACPI_GPE_DISPATCH_NOTIFY) {
  246. /* Delete the implicit notification device list */
  247. notify = gpe_event_info->dispatch.notify_list;
  248. while (notify) {
  249. next = notify->next;
  250. ACPI_FREE(notify);
  251. notify = next;
  252. }
  253. gpe_event_info->dispatch.notify_list = NULL;
  254. gpe_event_info->flags &=
  255. ~ACPI_GPE_DISPATCH_MASK;
  256. }
  257. }
  258. }
  259. return_ACPI_STATUS(AE_OK);
  260. }
  261. #endif /* !ACPI_REDUCED_HARDWARE */