1 /******************************************************************************
2 *
3 * Module Name: evhandler - Support for Address Space handlers
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2022, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acevents.h"
47 #include "acnamesp.h"
48 #include "acinterp.h"
49
50 #define _COMPONENT ACPI_EVENTS
51 ACPI_MODULE_NAME ("evhandler")
52
53
54 /* Local prototypes */
55
56 static ACPI_STATUS
57 AcpiEvInstallHandler (
58 ACPI_HANDLE ObjHandle,
59 UINT32 Level,
60 void *Context,
61 void **ReturnValue);
62
63
64 /* These are the address spaces that will get default handlers */
65
66 UINT8 AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] =
67 {
68 ACPI_ADR_SPACE_SYSTEM_MEMORY,
69 ACPI_ADR_SPACE_SYSTEM_IO,
70 ACPI_ADR_SPACE_PCI_CONFIG,
71 ACPI_ADR_SPACE_DATA_TABLE
72 };
73
74
75 /*******************************************************************************
76 *
77 * FUNCTION: AcpiEvInstallRegionHandlers
78 *
79 * PARAMETERS: None
80 *
81 * RETURN: Status
82 *
83 * DESCRIPTION: Installs the core subsystem default address space handlers.
84 *
85 ******************************************************************************/
86
87 ACPI_STATUS
AcpiEvInstallRegionHandlers(void)88 AcpiEvInstallRegionHandlers (
89 void)
90 {
91 ACPI_STATUS Status;
92 UINT32 i;
93
94
95 ACPI_FUNCTION_TRACE (EvInstallRegionHandlers);
96
97
98 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
99 if (ACPI_FAILURE (Status))
100 {
101 return_ACPI_STATUS (Status);
102 }
103
104 /*
105 * All address spaces (PCI Config, EC, SMBus) are scope dependent and
106 * registration must occur for a specific device.
107 *
108 * In the case of the system memory and IO address spaces there is
109 * currently no device associated with the address space. For these we
110 * use the root.
111 *
112 * We install the default PCI config space handler at the root so that
113 * this space is immediately available even though the we have not
114 * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
115 * specification which states that the PCI config space must be always
116 * available -- even though we are nowhere near ready to find the PCI root
117 * buses at this point.
118 *
119 * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
120 * has already been installed (via AcpiInstallAddressSpaceHandler).
121 * Similar for AE_SAME_HANDLER.
122 */
123 for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++)
124 {
125 Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode,
126 AcpiGbl_DefaultAddressSpaces[i],
127 ACPI_DEFAULT_HANDLER, NULL, NULL);
128 switch (Status)
129 {
130 case AE_OK:
131 case AE_SAME_HANDLER:
132 case AE_ALREADY_EXISTS:
133
134 /* These exceptions are all OK */
135
136 Status = AE_OK;
137 break;
138
139 default:
140
141 goto UnlockAndExit;
142 }
143 }
144
145 UnlockAndExit:
146 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
147 return_ACPI_STATUS (Status);
148 }
149
150
151 /*******************************************************************************
152 *
153 * FUNCTION: AcpiEvHasDefaultHandler
154 *
155 * PARAMETERS: Node - Namespace node for the device
156 * SpaceId - The address space ID
157 *
158 * RETURN: TRUE if default handler is installed, FALSE otherwise
159 *
160 * DESCRIPTION: Check if the default handler is installed for the requested
161 * space ID.
162 *
163 ******************************************************************************/
164
165 BOOLEAN
AcpiEvHasDefaultHandler(ACPI_NAMESPACE_NODE * Node,ACPI_ADR_SPACE_TYPE SpaceId)166 AcpiEvHasDefaultHandler (
167 ACPI_NAMESPACE_NODE *Node,
168 ACPI_ADR_SPACE_TYPE SpaceId)
169 {
170 ACPI_OPERAND_OBJECT *ObjDesc;
171 ACPI_OPERAND_OBJECT *HandlerObj;
172
173
174 /* Must have an existing internal object */
175
176 ObjDesc = AcpiNsGetAttachedObject (Node);
177 if (ObjDesc)
178 {
179 HandlerObj = ObjDesc->CommonNotify.Handler;
180
181 /* Walk the linked list of handlers for this object */
182
183 while (HandlerObj)
184 {
185 if (HandlerObj->AddressSpace.SpaceId == SpaceId)
186 {
187 if (HandlerObj->AddressSpace.HandlerFlags &
188 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
189 {
190 return (TRUE);
191 }
192 }
193
194 HandlerObj = HandlerObj->AddressSpace.Next;
195 }
196 }
197
198 return (FALSE);
199 }
200
201
202 /*******************************************************************************
203 *
204 * FUNCTION: AcpiEvInstallHandler
205 *
206 * PARAMETERS: WalkNamespace callback
207 *
208 * DESCRIPTION: This routine installs an address handler into objects that are
209 * of type Region or Device.
210 *
211 * If the Object is a Device, and the device has a handler of
212 * the same type then the search is terminated in that branch.
213 *
214 * This is because the existing handler is closer in proximity
215 * to any more regions than the one we are trying to install.
216 *
217 ******************************************************************************/
218
219 static ACPI_STATUS
AcpiEvInstallHandler(ACPI_HANDLE ObjHandle,UINT32 Level,void * Context,void ** ReturnValue)220 AcpiEvInstallHandler (
221 ACPI_HANDLE ObjHandle,
222 UINT32 Level,
223 void *Context,
224 void **ReturnValue)
225 {
226 ACPI_OPERAND_OBJECT *HandlerObj;
227 ACPI_OPERAND_OBJECT *NextHandlerObj;
228 ACPI_OPERAND_OBJECT *ObjDesc;
229 ACPI_NAMESPACE_NODE *Node;
230 ACPI_STATUS Status;
231
232
233 ACPI_FUNCTION_NAME (EvInstallHandler);
234
235
236 HandlerObj = (ACPI_OPERAND_OBJECT *) Context;
237
238 /* Parameter validation */
239
240 if (!HandlerObj)
241 {
242 return (AE_OK);
243 }
244
245 /* Convert and validate the device handle */
246
247 Node = AcpiNsValidateHandle (ObjHandle);
248 if (!Node)
249 {
250 return (AE_BAD_PARAMETER);
251 }
252
253 /*
254 * We only care about regions and objects that are allowed to have
255 * address space handlers
256 */
257 if ((Node->Type != ACPI_TYPE_DEVICE) &&
258 (Node->Type != ACPI_TYPE_REGION) &&
259 (Node != AcpiGbl_RootNode))
260 {
261 return (AE_OK);
262 }
263
264 /* Check for an existing internal object */
265
266 ObjDesc = AcpiNsGetAttachedObject (Node);
267 if (!ObjDesc)
268 {
269 /* No object, just exit */
270
271 return (AE_OK);
272 }
273
274 /* Devices are handled different than regions */
275
276 if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE)
277 {
278 /* Check if this Device already has a handler for this address space */
279
280 NextHandlerObj = AcpiEvFindRegionHandler (
281 HandlerObj->AddressSpace.SpaceId, ObjDesc->CommonNotify.Handler);
282 if (NextHandlerObj)
283 {
284 /* Found a handler, is it for the same address space? */
285
286 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
287 "Found handler for region [%s] in device %p(%p) handler %p\n",
288 AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId),
289 ObjDesc, NextHandlerObj, HandlerObj));
290
291 /*
292 * Since the object we found it on was a device, then it means
293 * that someone has already installed a handler for the branch
294 * of the namespace from this device on. Just bail out telling
295 * the walk routine to not traverse this branch. This preserves
296 * the scoping rule for handlers.
297 */
298 return (AE_CTRL_DEPTH);
299 }
300
301 /*
302 * As long as the device didn't have a handler for this space we
303 * don't care about it. We just ignore it and proceed.
304 */
305 return (AE_OK);
306 }
307
308 /* Object is a Region */
309
310 if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId)
311 {
312 /* This region is for a different address space, just ignore it */
313
314 return (AE_OK);
315 }
316
317 /*
318 * Now we have a region and it is for the handler's address space type.
319 *
320 * First disconnect region for any previous handler (if any)
321 */
322 AcpiEvDetachRegion (ObjDesc, FALSE);
323
324 /* Connect the region to the new handler */
325
326 Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE);
327 return (Status);
328 }
329
330
331 /*******************************************************************************
332 *
333 * FUNCTION: AcpiEvFindRegionHandler
334 *
335 * PARAMETERS: SpaceId - The address space ID
336 * HandlerObj - Head of the handler object list
337 *
338 * RETURN: Matching handler object. NULL if space ID not matched
339 *
340 * DESCRIPTION: Search a handler object list for a match on the address
341 * space ID.
342 *
343 ******************************************************************************/
344
345 ACPI_OPERAND_OBJECT *
AcpiEvFindRegionHandler(ACPI_ADR_SPACE_TYPE SpaceId,ACPI_OPERAND_OBJECT * HandlerObj)346 AcpiEvFindRegionHandler (
347 ACPI_ADR_SPACE_TYPE SpaceId,
348 ACPI_OPERAND_OBJECT *HandlerObj)
349 {
350
351 /* Walk the handler list for this device */
352
353 while (HandlerObj)
354 {
355 /* Same SpaceId indicates a handler is installed */
356
357 if (HandlerObj->AddressSpace.SpaceId == SpaceId)
358 {
359 return (HandlerObj);
360 }
361
362 /* Next handler object */
363
364 HandlerObj = HandlerObj->AddressSpace.Next;
365 }
366
367 return (NULL);
368 }
369
370
371 /*******************************************************************************
372 *
373 * FUNCTION: AcpiEvInstallSpaceHandler
374 *
375 * PARAMETERS: Node - Namespace node for the device
376 * SpaceId - The address space ID
377 * Handler - Address of the handler
378 * Setup - Address of the setup function
379 * Context - Value passed to the handler on each access
380 *
381 * RETURN: Status
382 *
383 * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId.
384 * Assumes namespace is locked
385 *
386 ******************************************************************************/
387
388 ACPI_STATUS
AcpiEvInstallSpaceHandler(ACPI_NAMESPACE_NODE * Node,ACPI_ADR_SPACE_TYPE SpaceId,ACPI_ADR_SPACE_HANDLER Handler,ACPI_ADR_SPACE_SETUP Setup,void * Context)389 AcpiEvInstallSpaceHandler (
390 ACPI_NAMESPACE_NODE *Node,
391 ACPI_ADR_SPACE_TYPE SpaceId,
392 ACPI_ADR_SPACE_HANDLER Handler,
393 ACPI_ADR_SPACE_SETUP Setup,
394 void *Context)
395 {
396 ACPI_OPERAND_OBJECT *ObjDesc;
397 ACPI_OPERAND_OBJECT *HandlerObj;
398 ACPI_STATUS Status = AE_OK;
399 ACPI_OBJECT_TYPE Type;
400 UINT8 Flags = 0;
401
402
403 ACPI_FUNCTION_TRACE (EvInstallSpaceHandler);
404
405
406 /*
407 * This registration is valid for only the types below and the root.
408 * The root node is where the default handlers get installed.
409 */
410 if ((Node->Type != ACPI_TYPE_DEVICE) &&
411 (Node->Type != ACPI_TYPE_PROCESSOR) &&
412 (Node->Type != ACPI_TYPE_THERMAL) &&
413 (Node != AcpiGbl_RootNode))
414 {
415 Status = AE_BAD_PARAMETER;
416 goto UnlockAndExit;
417 }
418
419 if (Handler == ACPI_DEFAULT_HANDLER)
420 {
421 Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
422
423 switch (SpaceId)
424 {
425 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
426
427 Handler = AcpiExSystemMemorySpaceHandler;
428 Setup = AcpiEvSystemMemoryRegionSetup;
429 break;
430
431 case ACPI_ADR_SPACE_SYSTEM_IO:
432
433 Handler = AcpiExSystemIoSpaceHandler;
434 Setup = AcpiEvIoSpaceRegionSetup;
435 break;
436
437 case ACPI_ADR_SPACE_PCI_CONFIG:
438
439 Handler = AcpiExPciConfigSpaceHandler;
440 Setup = AcpiEvPciConfigRegionSetup;
441 break;
442
443 case ACPI_ADR_SPACE_CMOS:
444
445 Handler = AcpiExCmosSpaceHandler;
446 Setup = AcpiEvCmosRegionSetup;
447 break;
448
449 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
450
451 Handler = AcpiExPciBarSpaceHandler;
452 Setup = AcpiEvPciBarRegionSetup;
453 break;
454
455 case ACPI_ADR_SPACE_DATA_TABLE:
456
457 Handler = AcpiExDataTableSpaceHandler;
458 Setup = AcpiEvDataTableRegionSetup;
459 break;
460
461 default:
462
463 Status = AE_BAD_PARAMETER;
464 goto UnlockAndExit;
465 }
466 }
467
468 /* If the caller hasn't specified a setup routine, use the default */
469
470 if (!Setup)
471 {
472 Setup = AcpiEvDefaultRegionSetup;
473 }
474
475 /* Check for an existing internal object */
476
477 ObjDesc = AcpiNsGetAttachedObject (Node);
478 if (ObjDesc)
479 {
480 /*
481 * The attached device object already exists. Now make sure
482 * the handler is not already installed.
483 */
484 HandlerObj = AcpiEvFindRegionHandler (SpaceId,
485 ObjDesc->CommonNotify.Handler);
486
487 if (HandlerObj)
488 {
489 if (HandlerObj->AddressSpace.Handler == Handler)
490 {
491 /*
492 * It is (relatively) OK to attempt to install the SAME
493 * handler twice. This can easily happen with the
494 * PCI_Config space.
495 */
496 Status = AE_SAME_HANDLER;
497 goto UnlockAndExit;
498 }
499 else
500 {
501 /* A handler is already installed */
502
503 Status = AE_ALREADY_EXISTS;
504 }
505
506 goto UnlockAndExit;
507 }
508 }
509 else
510 {
511 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
512 "Creating object on Device %p while installing handler\n",
513 Node));
514
515 /* ObjDesc does not exist, create one */
516
517 if (Node->Type == ACPI_TYPE_ANY)
518 {
519 Type = ACPI_TYPE_DEVICE;
520 }
521 else
522 {
523 Type = Node->Type;
524 }
525
526 ObjDesc = AcpiUtCreateInternalObject (Type);
527 if (!ObjDesc)
528 {
529 Status = AE_NO_MEMORY;
530 goto UnlockAndExit;
531 }
532
533 /* Init new descriptor */
534
535 ObjDesc->Common.Type = (UINT8) Type;
536
537 /* Attach the new object to the Node */
538
539 Status = AcpiNsAttachObject (Node, ObjDesc, Type);
540
541 /* Remove local reference to the object */
542
543 AcpiUtRemoveReference (ObjDesc);
544
545 if (ACPI_FAILURE (Status))
546 {
547 goto UnlockAndExit;
548 }
549 }
550
551 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
552 "Installing address handler for region %s(%X) "
553 "on Device %4.4s %p(%p)\n",
554 AcpiUtGetRegionName (SpaceId), SpaceId,
555 AcpiUtGetNodeName (Node), Node, ObjDesc));
556
557 /*
558 * Install the handler
559 *
560 * At this point there is no existing handler. Just allocate the object
561 * for the handler and link it into the list.
562 */
563 HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
564 if (!HandlerObj)
565 {
566 Status = AE_NO_MEMORY;
567 goto UnlockAndExit;
568 }
569
570 /* Init handler obj */
571
572 Status = AcpiOsCreateMutex (&HandlerObj->AddressSpace.ContextMutex);
573 if (ACPI_FAILURE (Status))
574 {
575 AcpiUtRemoveReference (HandlerObj);
576 goto UnlockAndExit;
577 }
578
579 HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId;
580 HandlerObj->AddressSpace.HandlerFlags = Flags;
581 HandlerObj->AddressSpace.RegionList = NULL;
582 HandlerObj->AddressSpace.Node = Node;
583 HandlerObj->AddressSpace.Handler = Handler;
584 HandlerObj->AddressSpace.Context = Context;
585 HandlerObj->AddressSpace.Setup = Setup;
586
587 /* Install at head of Device.AddressSpace list */
588
589 HandlerObj->AddressSpace.Next = ObjDesc->CommonNotify.Handler;
590
591 /*
592 * The Device object is the first reference on the HandlerObj.
593 * Each region that uses the handler adds a reference.
594 */
595 ObjDesc->CommonNotify.Handler = HandlerObj;
596
597 /*
598 * Walk the namespace finding all of the regions this handler will
599 * manage.
600 *
601 * Start at the device and search the branch toward the leaf nodes
602 * until either the leaf is encountered or a device is detected that
603 * has an address handler of the same type.
604 *
605 * In either case, back up and search down the remainder of the branch
606 */
607 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node,
608 ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
609 AcpiEvInstallHandler, NULL, HandlerObj, NULL);
610
611 UnlockAndExit:
612 return_ACPI_STATUS (Status);
613 }
614