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