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