xref: /openbmc/linux/drivers/acpi/acpica/evxfregn.c (revision f4356947)
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
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, space_id, ACPI_REG_CONNECT);
89 	}
90 
91 unlock_and_exit:
92 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
93 	return_ACPI_STATUS(status);
94 }
95 
96 acpi_status
97 acpi_install_address_space_handler(acpi_handle device,
98 				   acpi_adr_space_type space_id,
99 				   acpi_adr_space_handler handler,
100 				   acpi_adr_space_setup setup, void *context)
101 {
102 	return acpi_install_address_space_handler_internal(device, space_id,
103 							   handler, setup,
104 							   context, TRUE);
105 }
106 
107 ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
108 acpi_status
109 acpi_install_address_space_handler_no_reg(acpi_handle device,
110 					  acpi_adr_space_type space_id,
111 					  acpi_adr_space_handler handler,
112 					  acpi_adr_space_setup setup,
113 					  void *context)
114 {
115 	return acpi_install_address_space_handler_internal(device, space_id,
116 							   handler, setup,
117 							   context, FALSE);
118 }
119 
120 ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler_no_reg)
121 
122 /*******************************************************************************
123  *
124  * FUNCTION:    acpi_remove_address_space_handler
125  *
126  * PARAMETERS:  device          - Handle for the device
127  *              space_id        - The address space ID
128  *              handler         - Address of the handler
129  *
130  * RETURN:      Status
131  *
132  * DESCRIPTION: Remove a previously installed handler.
133  *
134  ******************************************************************************/
135 acpi_status
136 acpi_remove_address_space_handler(acpi_handle device,
137 				  acpi_adr_space_type space_id,
138 				  acpi_adr_space_handler handler)
139 {
140 	union acpi_operand_object *obj_desc;
141 	union acpi_operand_object *handler_obj;
142 	union acpi_operand_object *region_obj;
143 	union acpi_operand_object **last_obj_ptr;
144 	struct acpi_namespace_node *node;
145 	acpi_status status;
146 
147 	ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);
148 
149 	/* Parameter validation */
150 
151 	if (!device) {
152 		return_ACPI_STATUS(AE_BAD_PARAMETER);
153 	}
154 
155 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
156 	if (ACPI_FAILURE(status)) {
157 		return_ACPI_STATUS(status);
158 	}
159 
160 	/* Convert and validate the device handle */
161 
162 	node = acpi_ns_validate_handle(device);
163 	if (!node ||
164 	    ((node->type != ACPI_TYPE_DEVICE) &&
165 	     (node->type != ACPI_TYPE_PROCESSOR) &&
166 	     (node->type != ACPI_TYPE_THERMAL) &&
167 	     (node != acpi_gbl_root_node))) {
168 		status = AE_BAD_PARAMETER;
169 		goto unlock_and_exit;
170 	}
171 
172 	/* Make sure the internal object exists */
173 
174 	obj_desc = acpi_ns_get_attached_object(node);
175 	if (!obj_desc) {
176 		status = AE_NOT_EXIST;
177 		goto unlock_and_exit;
178 	}
179 
180 	/* Find the address handler the user requested */
181 
182 	handler_obj = obj_desc->common_notify.handler;
183 	last_obj_ptr = &obj_desc->common_notify.handler;
184 	while (handler_obj) {
185 
186 		/* We have a handler, see if user requested this one */
187 
188 		if (handler_obj->address_space.space_id == space_id) {
189 
190 			/* Handler must be the same as the installed handler */
191 
192 			if (handler_obj->address_space.handler != handler) {
193 				status = AE_BAD_PARAMETER;
194 				goto unlock_and_exit;
195 			}
196 
197 			/* Matched space_id, first dereference this in the Regions */
198 
199 			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
200 					  "Removing address handler %p(%p) for region %s "
201 					  "on Device %p(%p)\n",
202 					  handler_obj, handler,
203 					  acpi_ut_get_region_name(space_id),
204 					  node, obj_desc));
205 
206 			region_obj = handler_obj->address_space.region_list;
207 
208 			/* Walk the handler's region list */
209 
210 			while (region_obj) {
211 				/*
212 				 * First disassociate the handler from the region.
213 				 *
214 				 * NOTE: this doesn't mean that the region goes away
215 				 * The region is just inaccessible as indicated to
216 				 * the _REG method
217 				 */
218 				acpi_ev_detach_region(region_obj, TRUE);
219 
220 				/*
221 				 * Walk the list: Just grab the head because the
222 				 * detach_region removed the previous head.
223 				 */
224 				region_obj =
225 				    handler_obj->address_space.region_list;
226 			}
227 
228 			/* Remove this Handler object from the list */
229 
230 			*last_obj_ptr = handler_obj->address_space.next;
231 
232 			/* Now we can delete the handler object */
233 
234 			acpi_os_release_mutex(handler_obj->address_space.
235 					      context_mutex);
236 			acpi_ut_remove_reference(handler_obj);
237 			goto unlock_and_exit;
238 		}
239 
240 		/* Walk the linked list of handlers */
241 
242 		last_obj_ptr = &handler_obj->address_space.next;
243 		handler_obj = handler_obj->address_space.next;
244 	}
245 
246 	/* The handler does not exist */
247 
248 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
249 			  "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",
250 			  handler, acpi_ut_get_region_name(space_id), space_id,
251 			  node, obj_desc));
252 
253 	status = AE_NOT_EXIST;
254 
255 unlock_and_exit:
256 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
257 	return_ACPI_STATUS(status);
258 }
259 
260 ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
261 /*******************************************************************************
262  *
263  * FUNCTION:    acpi_execute_reg_methods
264  *
265  * PARAMETERS:  device          - Handle for the device
266  *              space_id        - The address space ID
267  *
268  * RETURN:      Status
269  *
270  * DESCRIPTION: Execute _REG for all op_regions of a given space_id.
271  *
272  ******************************************************************************/
273 acpi_status
274 acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id)
275 {
276 	struct acpi_namespace_node *node;
277 	acpi_status status;
278 
279 	ACPI_FUNCTION_TRACE(acpi_execute_reg_methods);
280 
281 	/* Parameter validation */
282 
283 	if (!device) {
284 		return_ACPI_STATUS(AE_BAD_PARAMETER);
285 	}
286 
287 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
288 	if (ACPI_FAILURE(status)) {
289 		return_ACPI_STATUS(status);
290 	}
291 
292 	/* Convert and validate the device handle */
293 
294 	node = acpi_ns_validate_handle(device);
295 	if (node) {
296 
297 		/* Run all _REG methods for this address space */
298 
299 		acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
300 	} else {
301 		status = AE_BAD_PARAMETER;
302 	}
303 
304 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
305 	return_ACPI_STATUS(status);
306 }
307 
308 ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods)
309