xref: /openbmc/linux/drivers/acpi/acpica/evxfregn.c (revision 03fd525d)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
5  *                         Address Spaces.
6  *
7  * Copyright (C) 2000 - 2023, Intel Corp.
8  *
9  *****************************************************************************/
10 
11 #define EXPORT_ACPI_INTERFACES
12 
13 #include <acpi/acpi.h>
14 #include "accommon.h"
15 #include "acnamesp.h"
16 #include "acevents.h"
17 
18 #define _COMPONENT          ACPI_EVENTS
19 ACPI_MODULE_NAME("evxfregn")
20 
21 /*******************************************************************************
22  *
23  * FUNCTION:    acpi_install_address_space_handler_internal
24  *
25  * PARAMETERS:  device          - Handle for the device
26  *              space_id        - The address space ID
27  *              handler         - Address of the handler
28  *              setup           - Address of the setup function
29  *              context         - Value passed to the handler on each access
30  *              Run_reg         - Run _REG methods for this address space?
31  *
32  * RETURN:      Status
33  *
34  * DESCRIPTION: Install a handler for all op_regions of a given space_id.
35  *
36  * NOTE: This function should only be called after acpi_enable_subsystem has
37  * been called. This is because any _REG methods associated with the Space ID
38  * are executed here, and these methods can only be safely executed after
39  * the default handlers have been installed and the hardware has been
40  * initialized (via acpi_enable_subsystem.)
41  * To avoid this problem pass FALSE for Run_Reg and later on call
42  * acpi_execute_reg_methods() to execute _REG.
43  *
44  ******************************************************************************/
45 static acpi_status
acpi_install_address_space_handler_internal(acpi_handle device,acpi_adr_space_type space_id,acpi_adr_space_handler handler,acpi_adr_space_setup setup,void * context,u8 run_reg)46 acpi_install_address_space_handler_internal(acpi_handle device,
47 					    acpi_adr_space_type space_id,
48 					    acpi_adr_space_handler handler,
49 					    acpi_adr_space_setup setup,
50 					    void *context, u8 run_reg)
51 {
52 	struct acpi_namespace_node *node;
53 	acpi_status status;
54 
55 	ACPI_FUNCTION_TRACE(acpi_install_address_space_handler);
56 
57 	/* Parameter validation */
58 
59 	if (!device) {
60 		return_ACPI_STATUS(AE_BAD_PARAMETER);
61 	}
62 
63 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
64 	if (ACPI_FAILURE(status)) {
65 		return_ACPI_STATUS(status);
66 	}
67 
68 	/* Convert and validate the device handle */
69 
70 	node = acpi_ns_validate_handle(device);
71 	if (!node) {
72 		status = AE_BAD_PARAMETER;
73 		goto unlock_and_exit;
74 	}
75 
76 	/* Install the handler for all Regions for this Space ID */
77 
78 	status =
79 	    acpi_ev_install_space_handler(node, space_id, handler, setup,
80 					  context);
81 	if (ACPI_FAILURE(status)) {
82 		goto unlock_and_exit;
83 	}
84 
85 	/* Run all _REG methods for this address space */
86 
87 	if (run_reg) {
88 		acpi_ev_execute_reg_methods(node, ACPI_UINT32_MAX, space_id,
89 					    ACPI_REG_CONNECT);
90 	}
91 
92 unlock_and_exit:
93 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
94 	return_ACPI_STATUS(status);
95 }
96 
97 acpi_status
acpi_install_address_space_handler(acpi_handle device,acpi_adr_space_type space_id,acpi_adr_space_handler handler,acpi_adr_space_setup setup,void * context)98 acpi_install_address_space_handler(acpi_handle device,
99 				   acpi_adr_space_type space_id,
100 				   acpi_adr_space_handler handler,
101 				   acpi_adr_space_setup setup, void *context)
102 {
103 	return acpi_install_address_space_handler_internal(device, space_id,
104 							   handler, setup,
105 							   context, TRUE);
106 }
107 
ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)108 ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
109 acpi_status
110 acpi_install_address_space_handler_no_reg(acpi_handle device,
111 					  acpi_adr_space_type space_id,
112 					  acpi_adr_space_handler handler,
113 					  acpi_adr_space_setup setup,
114 					  void *context)
115 {
116 	return acpi_install_address_space_handler_internal(device, space_id,
117 							   handler, setup,
118 							   context, FALSE);
119 }
120 
ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler_no_reg)121 ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler_no_reg)
122 
123 /*******************************************************************************
124  *
125  * FUNCTION:    acpi_remove_address_space_handler
126  *
127  * PARAMETERS:  device          - Handle for the device
128  *              space_id        - The address space ID
129  *              handler         - Address of the handler
130  *
131  * RETURN:      Status
132  *
133  * DESCRIPTION: Remove a previously installed handler.
134  *
135  ******************************************************************************/
136 acpi_status
137 acpi_remove_address_space_handler(acpi_handle device,
138 				  acpi_adr_space_type space_id,
139 				  acpi_adr_space_handler handler)
140 {
141 	union acpi_operand_object *obj_desc;
142 	union acpi_operand_object *handler_obj;
143 	union acpi_operand_object *region_obj;
144 	union acpi_operand_object **last_obj_ptr;
145 	struct acpi_namespace_node *node;
146 	acpi_status status;
147 
148 	ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);
149 
150 	/* Parameter validation */
151 
152 	if (!device) {
153 		return_ACPI_STATUS(AE_BAD_PARAMETER);
154 	}
155 
156 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
157 	if (ACPI_FAILURE(status)) {
158 		return_ACPI_STATUS(status);
159 	}
160 
161 	/* Convert and validate the device handle */
162 
163 	node = acpi_ns_validate_handle(device);
164 	if (!node ||
165 	    ((node->type != ACPI_TYPE_DEVICE) &&
166 	     (node->type != ACPI_TYPE_PROCESSOR) &&
167 	     (node->type != ACPI_TYPE_THERMAL) &&
168 	     (node != acpi_gbl_root_node))) {
169 		status = AE_BAD_PARAMETER;
170 		goto unlock_and_exit;
171 	}
172 
173 	/* Make sure the internal object exists */
174 
175 	obj_desc = acpi_ns_get_attached_object(node);
176 	if (!obj_desc) {
177 		status = AE_NOT_EXIST;
178 		goto unlock_and_exit;
179 	}
180 
181 	/* Find the address handler the user requested */
182 
183 	handler_obj = obj_desc->common_notify.handler;
184 	last_obj_ptr = &obj_desc->common_notify.handler;
185 	while (handler_obj) {
186 
187 		/* We have a handler, see if user requested this one */
188 
189 		if (handler_obj->address_space.space_id == space_id) {
190 
191 			/* Handler must be the same as the installed handler */
192 
193 			if (handler_obj->address_space.handler != handler) {
194 				status = AE_BAD_PARAMETER;
195 				goto unlock_and_exit;
196 			}
197 
198 			/* Matched space_id, first dereference this in the Regions */
199 
200 			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
201 					  "Removing address handler %p(%p) for region %s "
202 					  "on Device %p(%p)\n",
203 					  handler_obj, handler,
204 					  acpi_ut_get_region_name(space_id),
205 					  node, obj_desc));
206 
207 			region_obj = handler_obj->address_space.region_list;
208 
209 			/* Walk the handler's region list */
210 
211 			while (region_obj) {
212 				/*
213 				 * First disassociate the handler from the region.
214 				 *
215 				 * NOTE: this doesn't mean that the region goes away
216 				 * The region is just inaccessible as indicated to
217 				 * the _REG method
218 				 */
219 				acpi_ev_detach_region(region_obj, TRUE);
220 
221 				/*
222 				 * Walk the list: Just grab the head because the
223 				 * detach_region removed the previous head.
224 				 */
225 				region_obj =
226 				    handler_obj->address_space.region_list;
227 			}
228 
229 			/* Remove this Handler object from the list */
230 
231 			*last_obj_ptr = handler_obj->address_space.next;
232 
233 			/* Now we can delete the handler object */
234 
235 			acpi_os_release_mutex(handler_obj->address_space.
236 					      context_mutex);
237 			acpi_ut_remove_reference(handler_obj);
238 			goto unlock_and_exit;
239 		}
240 
241 		/* Walk the linked list of handlers */
242 
243 		last_obj_ptr = &handler_obj->address_space.next;
244 		handler_obj = handler_obj->address_space.next;
245 	}
246 
247 	/* The handler does not exist */
248 
249 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
250 			  "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",
251 			  handler, acpi_ut_get_region_name(space_id), space_id,
252 			  node, obj_desc));
253 
254 	status = AE_NOT_EXIST;
255 
256 unlock_and_exit:
257 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
258 	return_ACPI_STATUS(status);
259 }
260 
ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)261 ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
262 /*******************************************************************************
263  *
264  * FUNCTION:    acpi_execute_reg_methods
265  *
266  * PARAMETERS:  device          - Handle for the device
267  *              max_depth       - Depth to which search for _REG
268  *              space_id        - The address space ID
269  *
270  * RETURN:      Status
271  *
272  * DESCRIPTION: Execute _REG for all op_regions of a given space_id.
273  *
274  ******************************************************************************/
275 acpi_status
276 acpi_execute_reg_methods(acpi_handle device, u32 max_depth,
277 			 acpi_adr_space_type space_id)
278 {
279 	struct acpi_namespace_node *node;
280 	acpi_status status;
281 
282 	ACPI_FUNCTION_TRACE(acpi_execute_reg_methods);
283 
284 	/* Parameter validation */
285 
286 	if (!device) {
287 		return_ACPI_STATUS(AE_BAD_PARAMETER);
288 	}
289 
290 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
291 	if (ACPI_FAILURE(status)) {
292 		return_ACPI_STATUS(status);
293 	}
294 
295 	/* Convert and validate the device handle */
296 
297 	node = acpi_ns_validate_handle(device);
298 	if (node) {
299 
300 		/* Run all _REG methods for this address space */
301 
302 		acpi_ev_execute_reg_methods(node, max_depth, space_id,
303 					    ACPI_REG_CONNECT);
304 	} else {
305 		status = AE_BAD_PARAMETER;
306 	}
307 
308 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
309 	return_ACPI_STATUS(status);
310 }
311 
312 ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods)
313