xref: /titanic_41/usr/src/uts/intel/io/acpica/events/evgpeinit.c (revision f3312ec0e8acbd249df97358fb8c3ca92f4e089c)
1 /******************************************************************************
2  *
3  * Module Name: evgpeinit - System GPE initialization and update
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2011, 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 
45 #include "acpi.h"
46 #include "accommon.h"
47 #include "acevents.h"
48 #include "acnamesp.h"
49 
50 #define _COMPONENT          ACPI_EVENTS
51         ACPI_MODULE_NAME    ("evgpeinit")
52 
53 
54 /*
55  * Note: History of _PRW support in ACPICA
56  *
57  * Originally (2000 - 2010), the GPE initialization code performed a walk of
58  * the entire namespace to execute the _PRW methods and detect all GPEs
59  * capable of waking the system.
60  *
61  * As of 10/2010, the _PRW method execution has been removed since it is
62  * actually unnecessary. The host OS must in fact execute all _PRW methods
63  * in order to identify the device/power-resource dependencies. We now put
64  * the onus on the host OS to identify the wake GPEs as part of this process
65  * and to inform ACPICA of these GPEs via the AcpiSetupGpeForWake interface. This
66  * not only reduces the complexity of the ACPICA initialization code, but in
67  * some cases (on systems with very large namespaces) it should reduce the
68  * kernel boot time as well.
69  */
70 
71 /*******************************************************************************
72  *
73  * FUNCTION:    AcpiEvGpeInitialize
74  *
75  * PARAMETERS:  None
76  *
77  * RETURN:      Status
78  *
79  * DESCRIPTION: Initialize the GPE data structures and the FADT GPE 0/1 blocks
80  *
81  ******************************************************************************/
82 
83 ACPI_STATUS
84 AcpiEvGpeInitialize (
85     void)
86 {
87     UINT32                  RegisterCount0 = 0;
88     UINT32                  RegisterCount1 = 0;
89     UINT32                  GpeNumberMax = 0;
90     ACPI_STATUS             Status;
91 
92 
93     ACPI_FUNCTION_TRACE (EvGpeInitialize);
94 
95 
96     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
97     if (ACPI_FAILURE (Status))
98     {
99         return_ACPI_STATUS (Status);
100     }
101 
102     /*
103      * Initialize the GPE Block(s) defined in the FADT
104      *
105      * Why the GPE register block lengths are divided by 2:  From the ACPI
106      * Spec, section "General-Purpose Event Registers", we have:
107      *
108      * "Each register block contains two registers of equal length
109      *  GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
110      *  GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
111      *  The length of the GPE1_STS and GPE1_EN registers is equal to
112      *  half the GPE1_LEN. If a generic register block is not supported
113      *  then its respective block pointer and block length values in the
114      *  FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
115      *  to be the same size."
116      */
117 
118     /*
119      * Determine the maximum GPE number for this machine.
120      *
121      * Note: both GPE0 and GPE1 are optional, and either can exist without
122      * the other.
123      *
124      * If EITHER the register length OR the block address are zero, then that
125      * particular block is not supported.
126      */
127     if (AcpiGbl_FADT.Gpe0BlockLength &&
128         AcpiGbl_FADT.XGpe0Block.Address)
129     {
130         /* GPE block 0 exists (has both length and address > 0) */
131 
132         RegisterCount0 = (UINT16) (AcpiGbl_FADT.Gpe0BlockLength / 2);
133 
134         GpeNumberMax = (RegisterCount0 * ACPI_GPE_REGISTER_WIDTH) - 1;
135 
136         /* Install GPE Block 0 */
137 
138         Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice,
139                     &AcpiGbl_FADT.XGpe0Block, RegisterCount0, 0,
140                     AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[0]);
141 
142         if (ACPI_FAILURE (Status))
143         {
144             ACPI_EXCEPTION ((AE_INFO, Status,
145                 "Could not create GPE Block 0"));
146         }
147     }
148 
149     if (AcpiGbl_FADT.Gpe1BlockLength &&
150         AcpiGbl_FADT.XGpe1Block.Address)
151     {
152         /* GPE block 1 exists (has both length and address > 0) */
153 
154         RegisterCount1 = (UINT16) (AcpiGbl_FADT.Gpe1BlockLength / 2);
155 
156         /* Check for GPE0/GPE1 overlap (if both banks exist) */
157 
158         if ((RegisterCount0) &&
159             (GpeNumberMax >= AcpiGbl_FADT.Gpe1Base))
160         {
161             ACPI_ERROR ((AE_INFO,
162                 "GPE0 block (GPE 0 to %u) overlaps the GPE1 block "
163                 "(GPE %u to %u) - Ignoring GPE1",
164                 GpeNumberMax, AcpiGbl_FADT.Gpe1Base,
165                 AcpiGbl_FADT.Gpe1Base +
166                 ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1)));
167 
168             /* Ignore GPE1 block by setting the register count to zero */
169 
170             RegisterCount1 = 0;
171         }
172         else
173         {
174             /* Install GPE Block 1 */
175 
176             Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice,
177                         &AcpiGbl_FADT.XGpe1Block, RegisterCount1,
178                         AcpiGbl_FADT.Gpe1Base,
179                         AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[1]);
180 
181             if (ACPI_FAILURE (Status))
182             {
183                 ACPI_EXCEPTION ((AE_INFO, Status,
184                     "Could not create GPE Block 1"));
185             }
186 
187             /*
188              * GPE0 and GPE1 do not have to be contiguous in the GPE number
189              * space. However, GPE0 always starts at GPE number zero.
190              */
191             GpeNumberMax = AcpiGbl_FADT.Gpe1Base +
192                             ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1);
193         }
194     }
195 
196     /* Exit if there are no GPE registers */
197 
198     if ((RegisterCount0 + RegisterCount1) == 0)
199     {
200         /* GPEs are not required by ACPI, this is OK */
201 
202         ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
203             "There are no GPE blocks defined in the FADT\n"));
204         Status = AE_OK;
205         goto Cleanup;
206     }
207 
208     /* Check for Max GPE number out-of-range */
209 
210     if (GpeNumberMax > ACPI_GPE_MAX)
211     {
212         ACPI_ERROR ((AE_INFO,
213             "Maximum GPE number from FADT is too large: 0x%X",
214             GpeNumberMax));
215         Status = AE_BAD_VALUE;
216         goto Cleanup;
217     }
218 
219 Cleanup:
220     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
221     return_ACPI_STATUS (AE_OK);
222 }
223 
224 
225 /*******************************************************************************
226  *
227  * FUNCTION:    AcpiEvUpdateGpes
228  *
229  * PARAMETERS:  TableOwnerId        - ID of the newly-loaded ACPI table
230  *
231  * RETURN:      None
232  *
233  * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
234  *              result of a Load() or LoadTable() operation. If new GPE
235  *              methods have been installed, register the new methods.
236  *
237  ******************************************************************************/
238 
239 void
240 AcpiEvUpdateGpes (
241     ACPI_OWNER_ID           TableOwnerId)
242 {
243     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo;
244     ACPI_GPE_BLOCK_INFO     *GpeBlock;
245     ACPI_GPE_WALK_INFO      WalkInfo;
246     ACPI_STATUS             Status = AE_OK;
247 
248 
249     /*
250      * Find any _Lxx/_Exx GPE methods that have just been loaded.
251      *
252      * Any GPEs that correspond to new _Lxx/_Exx methods are immediately
253      * enabled.
254      *
255      * Examine the namespace underneath each GpeDevice within the
256      * GpeBlock lists.
257      */
258     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
259     if (ACPI_FAILURE (Status))
260     {
261         return;
262     }
263 
264     WalkInfo.Count = 0;
265     WalkInfo.OwnerId = TableOwnerId;
266     WalkInfo.ExecuteByOwnerId = TRUE;
267 
268     /* Walk the interrupt level descriptor list */
269 
270     GpeXruptInfo = AcpiGbl_GpeXruptListHead;
271     while (GpeXruptInfo)
272     {
273         /* Walk all Gpe Blocks attached to this interrupt level */
274 
275         GpeBlock = GpeXruptInfo->GpeBlockListHead;
276         while (GpeBlock)
277         {
278             WalkInfo.GpeBlock = GpeBlock;
279             WalkInfo.GpeDevice = GpeBlock->Node;
280 
281             Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD,
282                         WalkInfo.GpeDevice, ACPI_UINT32_MAX,
283                         ACPI_NS_WALK_NO_UNLOCK, AcpiEvMatchGpeMethod,
284                         NULL, &WalkInfo, NULL);
285             if (ACPI_FAILURE (Status))
286             {
287                 ACPI_EXCEPTION ((AE_INFO, Status,
288                     "While decoding _Lxx/_Exx methods"));
289             }
290 
291             GpeBlock = GpeBlock->Next;
292         }
293 
294         GpeXruptInfo = GpeXruptInfo->Next;
295     }
296 
297     if (WalkInfo.Count)
298     {
299         ACPI_INFO ((AE_INFO, "Enabled %u new GPEs", WalkInfo.Count));
300     }
301 
302     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
303     return;
304 }
305 
306 
307 /*******************************************************************************
308  *
309  * FUNCTION:    AcpiEvMatchGpeMethod
310  *
311  * PARAMETERS:  Callback from WalkNamespace
312  *
313  * RETURN:      Status
314  *
315  * DESCRIPTION: Called from AcpiWalkNamespace. Expects each object to be a
316  *              control method under the _GPE portion of the namespace.
317  *              Extract the name and GPE type from the object, saving this
318  *              information for quick lookup during GPE dispatch. Allows a
319  *              per-OwnerId evaluation if ExecuteByOwnerId is TRUE in the
320  *              WalkInfo parameter block.
321  *
322  *              The name of each GPE control method is of the form:
323  *              "_Lxx" or "_Exx", where:
324  *                  L      - means that the GPE is level triggered
325  *                  E      - means that the GPE is edge triggered
326  *                  xx     - is the GPE number [in HEX]
327  *
328  * If WalkInfo->ExecuteByOwnerId is TRUE, we only execute examine GPE methods
329  * with that owner.
330  *
331  ******************************************************************************/
332 
333 ACPI_STATUS
334 AcpiEvMatchGpeMethod (
335     ACPI_HANDLE             ObjHandle,
336     UINT32                  Level,
337     void                    *Context,
338     void                    **ReturnValue)
339 {
340     ACPI_NAMESPACE_NODE     *MethodNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
341     ACPI_GPE_WALK_INFO      *WalkInfo = ACPI_CAST_PTR (ACPI_GPE_WALK_INFO, Context);
342     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
343     UINT32                  GpeNumber;
344     char                    Name[ACPI_NAME_SIZE + 1];
345     UINT8                   Type;
346 
347 
348     ACPI_FUNCTION_TRACE (EvMatchGpeMethod);
349 
350 
351     /* Check if requested OwnerId matches this OwnerId */
352 
353     if ((WalkInfo->ExecuteByOwnerId) &&
354         (MethodNode->OwnerId != WalkInfo->OwnerId))
355     {
356         return_ACPI_STATUS (AE_OK);
357     }
358 
359     /*
360      * Match and decode the _Lxx and _Exx GPE method names
361      *
362      * 1) Extract the method name and null terminate it
363      */
364     ACPI_MOVE_32_TO_32 (Name, &MethodNode->Name.Integer);
365     Name[ACPI_NAME_SIZE] = 0;
366 
367     /* 2) Name must begin with an underscore */
368 
369     if (Name[0] != '_')
370     {
371         return_ACPI_STATUS (AE_OK); /* Ignore this method */
372     }
373 
374     /*
375      * 3) Edge/Level determination is based on the 2nd character
376      *    of the method name
377      */
378     switch (Name[1])
379     {
380     case 'L':
381         Type = ACPI_GPE_LEVEL_TRIGGERED;
382         break;
383 
384     case 'E':
385         Type = ACPI_GPE_EDGE_TRIGGERED;
386         break;
387 
388     default:
389         /* Unknown method type, just ignore it */
390 
391         ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
392             "Ignoring unknown GPE method type: %s "
393             "(name not of form _Lxx or _Exx)", Name));
394         return_ACPI_STATUS (AE_OK);
395     }
396 
397     /* 4) The last two characters of the name are the hex GPE Number */
398 
399     GpeNumber = ACPI_STRTOUL (&Name[2], NULL, 16);
400     if (GpeNumber == ACPI_UINT32_MAX)
401     {
402         /* Conversion failed; invalid method, just ignore it */
403 
404         ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
405             "Could not extract GPE number from name: %s "
406             "(name is not of form _Lxx or _Exx)", Name));
407         return_ACPI_STATUS (AE_OK);
408     }
409 
410     /* Ensure that we have a valid GPE number for this GPE block */
411 
412     GpeEventInfo = AcpiEvLowGetGpeInfo (GpeNumber, WalkInfo->GpeBlock);
413     if (!GpeEventInfo)
414     {
415         /*
416          * This GpeNumber is not valid for this GPE block, just ignore it.
417          * However, it may be valid for a different GPE block, since GPE0
418          * and GPE1 methods both appear under \_GPE.
419          */
420         return_ACPI_STATUS (AE_OK);
421     }
422 
423     if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
424             ACPI_GPE_DISPATCH_HANDLER)
425     {
426         /* If there is already a handler, ignore this GPE method */
427 
428         return_ACPI_STATUS (AE_OK);
429     }
430 
431     if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
432             ACPI_GPE_DISPATCH_METHOD)
433     {
434         /*
435          * If there is already a method, ignore this method. But check
436          * for a type mismatch (if both the _Lxx AND _Exx exist)
437          */
438         if (Type != (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
439         {
440             ACPI_ERROR ((AE_INFO,
441                 "For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods",
442                 GpeNumber, GpeNumber, GpeNumber));
443         }
444         return_ACPI_STATUS (AE_OK);
445     }
446 
447     /*
448      * Add the GPE information from above to the GpeEventInfo block for
449      * use during dispatch of this GPE.
450      */
451     GpeEventInfo->Flags &= ~(ACPI_GPE_DISPATCH_MASK);
452     GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_METHOD);
453     GpeEventInfo->Dispatch.MethodNode = MethodNode;
454 
455     ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
456         "Registered GPE method %s as GPE number 0x%.2X\n",
457         Name, GpeNumber));
458     return_ACPI_STATUS (AE_OK);
459 }
460