xref: /freebsd/sys/contrib/dev/acpica/components/events/evrgnini.c (revision 076ad2f836d5f49dc1375f1677335a48fe0d4b82)
1 /******************************************************************************
2  *
3  * Module Name: evrgnini- ACPI AddressSpace (OpRegion) init
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, 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 #include <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/acevents.h>
47 #include <contrib/dev/acpica/include/acnamesp.h>
48 #include <contrib/dev/acpica/include/acinterp.h>
49 
50 #define _COMPONENT          ACPI_EVENTS
51         ACPI_MODULE_NAME    ("evrgnini")
52 
53 /* Local prototypes */
54 
55 static BOOLEAN
56 AcpiEvIsPciRootBridge (
57     ACPI_NAMESPACE_NODE     *Node);
58 
59 
60 /*******************************************************************************
61  *
62  * FUNCTION:    AcpiEvSystemMemoryRegionSetup
63  *
64  * PARAMETERS:  Handle              - Region we are interested in
65  *              Function            - Start or stop
66  *              HandlerContext      - Address space handler context
67  *              RegionContext       - Region specific context
68  *
69  * RETURN:      Status
70  *
71  * DESCRIPTION: Setup a SystemMemory operation region
72  *
73  ******************************************************************************/
74 
75 ACPI_STATUS
76 AcpiEvSystemMemoryRegionSetup (
77     ACPI_HANDLE             Handle,
78     UINT32                  Function,
79     void                    *HandlerContext,
80     void                    **RegionContext)
81 {
82     ACPI_OPERAND_OBJECT     *RegionDesc = (ACPI_OPERAND_OBJECT *) Handle;
83     ACPI_MEM_SPACE_CONTEXT  *LocalRegionContext;
84 
85 
86     ACPI_FUNCTION_TRACE (EvSystemMemoryRegionSetup);
87 
88 
89     if (Function == ACPI_REGION_DEACTIVATE)
90     {
91         if (*RegionContext)
92         {
93             LocalRegionContext = (ACPI_MEM_SPACE_CONTEXT *) *RegionContext;
94 
95             /* Delete a cached mapping if present */
96 
97             if (LocalRegionContext->MappedLength)
98             {
99                 AcpiOsUnmapMemory (LocalRegionContext->MappedLogicalAddress,
100                     LocalRegionContext->MappedLength);
101             }
102             ACPI_FREE (LocalRegionContext);
103             *RegionContext = NULL;
104         }
105         return_ACPI_STATUS (AE_OK);
106     }
107 
108     /* Create a new context */
109 
110     LocalRegionContext = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_MEM_SPACE_CONTEXT));
111     if (!(LocalRegionContext))
112     {
113         return_ACPI_STATUS (AE_NO_MEMORY);
114     }
115 
116     /* Save the region length and address for use in the handler */
117 
118     LocalRegionContext->Length  = RegionDesc->Region.Length;
119     LocalRegionContext->Address = RegionDesc->Region.Address;
120 
121     *RegionContext = LocalRegionContext;
122     return_ACPI_STATUS (AE_OK);
123 }
124 
125 
126 /*******************************************************************************
127  *
128  * FUNCTION:    AcpiEvIoSpaceRegionSetup
129  *
130  * PARAMETERS:  Handle              - Region we are interested in
131  *              Function            - Start or stop
132  *              HandlerContext      - Address space handler context
133  *              RegionContext       - Region specific context
134  *
135  * RETURN:      Status
136  *
137  * DESCRIPTION: Setup a IO operation region
138  *
139  ******************************************************************************/
140 
141 ACPI_STATUS
142 AcpiEvIoSpaceRegionSetup (
143     ACPI_HANDLE             Handle,
144     UINT32                  Function,
145     void                    *HandlerContext,
146     void                    **RegionContext)
147 {
148     ACPI_FUNCTION_TRACE (EvIoSpaceRegionSetup);
149 
150 
151     if (Function == ACPI_REGION_DEACTIVATE)
152     {
153         *RegionContext = NULL;
154     }
155     else
156     {
157         *RegionContext = HandlerContext;
158     }
159 
160     return_ACPI_STATUS (AE_OK);
161 }
162 
163 
164 /*******************************************************************************
165  *
166  * FUNCTION:    AcpiEvPciConfigRegionSetup
167  *
168  * PARAMETERS:  Handle              - Region we are interested in
169  *              Function            - Start or stop
170  *              HandlerContext      - Address space handler context
171  *              RegionContext       - Region specific context
172  *
173  * RETURN:      Status
174  *
175  * DESCRIPTION: Setup a PCI_Config operation region
176  *
177  * MUTEX:       Assumes namespace is not locked
178  *
179  ******************************************************************************/
180 
181 ACPI_STATUS
182 AcpiEvPciConfigRegionSetup (
183     ACPI_HANDLE             Handle,
184     UINT32                  Function,
185     void                    *HandlerContext,
186     void                    **RegionContext)
187 {
188     ACPI_STATUS             Status = AE_OK;
189     UINT64                  PciValue;
190     ACPI_PCI_ID             *PciId = *RegionContext;
191     ACPI_OPERAND_OBJECT     *HandlerObj;
192     ACPI_NAMESPACE_NODE     *ParentNode;
193     ACPI_NAMESPACE_NODE     *PciRootNode;
194     ACPI_NAMESPACE_NODE     *PciDeviceNode;
195     ACPI_OPERAND_OBJECT     *RegionObj = (ACPI_OPERAND_OBJECT  *) Handle;
196 
197 
198     ACPI_FUNCTION_TRACE (EvPciConfigRegionSetup);
199 
200 
201     HandlerObj = RegionObj->Region.Handler;
202     if (!HandlerObj)
203     {
204         /*
205          * No installed handler. This shouldn't happen because the dispatch
206          * routine checks before we get here, but we check again just in case.
207          */
208         ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
209             "Attempting to init a region %p, with no handler\n", RegionObj));
210         return_ACPI_STATUS (AE_NOT_EXIST);
211     }
212 
213     *RegionContext = NULL;
214     if (Function == ACPI_REGION_DEACTIVATE)
215     {
216         if (PciId)
217         {
218             ACPI_FREE (PciId);
219         }
220         return_ACPI_STATUS (Status);
221     }
222 
223     ParentNode = RegionObj->Region.Node->Parent;
224 
225     /*
226      * Get the _SEG and _BBN values from the device upon which the handler
227      * is installed.
228      *
229      * We need to get the _SEG and _BBN objects relative to the PCI BUS device.
230      * This is the device the handler has been registered to handle.
231      */
232 
233     /*
234      * If the AddressSpace.Node is still pointing to the root, we need
235      * to scan upward for a PCI Root bridge and re-associate the OpRegion
236      * handlers with that device.
237      */
238     if (HandlerObj->AddressSpace.Node == AcpiGbl_RootNode)
239     {
240         /* Start search from the parent object */
241 
242         PciRootNode = ParentNode;
243         while (PciRootNode != AcpiGbl_RootNode)
244         {
245             /* Get the _HID/_CID in order to detect a RootBridge */
246 
247             if (AcpiEvIsPciRootBridge (PciRootNode))
248             {
249                 /* Install a handler for this PCI root bridge */
250 
251                 Status = AcpiInstallAddressSpaceHandler (
252                     (ACPI_HANDLE) PciRootNode,
253                     ACPI_ADR_SPACE_PCI_CONFIG,
254                     ACPI_DEFAULT_HANDLER, NULL, NULL);
255                 if (ACPI_FAILURE (Status))
256                 {
257                     if (Status == AE_SAME_HANDLER)
258                     {
259                         /*
260                          * It is OK if the handler is already installed on the
261                          * root bridge. Still need to return a context object
262                          * for the new PCI_Config operation region, however.
263                          */
264                         Status = AE_OK;
265                     }
266                     else
267                     {
268                         ACPI_EXCEPTION ((AE_INFO, Status,
269                             "Could not install PciConfig handler "
270                             "for Root Bridge %4.4s",
271                             AcpiUtGetNodeName (PciRootNode)));
272                     }
273                 }
274                 break;
275             }
276 
277             PciRootNode = PciRootNode->Parent;
278         }
279 
280         /* PCI root bridge not found, use namespace root node */
281     }
282     else
283     {
284         PciRootNode = HandlerObj->AddressSpace.Node;
285     }
286 
287     /*
288      * If this region is now initialized, we are done.
289      * (InstallAddressSpaceHandler could have initialized it)
290      */
291     if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)
292     {
293         return_ACPI_STATUS (AE_OK);
294     }
295 
296     /* Region is still not initialized. Create a new context */
297 
298     PciId = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PCI_ID));
299     if (!PciId)
300     {
301         return_ACPI_STATUS (AE_NO_MEMORY);
302     }
303 
304     /*
305      * For PCI_Config space access, we need the segment, bus, device and
306      * function numbers. Acquire them here.
307      *
308      * Find the parent device object. (This allows the operation region to be
309      * within a subscope under the device, such as a control method.)
310      */
311     PciDeviceNode = RegionObj->Region.Node;
312     while (PciDeviceNode && (PciDeviceNode->Type != ACPI_TYPE_DEVICE))
313     {
314         PciDeviceNode = PciDeviceNode->Parent;
315     }
316 
317     if (!PciDeviceNode)
318     {
319         ACPI_FREE (PciId);
320         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
321     }
322 
323     /*
324      * Get the PCI device and function numbers from the _ADR object
325      * contained in the parent's scope.
326      */
327     Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR,
328         PciDeviceNode, &PciValue);
329 
330     /*
331      * The default is zero, and since the allocation above zeroed the data,
332      * just do nothing on failure.
333      */
334     if (ACPI_SUCCESS (Status))
335     {
336         PciId->Device   = ACPI_HIWORD (ACPI_LODWORD (PciValue));
337         PciId->Function = ACPI_LOWORD (ACPI_LODWORD (PciValue));
338     }
339 
340     /* The PCI segment number comes from the _SEG method */
341 
342     Status = AcpiUtEvaluateNumericObject (METHOD_NAME__SEG,
343         PciRootNode, &PciValue);
344     if (ACPI_SUCCESS (Status))
345     {
346         PciId->Segment = ACPI_LOWORD (PciValue);
347     }
348 
349     /* The PCI bus number comes from the _BBN method */
350 
351     Status = AcpiUtEvaluateNumericObject (METHOD_NAME__BBN,
352         PciRootNode, &PciValue);
353     if (ACPI_SUCCESS (Status))
354     {
355         PciId->Bus = ACPI_LOWORD (PciValue);
356     }
357 
358     /* Complete/update the PCI ID for this device */
359 
360     Status = AcpiHwDerivePciId (PciId, PciRootNode, RegionObj->Region.Node);
361     if (ACPI_FAILURE (Status))
362     {
363         ACPI_FREE (PciId);
364         return_ACPI_STATUS (Status);
365     }
366 
367     *RegionContext = PciId;
368     return_ACPI_STATUS (AE_OK);
369 }
370 
371 
372 /*******************************************************************************
373  *
374  * FUNCTION:    AcpiEvIsPciRootBridge
375  *
376  * PARAMETERS:  Node            - Device node being examined
377  *
378  * RETURN:      TRUE if device is a PCI/PCI-Express Root Bridge
379  *
380  * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
381  *              examining the _HID and _CID for the device.
382  *
383  ******************************************************************************/
384 
385 static BOOLEAN
386 AcpiEvIsPciRootBridge (
387     ACPI_NAMESPACE_NODE     *Node)
388 {
389     ACPI_STATUS             Status;
390     ACPI_PNP_DEVICE_ID      *Hid;
391     ACPI_PNP_DEVICE_ID_LIST *Cid;
392     UINT32                  i;
393     BOOLEAN                 Match;
394 
395 
396     /* Get the _HID and check for a PCI Root Bridge */
397 
398     Status = AcpiUtExecute_HID (Node, &Hid);
399     if (ACPI_FAILURE (Status))
400     {
401         return (FALSE);
402     }
403 
404     Match = AcpiUtIsPciRootBridge (Hid->String);
405     ACPI_FREE (Hid);
406 
407     if (Match)
408     {
409         return (TRUE);
410     }
411 
412     /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */
413 
414     Status = AcpiUtExecute_CID (Node, &Cid);
415     if (ACPI_FAILURE (Status))
416     {
417         return (FALSE);
418     }
419 
420     /* Check all _CIDs in the returned list */
421 
422     for (i = 0; i < Cid->Count; i++)
423     {
424         if (AcpiUtIsPciRootBridge (Cid->Ids[i].String))
425         {
426             ACPI_FREE (Cid);
427             return (TRUE);
428         }
429     }
430 
431     ACPI_FREE (Cid);
432     return (FALSE);
433 }
434 
435 
436 /*******************************************************************************
437  *
438  * FUNCTION:    AcpiEvPciBarRegionSetup
439  *
440  * PARAMETERS:  Handle              - Region we are interested in
441  *              Function            - Start or stop
442  *              HandlerContext      - Address space handler context
443  *              RegionContext       - Region specific context
444  *
445  * RETURN:      Status
446  *
447  * DESCRIPTION: Setup a PciBAR operation region
448  *
449  * MUTEX:       Assumes namespace is not locked
450  *
451  ******************************************************************************/
452 
453 ACPI_STATUS
454 AcpiEvPciBarRegionSetup (
455     ACPI_HANDLE             Handle,
456     UINT32                  Function,
457     void                    *HandlerContext,
458     void                    **RegionContext)
459 {
460     ACPI_FUNCTION_TRACE (EvPciBarRegionSetup);
461 
462 
463     return_ACPI_STATUS (AE_OK);
464 }
465 
466 
467 /*******************************************************************************
468  *
469  * FUNCTION:    AcpiEvCmosRegionSetup
470  *
471  * PARAMETERS:  Handle              - Region we are interested in
472  *              Function            - Start or stop
473  *              HandlerContext      - Address space handler context
474  *              RegionContext       - Region specific context
475  *
476  * RETURN:      Status
477  *
478  * DESCRIPTION: Setup a CMOS operation region
479  *
480  * MUTEX:       Assumes namespace is not locked
481  *
482  ******************************************************************************/
483 
484 ACPI_STATUS
485 AcpiEvCmosRegionSetup (
486     ACPI_HANDLE             Handle,
487     UINT32                  Function,
488     void                    *HandlerContext,
489     void                    **RegionContext)
490 {
491     ACPI_FUNCTION_TRACE (EvCmosRegionSetup);
492 
493 
494     return_ACPI_STATUS (AE_OK);
495 }
496 
497 
498 /*******************************************************************************
499  *
500  * FUNCTION:    AcpiEvDefaultRegionSetup
501  *
502  * PARAMETERS:  Handle              - Region we are interested in
503  *              Function            - Start or stop
504  *              HandlerContext      - Address space handler context
505  *              RegionContext       - Region specific context
506  *
507  * RETURN:      Status
508  *
509  * DESCRIPTION: Default region initialization
510  *
511  ******************************************************************************/
512 
513 ACPI_STATUS
514 AcpiEvDefaultRegionSetup (
515     ACPI_HANDLE             Handle,
516     UINT32                  Function,
517     void                    *HandlerContext,
518     void                    **RegionContext)
519 {
520     ACPI_FUNCTION_TRACE (EvDefaultRegionSetup);
521 
522 
523     if (Function == ACPI_REGION_DEACTIVATE)
524     {
525         *RegionContext = NULL;
526     }
527     else
528     {
529         *RegionContext = HandlerContext;
530     }
531 
532     return_ACPI_STATUS (AE_OK);
533 }
534 
535 
536 /*******************************************************************************
537  *
538  * FUNCTION:    AcpiEvInitializeRegion
539  *
540  * PARAMETERS:  RegionObj       - Region we are initializing
541  *
542  * RETURN:      Status
543  *
544  * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
545  *              for execution at a later time
546  *
547  *              Get the appropriate address space handler for a newly
548  *              created region.
549  *
550  *              This also performs address space specific initialization. For
551  *              example, PCI regions must have an _ADR object that contains
552  *              a PCI address in the scope of the definition. This address is
553  *              required to perform an access to PCI config space.
554  *
555  * MUTEX:       Interpreter should be unlocked, because we may run the _REG
556  *              method for this region.
557  *
558  * NOTE:        Possible incompliance:
559  *              There is a behavior conflict in automatic _REG execution:
560  *              1. When the interpreter is evaluating a method, we can only
561  *                 automatically run _REG for the following case:
562  *                   Method(_REG, 2) {}
563  *                   OperationRegion (OPR1, 0x80, 0x1000010, 0x4)
564  *              2. When the interpreter is loading a table, we can also
565  *                 automatically run _REG for the following case:
566  *                   OperationRegion (OPR1, 0x80, 0x1000010, 0x4)
567  *                   Method(_REG, 2) {}
568  *              Though this may not be compliant to the de-facto standard, the
569  *              logic is kept in order not to trigger regressions. And keeping
570  *              this logic should be taken care by the caller of this function.
571  *
572  ******************************************************************************/
573 
574 ACPI_STATUS
575 AcpiEvInitializeRegion (
576     ACPI_OPERAND_OBJECT     *RegionObj)
577 {
578     ACPI_OPERAND_OBJECT     *HandlerObj;
579     ACPI_OPERAND_OBJECT     *ObjDesc;
580     ACPI_ADR_SPACE_TYPE     SpaceId;
581     ACPI_NAMESPACE_NODE     *Node;
582 
583 
584     ACPI_FUNCTION_TRACE (EvInitializeRegion);
585 
586 
587     if (!RegionObj)
588     {
589         return_ACPI_STATUS (AE_BAD_PARAMETER);
590     }
591 
592     if (RegionObj->Common.Flags & AOPOBJ_OBJECT_INITIALIZED)
593     {
594         return_ACPI_STATUS (AE_OK);
595     }
596 
597     RegionObj->Common.Flags |= AOPOBJ_OBJECT_INITIALIZED;
598 
599     Node = RegionObj->Region.Node->Parent;
600     SpaceId = RegionObj->Region.SpaceId;
601 
602     /*
603      * The following loop depends upon the root Node having no parent
604      * ie: AcpiGbl_RootNode->Parent being set to NULL
605      */
606     while (Node)
607     {
608         /* Check to see if a handler exists */
609 
610         HandlerObj = NULL;
611         ObjDesc = AcpiNsGetAttachedObject (Node);
612         if (ObjDesc)
613         {
614             /* Can only be a handler if the object exists */
615 
616             switch (Node->Type)
617             {
618             case ACPI_TYPE_DEVICE:
619             case ACPI_TYPE_PROCESSOR:
620             case ACPI_TYPE_THERMAL:
621 
622                 HandlerObj = ObjDesc->CommonNotify.Handler;
623                 break;
624 
625             case ACPI_TYPE_METHOD:
626                 /*
627                  * If we are executing module level code, the original
628                  * Node's object was replaced by this Method object and we
629                  * saved the handler in the method object.
630                  *
631                  * See AcpiNsExecModuleCode
632                  */
633                 if (!AcpiGbl_ParseTableAsTermList &&
634                     ObjDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)
635                 {
636                     HandlerObj = ObjDesc->Method.Dispatch.Handler;
637                 }
638                 break;
639 
640             default:
641 
642                 /* Ignore other objects */
643 
644                 break;
645             }
646 
647             HandlerObj = AcpiEvFindRegionHandler (SpaceId, HandlerObj);
648             if (HandlerObj)
649             {
650                 /* Found correct handler */
651 
652                 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
653                     "Found handler %p for region %p in obj %p\n",
654                     HandlerObj, RegionObj, ObjDesc));
655 
656                 (void) AcpiEvAttachRegion (HandlerObj, RegionObj, FALSE);
657 
658                 /*
659                  * Tell all users that this region is usable by
660                  * running the _REG method
661                  */
662                 AcpiExExitInterpreter ();
663                 (void) AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_CONNECT);
664                 AcpiExEnterInterpreter ();
665                 return_ACPI_STATUS (AE_OK);
666             }
667         }
668 
669         /* This node does not have the handler we need; Pop up one level */
670 
671         Node = Node->Parent;
672     }
673 
674     /*
675      * If we get here, there is no handler for this region. This is not
676      * fatal because many regions get created before a handler is installed
677      * for said region.
678      */
679     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
680         "No handler for RegionType %s(%X) (RegionObj %p)\n",
681         AcpiUtGetRegionName (SpaceId), SpaceId, RegionObj));
682 
683     return_ACPI_STATUS (AE_OK);
684 }
685