1114239Snjl/******************************************************************************
2114239Snjl *
3114239Snjl * Module Name: evgpeblk - GPE block creation and initialization.
4114239Snjl *
5114239Snjl *****************************************************************************/
6114239Snjl
7217365Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp.
9114239Snjl * All rights reserved.
10114239Snjl *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
25114239Snjl *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
29114239Snjl *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
43114239Snjl
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
47193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
48114239Snjl
49114239Snjl#define _COMPONENT          ACPI_EVENTS
50117521Snjl        ACPI_MODULE_NAME    ("evgpeblk")
51114239Snjl
52231844Sjkim#if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53231844Sjkim
54151937Sjkim/* Local prototypes */
55114239Snjl
56151937Sjkimstatic ACPI_STATUS
57151937SjkimAcpiEvInstallGpeBlock (
58151937Sjkim    ACPI_GPE_BLOCK_INFO     *GpeBlock,
59151937Sjkim    UINT32                  InterruptNumber);
60151937Sjkim
61151937Sjkimstatic ACPI_STATUS
62151937SjkimAcpiEvCreateGpeInfoBlocks (
63151937Sjkim    ACPI_GPE_BLOCK_INFO     *GpeBlock);
64151937Sjkim
65151937Sjkim
66114239Snjl/*******************************************************************************
67114239Snjl *
68114239Snjl * FUNCTION:    AcpiEvInstallGpeBlock
69114239Snjl *
70193267Sjkim * PARAMETERS:  GpeBlock                - New GPE block
71193267Sjkim *              InterruptNumber         - Xrupt to be associated with this
72193267Sjkim *                                        GPE block
73114239Snjl *
74114239Snjl * RETURN:      Status
75114239Snjl *
76114239Snjl * DESCRIPTION: Install new GPE block with mutex support
77114239Snjl *
78114239Snjl ******************************************************************************/
79114239Snjl
80117521Snjlstatic ACPI_STATUS
81114239SnjlAcpiEvInstallGpeBlock (
82117521Snjl    ACPI_GPE_BLOCK_INFO     *GpeBlock,
83151937Sjkim    UINT32                  InterruptNumber)
84114239Snjl{
85114239Snjl    ACPI_GPE_BLOCK_INFO     *NextGpeBlock;
86117521Snjl    ACPI_GPE_XRUPT_INFO     *GpeXruptBlock;
87114239Snjl    ACPI_STATUS             Status;
88167802Sjkim    ACPI_CPU_FLAGS          Flags;
89114239Snjl
90114239Snjl
91167802Sjkim    ACPI_FUNCTION_TRACE (EvInstallGpeBlock);
92117521Snjl
93117521Snjl
94114239Snjl    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
95114239Snjl    if (ACPI_FAILURE (Status))
96114239Snjl    {
97117521Snjl        return_ACPI_STATUS (Status);
98114239Snjl    }
99114239Snjl
100281075Sdim    Status = AcpiEvGetGpeXruptBlock (InterruptNumber, &GpeXruptBlock);
101281075Sdim    if (ACPI_FAILURE (Status))
102117521Snjl    {
103117521Snjl        goto UnlockAndExit;
104117521Snjl    }
105114239Snjl
106151937Sjkim    /* Install the new block at the end of the list with lock */
107117521Snjl
108151937Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
109117521Snjl    if (GpeXruptBlock->GpeBlockListHead)
110114239Snjl    {
111117521Snjl        NextGpeBlock = GpeXruptBlock->GpeBlockListHead;
112114239Snjl        while (NextGpeBlock->Next)
113114239Snjl        {
114114239Snjl            NextGpeBlock = NextGpeBlock->Next;
115114239Snjl        }
116114239Snjl
117114239Snjl        NextGpeBlock->Next = GpeBlock;
118114239Snjl        GpeBlock->Previous = NextGpeBlock;
119114239Snjl    }
120114239Snjl    else
121114239Snjl    {
122117521Snjl        GpeXruptBlock->GpeBlockListHead = GpeBlock;
123114239Snjl    }
124114239Snjl
125117521Snjl    GpeBlock->XruptBlock = GpeXruptBlock;
126151937Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
127117521Snjl
128167802Sjkim
129117521SnjlUnlockAndExit:
130281075Sdim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
131117521Snjl    return_ACPI_STATUS (Status);
132114239Snjl}
133114239Snjl
134114239Snjl
135114239Snjl/*******************************************************************************
136114239Snjl *
137117521Snjl * FUNCTION:    AcpiEvDeleteGpeBlock
138117521Snjl *
139193267Sjkim * PARAMETERS:  GpeBlock            - Existing GPE block
140117521Snjl *
141117521Snjl * RETURN:      Status
142117521Snjl *
143123315Snjl * DESCRIPTION: Remove a GPE block
144117521Snjl *
145117521Snjl ******************************************************************************/
146117521Snjl
147117521SnjlACPI_STATUS
148117521SnjlAcpiEvDeleteGpeBlock (
149117521Snjl    ACPI_GPE_BLOCK_INFO     *GpeBlock)
150117521Snjl{
151117521Snjl    ACPI_STATUS             Status;
152167802Sjkim    ACPI_CPU_FLAGS          Flags;
153117521Snjl
154117521Snjl
155167802Sjkim    ACPI_FUNCTION_TRACE (EvInstallGpeBlock);
156117521Snjl
157117521Snjl
158117521Snjl    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
159117521Snjl    if (ACPI_FAILURE (Status))
160117521Snjl    {
161117521Snjl        return_ACPI_STATUS (Status);
162117521Snjl    }
163117521Snjl
164117521Snjl    /* Disable all GPEs in this block */
165117521Snjl
166193267Sjkim    Status = AcpiHwDisableGpeBlock (GpeBlock->XruptBlock, GpeBlock, NULL);
167117521Snjl
168117521Snjl    if (!GpeBlock->Previous && !GpeBlock->Next)
169117521Snjl    {
170117521Snjl        /* This is the last GpeBlock on this interrupt */
171117521Snjl
172117521Snjl        Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock);
173117521Snjl        if (ACPI_FAILURE (Status))
174117521Snjl        {
175117521Snjl            goto UnlockAndExit;
176117521Snjl        }
177117521Snjl    }
178117521Snjl    else
179117521Snjl    {
180117521Snjl        /* Remove the block on this interrupt with lock */
181117521Snjl
182151937Sjkim        Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
183117521Snjl        if (GpeBlock->Previous)
184117521Snjl        {
185117521Snjl            GpeBlock->Previous->Next = GpeBlock->Next;
186117521Snjl        }
187117521Snjl        else
188117521Snjl        {
189117521Snjl            GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next;
190117521Snjl        }
191117521Snjl
192117521Snjl        if (GpeBlock->Next)
193117521Snjl        {
194117521Snjl            GpeBlock->Next->Previous = GpeBlock->Previous;
195117521Snjl        }
196151937Sjkim        AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
197117521Snjl    }
198117521Snjl
199206117Sjkim    AcpiCurrentGpeCount -= GpeBlock->GpeCount;
200193267Sjkim
201117521Snjl    /* Free the GpeBlock */
202117521Snjl
203167802Sjkim    ACPI_FREE (GpeBlock->RegisterInfo);
204167802Sjkim    ACPI_FREE (GpeBlock->EventInfo);
205167802Sjkim    ACPI_FREE (GpeBlock);
206117521Snjl
207117521SnjlUnlockAndExit:
208117521Snjl    Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
209117521Snjl    return_ACPI_STATUS (Status);
210117521Snjl}
211117521Snjl
212117521Snjl
213117521Snjl/*******************************************************************************
214117521Snjl *
215114239Snjl * FUNCTION:    AcpiEvCreateGpeInfoBlocks
216114239Snjl *
217114239Snjl * PARAMETERS:  GpeBlock    - New GPE block
218114239Snjl *
219114239Snjl * RETURN:      Status
220114239Snjl *
221114239Snjl * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block
222114239Snjl *
223114239Snjl ******************************************************************************/
224114239Snjl
225117521Snjlstatic ACPI_STATUS
226114239SnjlAcpiEvCreateGpeInfoBlocks (
227114239Snjl    ACPI_GPE_BLOCK_INFO     *GpeBlock)
228114239Snjl{
229114239Snjl    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo = NULL;
230114239Snjl    ACPI_GPE_EVENT_INFO     *GpeEventInfo = NULL;
231114239Snjl    ACPI_GPE_EVENT_INFO     *ThisEvent;
232114239Snjl    ACPI_GPE_REGISTER_INFO  *ThisRegister;
233193267Sjkim    UINT32                  i;
234193267Sjkim    UINT32                  j;
235114239Snjl    ACPI_STATUS             Status;
236114239Snjl
237114239Snjl
238167802Sjkim    ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks);
239114239Snjl
240114239Snjl
241114239Snjl    /* Allocate the GPE register information block */
242114239Snjl
243167802Sjkim    GpeRegisterInfo = ACPI_ALLOCATE_ZEROED (
244206117Sjkim                        (ACPI_SIZE) GpeBlock->RegisterCount *
245206117Sjkim                        sizeof (ACPI_GPE_REGISTER_INFO));
246114239Snjl    if (!GpeRegisterInfo)
247114239Snjl    {
248167802Sjkim        ACPI_ERROR ((AE_INFO,
249167802Sjkim            "Could not allocate the GpeRegisterInfo table"));
250114239Snjl        return_ACPI_STATUS (AE_NO_MEMORY);
251114239Snjl    }
252114239Snjl
253114239Snjl    /*
254167802Sjkim     * Allocate the GPE EventInfo block. There are eight distinct GPEs
255167802Sjkim     * per register. Initialization to zeros is sufficient.
256114239Snjl     */
257206117Sjkim    GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount *
258206117Sjkim                    sizeof (ACPI_GPE_EVENT_INFO));
259114239Snjl    if (!GpeEventInfo)
260114239Snjl    {
261167802Sjkim        ACPI_ERROR ((AE_INFO,
262167802Sjkim            "Could not allocate the GpeEventInfo table"));
263114239Snjl        Status = AE_NO_MEMORY;
264114239Snjl        goto ErrorExit;
265114239Snjl    }
266114239Snjl
267117521Snjl    /* Save the new Info arrays in the GPE block */
268117521Snjl
269117521Snjl    GpeBlock->RegisterInfo = GpeRegisterInfo;
270117521Snjl    GpeBlock->EventInfo    = GpeEventInfo;
271117521Snjl
272114239Snjl    /*
273167802Sjkim     * Initialize the GPE Register and Event structures. A goal of these
274193267Sjkim     * tables is to hide the fact that there are two separate GPE register
275193267Sjkim     * sets in a given GPE hardware block, the status registers occupy the
276193267Sjkim     * first half, and the enable registers occupy the second half.
277114239Snjl     */
278114239Snjl    ThisRegister = GpeRegisterInfo;
279114239Snjl    ThisEvent    = GpeEventInfo;
280114239Snjl
281114239Snjl    for (i = 0; i < GpeBlock->RegisterCount; i++)
282114239Snjl    {
283114239Snjl        /* Init the RegisterInfo for this GPE register (8 GPEs) */
284114239Snjl
285281075Sdim        ThisRegister->BaseGpeNumber = (UINT16)
286281075Sdim            (GpeBlock->BlockBaseNumber + (i * ACPI_GPE_REGISTER_WIDTH));
287114239Snjl
288167802Sjkim        ThisRegister->StatusAddress.Address =
289281075Sdim            GpeBlock->Address + i;
290114239Snjl
291167802Sjkim        ThisRegister->EnableAddress.Address =
292281075Sdim            GpeBlock->Address + i + GpeBlock->RegisterCount;
293114239Snjl
294281075Sdim        ThisRegister->StatusAddress.SpaceId   = GpeBlock->SpaceId;
295281075Sdim        ThisRegister->EnableAddress.SpaceId   = GpeBlock->SpaceId;
296167802Sjkim        ThisRegister->StatusAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
297167802Sjkim        ThisRegister->EnableAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
298193267Sjkim        ThisRegister->StatusAddress.BitOffset = 0;
299193267Sjkim        ThisRegister->EnableAddress.BitOffset = 0;
300114239Snjl
301114239Snjl        /* Init the EventInfo for each GPE within this register */
302114239Snjl
303114239Snjl        for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
304114239Snjl        {
305167802Sjkim            ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j);
306114239Snjl            ThisEvent->RegisterInfo = ThisRegister;
307114239Snjl            ThisEvent++;
308114239Snjl        }
309114239Snjl
310167802Sjkim        /* Disable all GPEs within this register */
311167802Sjkim
312197104Sjkim        Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress);
313114239Snjl        if (ACPI_FAILURE (Status))
314114239Snjl        {
315114239Snjl            goto ErrorExit;
316114239Snjl        }
317114239Snjl
318167802Sjkim        /* Clear any pending GPE events within this register */
319167802Sjkim
320197104Sjkim        Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress);
321114239Snjl        if (ACPI_FAILURE (Status))
322114239Snjl        {
323114239Snjl            goto ErrorExit;
324114239Snjl        }
325114239Snjl
326114239Snjl        ThisRegister++;
327114239Snjl    }
328114239Snjl
329114239Snjl    return_ACPI_STATUS (AE_OK);
330114239Snjl
331114239Snjl
332114239SnjlErrorExit:
333114239Snjl    if (GpeRegisterInfo)
334114239Snjl    {
335167802Sjkim        ACPI_FREE (GpeRegisterInfo);
336114239Snjl    }
337114239Snjl    if (GpeEventInfo)
338114239Snjl    {
339167802Sjkim        ACPI_FREE (GpeEventInfo);
340114239Snjl    }
341114239Snjl
342117521Snjl    return_ACPI_STATUS (Status);
343114239Snjl}
344114239Snjl
345114239Snjl
346114239Snjl/*******************************************************************************
347114239Snjl *
348114239Snjl * FUNCTION:    AcpiEvCreateGpeBlock
349114239Snjl *
350117521Snjl * PARAMETERS:  GpeDevice           - Handle to the parent GPE block
351117521Snjl *              GpeBlockAddress     - Address and SpaceID
352117521Snjl *              RegisterCount       - Number of GPE register pairs in the block
353117521Snjl *              GpeBlockBaseNumber  - Starting GPE number for the block
354151937Sjkim *              InterruptNumber     - H/W interrupt for the block
355117521Snjl *              ReturnGpeBlock      - Where the new block descriptor is returned
356114239Snjl *
357114239Snjl * RETURN:      Status
358114239Snjl *
359167802Sjkim * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
360167802Sjkim *              the block are disabled at exit.
361167802Sjkim *              Note: Assumes namespace is locked.
362114239Snjl *
363114239Snjl ******************************************************************************/
364114239Snjl
365114239SnjlACPI_STATUS
366114239SnjlAcpiEvCreateGpeBlock (
367117521Snjl    ACPI_NAMESPACE_NODE     *GpeDevice,
368281075Sdim    UINT64                  Address,
369281075Sdim    UINT8                   SpaceId,
370114239Snjl    UINT32                  RegisterCount,
371281075Sdim    UINT16                  GpeBlockBaseNumber,
372151937Sjkim    UINT32                  InterruptNumber,
373117521Snjl    ACPI_GPE_BLOCK_INFO     **ReturnGpeBlock)
374114239Snjl{
375167802Sjkim    ACPI_STATUS             Status;
376114239Snjl    ACPI_GPE_BLOCK_INFO     *GpeBlock;
377207344Sjkim    ACPI_GPE_WALK_INFO      WalkInfo;
378114239Snjl
379129684Snjl
380167802Sjkim    ACPI_FUNCTION_TRACE (EvCreateGpeBlock);
381114239Snjl
382114239Snjl
383114239Snjl    if (!RegisterCount)
384114239Snjl    {
385114239Snjl        return_ACPI_STATUS (AE_OK);
386114239Snjl    }
387114239Snjl
388114239Snjl    /* Allocate a new GPE block */
389114239Snjl
390167802Sjkim    GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO));
391114239Snjl    if (!GpeBlock)
392114239Snjl    {
393114239Snjl        return_ACPI_STATUS (AE_NO_MEMORY);
394114239Snjl    }
395114239Snjl
396114239Snjl    /* Initialize the new GPE block */
397114239Snjl
398281075Sdim    GpeBlock->Address = Address;
399281075Sdim    GpeBlock->SpaceId = SpaceId;
400167802Sjkim    GpeBlock->Node = GpeDevice;
401206117Sjkim    GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH);
402216471Sjkim    GpeBlock->Initialized = FALSE;
403167802Sjkim    GpeBlock->RegisterCount = RegisterCount;
404114239Snjl    GpeBlock->BlockBaseNumber = GpeBlockBaseNumber;
405114239Snjl
406167802Sjkim    /*
407167802Sjkim     * Create the RegisterInfo and EventInfo sub-structures
408167802Sjkim     * Note: disables and clears all GPEs in the block
409167802Sjkim     */
410114239Snjl    Status = AcpiEvCreateGpeInfoBlocks (GpeBlock);
411114239Snjl    if (ACPI_FAILURE (Status))
412114239Snjl    {
413167802Sjkim        ACPI_FREE (GpeBlock);
414114239Snjl        return_ACPI_STATUS (Status);
415114239Snjl    }
416114239Snjl
417167802Sjkim    /* Install the new block in the global lists */
418114239Snjl
419151937Sjkim    Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber);
420114239Snjl    if (ACPI_FAILURE (Status))
421114239Snjl    {
422250838Sjkim        ACPI_FREE (GpeBlock->RegisterInfo);
423250838Sjkim        ACPI_FREE (GpeBlock->EventInfo);
424167802Sjkim        ACPI_FREE (GpeBlock);
425114239Snjl        return_ACPI_STATUS (Status);
426114239Snjl    }
427114239Snjl
428216471Sjkim    AcpiGbl_AllGpesInitialized = FALSE;
429216471Sjkim
430207344Sjkim    /* Find all GPE methods (_Lxx or_Exx) for this block */
431114239Snjl
432207344Sjkim    WalkInfo.GpeBlock = GpeBlock;
433207344Sjkim    WalkInfo.GpeDevice = GpeDevice;
434207344Sjkim    WalkInfo.ExecuteByOwnerId = FALSE;
435207344Sjkim
436117521Snjl    Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice,
437167802Sjkim                ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
438207344Sjkim                AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL);
439114239Snjl
440167802Sjkim    /* Return the new block */
441167802Sjkim
442167802Sjkim    if (ReturnGpeBlock)
443167802Sjkim    {
444167802Sjkim        (*ReturnGpeBlock) = GpeBlock;
445167802Sjkim    }
446167802Sjkim
447245582Sjkim    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
448281075Sdim        "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
449167802Sjkim        (UINT32) GpeBlock->BlockBaseNumber,
450206117Sjkim        (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)),
451281075Sdim        GpeDevice->Name.Ascii, GpeBlock->RegisterCount, InterruptNumber,
452281075Sdim        InterruptNumber == AcpiGbl_FADT.SciInterrupt ? " (SCI)" : ""));
453167802Sjkim
454193267Sjkim    /* Update global count of currently available GPEs */
455193267Sjkim
456206117Sjkim    AcpiCurrentGpeCount += GpeBlock->GpeCount;
457167802Sjkim    return_ACPI_STATUS (AE_OK);
458167802Sjkim}
459167802Sjkim
460167802Sjkim
461167802Sjkim/*******************************************************************************
462167802Sjkim *
463167802Sjkim * FUNCTION:    AcpiEvInitializeGpeBlock
464167802Sjkim *
465216471Sjkim * PARAMETERS:  ACPI_GPE_CALLBACK
466167802Sjkim *
467167802Sjkim * RETURN:      Status
468167802Sjkim *
469216471Sjkim * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
470216471Sjkim *              associated methods.
471167802Sjkim *              Note: Assumes namespace is locked.
472167802Sjkim *
473167802Sjkim ******************************************************************************/
474167802Sjkim
475167802SjkimACPI_STATUS
476167802SjkimAcpiEvInitializeGpeBlock (
477216471Sjkim    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
478216471Sjkim    ACPI_GPE_BLOCK_INFO     *GpeBlock,
479216471Sjkim    void                    *Ignored)
480167802Sjkim{
481167802Sjkim    ACPI_STATUS             Status;
482167802Sjkim    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
483167802Sjkim    UINT32                  GpeEnabledCount;
484206117Sjkim    UINT32                  GpeIndex;
485193267Sjkim    UINT32                  i;
486193267Sjkim    UINT32                  j;
487167802Sjkim
488167802Sjkim
489167802Sjkim    ACPI_FUNCTION_TRACE (EvInitializeGpeBlock);
490167802Sjkim
491167802Sjkim
492128212Snjl    /*
493216471Sjkim     * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
494216471Sjkim     * any GPE blocks that have been initialized already.
495128212Snjl     */
496216471Sjkim    if (!GpeBlock || GpeBlock->Initialized)
497128212Snjl    {
498216471Sjkim        return_ACPI_STATUS (AE_OK);
499128212Snjl    }
500128212Snjl
501129684Snjl    /*
502216471Sjkim     * Enable all GPEs that have a corresponding method and have the
503216471Sjkim     * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
504216471Sjkim     * must be enabled via the acpi_enable_gpe() interface.
505128212Snjl     */
506128212Snjl    GpeEnabledCount = 0;
507128212Snjl
508128212Snjl    for (i = 0; i < GpeBlock->RegisterCount; i++)
509128212Snjl    {
510206117Sjkim        for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
511128212Snjl        {
512128212Snjl            /* Get the info block for this particular GPE */
513128212Snjl
514206117Sjkim            GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j;
515206117Sjkim            GpeEventInfo = &GpeBlock->EventInfo[GpeIndex];
516129684Snjl
517209746Sjkim            /*
518216471Sjkim             * Ignore GPEs that have no corresponding _Lxx/_Exx method
519216471Sjkim             * and GPEs that are used to wake the system
520209746Sjkim             */
521281075Sdim            if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_NONE) ||
522281075Sdim                (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_HANDLER) ||
523281075Sdim                (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_RAW_HANDLER) ||
524216471Sjkim                (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE))
525209746Sjkim            {
526206117Sjkim                continue;
527128212Snjl            }
528206117Sjkim
529216471Sjkim            Status = AcpiEvAddGpeReference (GpeEventInfo);
530206117Sjkim            if (ACPI_FAILURE (Status))
531206117Sjkim            {
532206117Sjkim                ACPI_EXCEPTION ((AE_INFO, Status,
533216471Sjkim                    "Could not enable GPE 0x%02X",
534216471Sjkim                    GpeIndex + GpeBlock->BlockBaseNumber));
535206117Sjkim                continue;
536206117Sjkim            }
537206117Sjkim
538206117Sjkim            GpeEnabledCount++;
539128212Snjl        }
540128212Snjl    }
541128212Snjl
542216471Sjkim    if (GpeEnabledCount)
543117521Snjl    {
544245582Sjkim        ACPI_INFO ((AE_INFO,
545245582Sjkim            "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount,
546245582Sjkim            (UINT32) GpeBlock->BlockBaseNumber,
547245582Sjkim            (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1))));
548114239Snjl    }
549114239Snjl
550216471Sjkim    GpeBlock->Initialized = TRUE;
551114239Snjl    return_ACPI_STATUS (AE_OK);
552114239Snjl}
553114239Snjl
554231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
555