1  // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2  /*******************************************************************************
3   *
4   * Module Name: evsci - System Control Interrupt configuration and
5   *                      legacy to ACPI mode state transition functions
6   *
7   ******************************************************************************/
8  
9  #include <acpi/acpi.h>
10  #include "accommon.h"
11  #include "acevents.h"
12  
13  #define _COMPONENT          ACPI_EVENTS
14  ACPI_MODULE_NAME("evsci")
15  #if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
16  /* Local prototypes */
17  static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context);
18  
19  /*******************************************************************************
20   *
21   * FUNCTION:    acpi_ev_sci_dispatch
22   *
23   * PARAMETERS:  None
24   *
25   * RETURN:      Status code indicates whether interrupt was handled.
26   *
27   * DESCRIPTION: Dispatch the SCI to all host-installed SCI handlers.
28   *
29   ******************************************************************************/
30  
acpi_ev_sci_dispatch(void)31  u32 acpi_ev_sci_dispatch(void)
32  {
33  	struct acpi_sci_handler_info *sci_handler;
34  	acpi_cpu_flags flags;
35  	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
36  
37  	ACPI_FUNCTION_NAME(ev_sci_dispatch);
38  
39  	/* Are there any host-installed SCI handlers? */
40  
41  	if (!acpi_gbl_sci_handler_list) {
42  		return (int_status);
43  	}
44  
45  	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
46  
47  	/* Invoke all host-installed SCI handlers */
48  
49  	sci_handler = acpi_gbl_sci_handler_list;
50  	while (sci_handler) {
51  
52  		/* Invoke the installed handler (at interrupt level) */
53  
54  		int_status |= sci_handler->address(sci_handler->context);
55  
56  		sci_handler = sci_handler->next;
57  	}
58  
59  	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
60  	return (int_status);
61  }
62  
63  /*******************************************************************************
64   *
65   * FUNCTION:    acpi_ev_sci_xrupt_handler
66   *
67   * PARAMETERS:  context   - Calling Context
68   *
69   * RETURN:      Status code indicates whether interrupt was handled.
70   *
71   * DESCRIPTION: Interrupt handler that will figure out what function or
72   *              control method to call to deal with a SCI.
73   *
74   ******************************************************************************/
75  
acpi_ev_sci_xrupt_handler(void * context)76  static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
77  {
78  	struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
79  	u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
80  
81  	ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler);
82  
83  	/*
84  	 * We are guaranteed by the ACPICA initialization/shutdown code that
85  	 * if this interrupt handler is installed, ACPI is enabled.
86  	 */
87  
88  	/*
89  	 * Fixed Events:
90  	 * Check for and dispatch any Fixed Events that have occurred
91  	 */
92  	interrupt_handled |= acpi_ev_fixed_event_detect();
93  
94  	/*
95  	 * General Purpose Events:
96  	 * Check for and dispatch any GPEs that have occurred
97  	 */
98  	interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
99  
100  	/* Invoke all host-installed SCI handlers */
101  
102  	interrupt_handled |= acpi_ev_sci_dispatch();
103  
104  	acpi_sci_count++;
105  	return_UINT32(interrupt_handled);
106  }
107  
108  /*******************************************************************************
109   *
110   * FUNCTION:    acpi_ev_gpe_xrupt_handler
111   *
112   * PARAMETERS:  context   - Calling Context
113   *
114   * RETURN:      Status code indicates whether interrupt was handled.
115   *
116   * DESCRIPTION: Handler for GPE Block Device interrupts
117   *
118   ******************************************************************************/
119  
acpi_ev_gpe_xrupt_handler(void * context)120  u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
121  {
122  	struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
123  	u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
124  
125  	ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler);
126  
127  	/*
128  	 * We are guaranteed by the ACPICA initialization/shutdown code that
129  	 * if this interrupt handler is installed, ACPI is enabled.
130  	 */
131  
132  	/* GPEs: Check for and dispatch any GPEs that have occurred */
133  
134  	interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
135  	return_UINT32(interrupt_handled);
136  }
137  
138  /******************************************************************************
139   *
140   * FUNCTION:    acpi_ev_install_sci_handler
141   *
142   * PARAMETERS:  none
143   *
144   * RETURN:      Status
145   *
146   * DESCRIPTION: Installs SCI handler.
147   *
148   ******************************************************************************/
149  
acpi_ev_install_sci_handler(void)150  u32 acpi_ev_install_sci_handler(void)
151  {
152  	u32 status = AE_OK;
153  
154  	ACPI_FUNCTION_TRACE(ev_install_sci_handler);
155  
156  	status =
157  	    acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
158  					      acpi_ev_sci_xrupt_handler,
159  					      acpi_gbl_gpe_xrupt_list_head);
160  	return_ACPI_STATUS(status);
161  }
162  
163  /******************************************************************************
164   *
165   * FUNCTION:    acpi_ev_remove_all_sci_handlers
166   *
167   * PARAMETERS:  none
168   *
169   * RETURN:      AE_OK if handler uninstalled, AE_ERROR if handler was not
170   *              installed to begin with
171   *
172   * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
173   *              taken. Remove all host-installed SCI handlers.
174   *
175   * Note:  It doesn't seem important to disable all events or set the event
176   *        enable registers to their original values. The OS should disable
177   *        the SCI interrupt level when the handler is removed, so no more
178   *        events will come in.
179   *
180   ******************************************************************************/
181  
acpi_ev_remove_all_sci_handlers(void)182  acpi_status acpi_ev_remove_all_sci_handlers(void)
183  {
184  	struct acpi_sci_handler_info *sci_handler;
185  	acpi_cpu_flags flags;
186  	acpi_status status;
187  
188  	ACPI_FUNCTION_TRACE(ev_remove_all_sci_handlers);
189  
190  	/* Just let the OS remove the handler and disable the level */
191  
192  	status =
193  	    acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
194  					     acpi_ev_sci_xrupt_handler);
195  
196  	if (!acpi_gbl_sci_handler_list) {
197  		return (status);
198  	}
199  
200  	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
201  
202  	/* Free all host-installed SCI handlers */
203  
204  	while (acpi_gbl_sci_handler_list) {
205  		sci_handler = acpi_gbl_sci_handler_list;
206  		acpi_gbl_sci_handler_list = sci_handler->next;
207  		ACPI_FREE(sci_handler);
208  	}
209  
210  	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
211  	return_ACPI_STATUS(status);
212  }
213  
214  #endif				/* !ACPI_REDUCED_HARDWARE */
215