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 310 /******************************************************************************* 311 * 312 * FUNCTION: acpi_execute_orphan_reg_method 313 * 314 * PARAMETERS: device - Handle for the device 315 * space_id - The address space ID 316 * 317 * RETURN: Status 318 * 319 * DESCRIPTION: Execute an "orphan" _REG method that appears under an ACPI 320 * device. This is a _REG method that has no corresponding region 321 * within the device's scope. 322 * 323 ******************************************************************************/ 324 acpi_status 325 acpi_execute_orphan_reg_method(acpi_handle device, acpi_adr_space_type space_id) 326 { 327 struct acpi_namespace_node *node; 328 acpi_status status; 329 330 ACPI_FUNCTION_TRACE(acpi_execute_orphan_reg_method); 331 332 /* Parameter validation */ 333 334 if (!device) { 335 return_ACPI_STATUS(AE_BAD_PARAMETER); 336 } 337 338 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 339 if (ACPI_FAILURE(status)) { 340 return_ACPI_STATUS(status); 341 } 342 343 /* Convert and validate the device handle */ 344 345 node = acpi_ns_validate_handle(device); 346 if (node) { 347 348 /* 349 * If an "orphan" _REG method is present in the device's scope 350 * for the given address space ID, run it. 351 */ 352 353 acpi_ev_execute_orphan_reg_method(node, space_id); 354 } else { 355 status = AE_BAD_PARAMETER; 356 } 357 358 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 359 return_ACPI_STATUS(status); 360 } 361 362 ACPI_EXPORT_SYMBOL(acpi_execute_orphan_reg_method) 363