1114239Snjl/******************************************************************************
2114239Snjl *
3114239Snjl * Module Name: evgpeblk - GPE block creation and initialization.
4114239Snjl *
5114239Snjl *****************************************************************************/
6114239Snjl
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, 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        }
196306536Sjkim
197151937Sjkim        AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
198117521Snjl    }
199117521Snjl
200206117Sjkim    AcpiCurrentGpeCount -= GpeBlock->GpeCount;
201193267Sjkim
202117521Snjl    /* Free the GpeBlock */
203117521Snjl
204167802Sjkim    ACPI_FREE (GpeBlock->RegisterInfo);
205167802Sjkim    ACPI_FREE (GpeBlock->EventInfo);
206167802Sjkim    ACPI_FREE (GpeBlock);
207117521Snjl
208117521SnjlUnlockAndExit:
209117521Snjl    Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
210117521Snjl    return_ACPI_STATUS (Status);
211117521Snjl}
212117521Snjl
213117521Snjl
214117521Snjl/*******************************************************************************
215117521Snjl *
216114239Snjl * FUNCTION:    AcpiEvCreateGpeInfoBlocks
217114239Snjl *
218114239Snjl * PARAMETERS:  GpeBlock    - New GPE block
219114239Snjl *
220114239Snjl * RETURN:      Status
221114239Snjl *
222114239Snjl * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block
223114239Snjl *
224114239Snjl ******************************************************************************/
225114239Snjl
226117521Snjlstatic ACPI_STATUS
227114239SnjlAcpiEvCreateGpeInfoBlocks (
228114239Snjl    ACPI_GPE_BLOCK_INFO     *GpeBlock)
229114239Snjl{
230114239Snjl    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo = NULL;
231114239Snjl    ACPI_GPE_EVENT_INFO     *GpeEventInfo = NULL;
232114239Snjl    ACPI_GPE_EVENT_INFO     *ThisEvent;
233114239Snjl    ACPI_GPE_REGISTER_INFO  *ThisRegister;
234193267Sjkim    UINT32                  i;
235193267Sjkim    UINT32                  j;
236114239Snjl    ACPI_STATUS             Status;
237114239Snjl
238114239Snjl
239167802Sjkim    ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks);
240114239Snjl
241114239Snjl
242114239Snjl    /* Allocate the GPE register information block */
243114239Snjl
244167802Sjkim    GpeRegisterInfo = ACPI_ALLOCATE_ZEROED (
245306536Sjkim        (ACPI_SIZE) GpeBlock->RegisterCount *
246306536Sjkim        sizeof (ACPI_GPE_REGISTER_INFO));
247114239Snjl    if (!GpeRegisterInfo)
248114239Snjl    {
249167802Sjkim        ACPI_ERROR ((AE_INFO,
250167802Sjkim            "Could not allocate the GpeRegisterInfo table"));
251114239Snjl        return_ACPI_STATUS (AE_NO_MEMORY);
252114239Snjl    }
253114239Snjl
254114239Snjl    /*
255167802Sjkim     * Allocate the GPE EventInfo block. There are eight distinct GPEs
256167802Sjkim     * per register. Initialization to zeros is sufficient.
257114239Snjl     */
258206117Sjkim    GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount *
259306536Sjkim        sizeof (ACPI_GPE_EVENT_INFO));
260114239Snjl    if (!GpeEventInfo)
261114239Snjl    {
262167802Sjkim        ACPI_ERROR ((AE_INFO,
263167802Sjkim            "Could not allocate the GpeEventInfo table"));
264114239Snjl        Status = AE_NO_MEMORY;
265114239Snjl        goto ErrorExit;
266114239Snjl    }
267114239Snjl
268117521Snjl    /* Save the new Info arrays in the GPE block */
269117521Snjl
270117521Snjl    GpeBlock->RegisterInfo = GpeRegisterInfo;
271306536Sjkim    GpeBlock->EventInfo = GpeEventInfo;
272117521Snjl
273114239Snjl    /*
274167802Sjkim     * Initialize the GPE Register and Event structures. A goal of these
275193267Sjkim     * tables is to hide the fact that there are two separate GPE register
276193267Sjkim     * sets in a given GPE hardware block, the status registers occupy the
277193267Sjkim     * first half, and the enable registers occupy the second half.
278114239Snjl     */
279114239Snjl    ThisRegister = GpeRegisterInfo;
280306536Sjkim    ThisEvent = GpeEventInfo;
281114239Snjl
282114239Snjl    for (i = 0; i < GpeBlock->RegisterCount; i++)
283114239Snjl    {
284114239Snjl        /* Init the RegisterInfo for this GPE register (8 GPEs) */
285114239Snjl
286281075Sdim        ThisRegister->BaseGpeNumber = (UINT16)
287281075Sdim            (GpeBlock->BlockBaseNumber + (i * ACPI_GPE_REGISTER_WIDTH));
288114239Snjl
289167802Sjkim        ThisRegister->StatusAddress.Address =
290281075Sdim            GpeBlock->Address + i;
291114239Snjl
292167802Sjkim        ThisRegister->EnableAddress.Address =
293281075Sdim            GpeBlock->Address + i + GpeBlock->RegisterCount;
294114239Snjl
295281075Sdim        ThisRegister->StatusAddress.SpaceId   = GpeBlock->SpaceId;
296281075Sdim        ThisRegister->EnableAddress.SpaceId   = GpeBlock->SpaceId;
297167802Sjkim        ThisRegister->StatusAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
298167802Sjkim        ThisRegister->EnableAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
299193267Sjkim        ThisRegister->StatusAddress.BitOffset = 0;
300193267Sjkim        ThisRegister->EnableAddress.BitOffset = 0;
301114239Snjl
302114239Snjl        /* Init the EventInfo for each GPE within this register */
303114239Snjl
304114239Snjl        for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
305114239Snjl        {
306167802Sjkim            ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j);
307114239Snjl            ThisEvent->RegisterInfo = ThisRegister;
308114239Snjl            ThisEvent++;
309114239Snjl        }
310114239Snjl
311167802Sjkim        /* Disable all GPEs within this register */
312167802Sjkim
313197104Sjkim        Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress);
314114239Snjl        if (ACPI_FAILURE (Status))
315114239Snjl        {
316114239Snjl            goto ErrorExit;
317114239Snjl        }
318114239Snjl
319167802Sjkim        /* Clear any pending GPE events within this register */
320167802Sjkim
321197104Sjkim        Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress);
322114239Snjl        if (ACPI_FAILURE (Status))
323114239Snjl        {
324114239Snjl            goto ErrorExit;
325114239Snjl        }
326114239Snjl
327114239Snjl        ThisRegister++;
328114239Snjl    }
329114239Snjl
330114239Snjl    return_ACPI_STATUS (AE_OK);
331114239Snjl
332114239Snjl
333114239SnjlErrorExit:
334114239Snjl    if (GpeRegisterInfo)
335114239Snjl    {
336167802Sjkim        ACPI_FREE (GpeRegisterInfo);
337114239Snjl    }
338114239Snjl    if (GpeEventInfo)
339114239Snjl    {
340167802Sjkim        ACPI_FREE (GpeEventInfo);
341114239Snjl    }
342114239Snjl
343117521Snjl    return_ACPI_STATUS (Status);
344114239Snjl}
345114239Snjl
346114239Snjl
347114239Snjl/*******************************************************************************
348114239Snjl *
349114239Snjl * FUNCTION:    AcpiEvCreateGpeBlock
350114239Snjl *
351117521Snjl * PARAMETERS:  GpeDevice           - Handle to the parent GPE block
352117521Snjl *              GpeBlockAddress     - Address and SpaceID
353117521Snjl *              RegisterCount       - Number of GPE register pairs in the block
354117521Snjl *              GpeBlockBaseNumber  - Starting GPE number for the block
355151937Sjkim *              InterruptNumber     - H/W interrupt for the block
356117521Snjl *              ReturnGpeBlock      - Where the new block descriptor is returned
357114239Snjl *
358114239Snjl * RETURN:      Status
359114239Snjl *
360167802Sjkim * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
361167802Sjkim *              the block are disabled at exit.
362167802Sjkim *              Note: Assumes namespace is locked.
363114239Snjl *
364114239Snjl ******************************************************************************/
365114239Snjl
366114239SnjlACPI_STATUS
367114239SnjlAcpiEvCreateGpeBlock (
368117521Snjl    ACPI_NAMESPACE_NODE     *GpeDevice,
369281075Sdim    UINT64                  Address,
370281075Sdim    UINT8                   SpaceId,
371114239Snjl    UINT32                  RegisterCount,
372281075Sdim    UINT16                  GpeBlockBaseNumber,
373151937Sjkim    UINT32                  InterruptNumber,
374117521Snjl    ACPI_GPE_BLOCK_INFO     **ReturnGpeBlock)
375114239Snjl{
376167802Sjkim    ACPI_STATUS             Status;
377114239Snjl    ACPI_GPE_BLOCK_INFO     *GpeBlock;
378207344Sjkim    ACPI_GPE_WALK_INFO      WalkInfo;
379114239Snjl
380129684Snjl
381167802Sjkim    ACPI_FUNCTION_TRACE (EvCreateGpeBlock);
382114239Snjl
383114239Snjl
384114239Snjl    if (!RegisterCount)
385114239Snjl    {
386114239Snjl        return_ACPI_STATUS (AE_OK);
387114239Snjl    }
388114239Snjl
389114239Snjl    /* Allocate a new GPE block */
390114239Snjl
391167802Sjkim    GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO));
392114239Snjl    if (!GpeBlock)
393114239Snjl    {
394114239Snjl        return_ACPI_STATUS (AE_NO_MEMORY);
395114239Snjl    }
396114239Snjl
397114239Snjl    /* Initialize the new GPE block */
398114239Snjl
399281075Sdim    GpeBlock->Address = Address;
400281075Sdim    GpeBlock->SpaceId = SpaceId;
401167802Sjkim    GpeBlock->Node = GpeDevice;
402206117Sjkim    GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH);
403216471Sjkim    GpeBlock->Initialized = FALSE;
404167802Sjkim    GpeBlock->RegisterCount = RegisterCount;
405114239Snjl    GpeBlock->BlockBaseNumber = GpeBlockBaseNumber;
406114239Snjl
407167802Sjkim    /*
408167802Sjkim     * Create the RegisterInfo and EventInfo sub-structures
409167802Sjkim     * Note: disables and clears all GPEs in the block
410167802Sjkim     */
411114239Snjl    Status = AcpiEvCreateGpeInfoBlocks (GpeBlock);
412114239Snjl    if (ACPI_FAILURE (Status))
413114239Snjl    {
414167802Sjkim        ACPI_FREE (GpeBlock);
415114239Snjl        return_ACPI_STATUS (Status);
416114239Snjl    }
417114239Snjl
418167802Sjkim    /* Install the new block in the global lists */
419114239Snjl
420151937Sjkim    Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber);
421114239Snjl    if (ACPI_FAILURE (Status))
422114239Snjl    {
423250838Sjkim        ACPI_FREE (GpeBlock->RegisterInfo);
424250838Sjkim        ACPI_FREE (GpeBlock->EventInfo);
425167802Sjkim        ACPI_FREE (GpeBlock);
426114239Snjl        return_ACPI_STATUS (Status);
427114239Snjl    }
428114239Snjl
429216471Sjkim    AcpiGbl_AllGpesInitialized = FALSE;
430216471Sjkim
431207344Sjkim    /* Find all GPE methods (_Lxx or_Exx) for this block */
432114239Snjl
433207344Sjkim    WalkInfo.GpeBlock = GpeBlock;
434207344Sjkim    WalkInfo.GpeDevice = GpeDevice;
435207344Sjkim    WalkInfo.ExecuteByOwnerId = FALSE;
436207344Sjkim
437117521Snjl    Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice,
438306536Sjkim        ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
439306536Sjkim        AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL);
440114239Snjl
441167802Sjkim    /* Return the new block */
442167802Sjkim
443167802Sjkim    if (ReturnGpeBlock)
444167802Sjkim    {
445167802Sjkim        (*ReturnGpeBlock) = GpeBlock;
446167802Sjkim    }
447167802Sjkim
448245582Sjkim    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
449281075Sdim        "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
450167802Sjkim        (UINT32) GpeBlock->BlockBaseNumber,
451206117Sjkim        (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)),
452281075Sdim        GpeDevice->Name.Ascii, GpeBlock->RegisterCount, InterruptNumber,
453281075Sdim        InterruptNumber == AcpiGbl_FADT.SciInterrupt ? " (SCI)" : ""));
454167802Sjkim
455193267Sjkim    /* Update global count of currently available GPEs */
456193267Sjkim
457206117Sjkim    AcpiCurrentGpeCount += GpeBlock->GpeCount;
458167802Sjkim    return_ACPI_STATUS (AE_OK);
459167802Sjkim}
460167802Sjkim
461167802Sjkim
462167802Sjkim/*******************************************************************************
463167802Sjkim *
464167802Sjkim * FUNCTION:    AcpiEvInitializeGpeBlock
465167802Sjkim *
466216471Sjkim * PARAMETERS:  ACPI_GPE_CALLBACK
467167802Sjkim *
468167802Sjkim * RETURN:      Status
469167802Sjkim *
470216471Sjkim * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
471216471Sjkim *              associated methods.
472167802Sjkim *              Note: Assumes namespace is locked.
473167802Sjkim *
474167802Sjkim ******************************************************************************/
475167802Sjkim
476167802SjkimACPI_STATUS
477167802SjkimAcpiEvInitializeGpeBlock (
478216471Sjkim    ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
479216471Sjkim    ACPI_GPE_BLOCK_INFO     *GpeBlock,
480216471Sjkim    void                    *Ignored)
481167802Sjkim{
482167802Sjkim    ACPI_STATUS             Status;
483167802Sjkim    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
484167802Sjkim    UINT32                  GpeEnabledCount;
485206117Sjkim    UINT32                  GpeIndex;
486193267Sjkim    UINT32                  i;
487193267Sjkim    UINT32                  j;
488167802Sjkim
489167802Sjkim
490167802Sjkim    ACPI_FUNCTION_TRACE (EvInitializeGpeBlock);
491167802Sjkim
492167802Sjkim
493128212Snjl    /*
494216471Sjkim     * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
495216471Sjkim     * any GPE blocks that have been initialized already.
496128212Snjl     */
497216471Sjkim    if (!GpeBlock || GpeBlock->Initialized)
498128212Snjl    {
499216471Sjkim        return_ACPI_STATUS (AE_OK);
500128212Snjl    }
501128212Snjl
502129684Snjl    /*
503216471Sjkim     * Enable all GPEs that have a corresponding method and have the
504216471Sjkim     * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
505216471Sjkim     * must be enabled via the acpi_enable_gpe() interface.
506128212Snjl     */
507128212Snjl    GpeEnabledCount = 0;
508128212Snjl
509128212Snjl    for (i = 0; i < GpeBlock->RegisterCount; i++)
510128212Snjl    {
511206117Sjkim        for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
512128212Snjl        {
513128212Snjl            /* Get the info block for this particular GPE */
514128212Snjl
515206117Sjkim            GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j;
516206117Sjkim            GpeEventInfo = &GpeBlock->EventInfo[GpeIndex];
517129684Snjl
518209746Sjkim            /*
519216471Sjkim             * Ignore GPEs that have no corresponding _Lxx/_Exx method
520216471Sjkim             * and GPEs that are used to wake the system
521209746Sjkim             */
522281075Sdim            if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_NONE) ||
523281075Sdim                (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_HANDLER) ||
524281075Sdim                (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_RAW_HANDLER) ||
525216471Sjkim                (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE))
526209746Sjkim            {
527206117Sjkim                continue;
528128212Snjl            }
529206117Sjkim
530216471Sjkim            Status = AcpiEvAddGpeReference (GpeEventInfo);
531206117Sjkim            if (ACPI_FAILURE (Status))
532206117Sjkim            {
533206117Sjkim                ACPI_EXCEPTION ((AE_INFO, Status,
534216471Sjkim                    "Could not enable GPE 0x%02X",
535216471Sjkim                    GpeIndex + GpeBlock->BlockBaseNumber));
536206117Sjkim                continue;
537206117Sjkim            }
538206117Sjkim
539206117Sjkim            GpeEnabledCount++;
540128212Snjl        }
541128212Snjl    }
542128212Snjl
543216471Sjkim    if (GpeEnabledCount)
544117521Snjl    {
545306536Sjkim        ACPI_INFO ((
546245582Sjkim            "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount,
547245582Sjkim            (UINT32) GpeBlock->BlockBaseNumber,
548245582Sjkim            (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1))));
549114239Snjl    }
550114239Snjl
551216471Sjkim    GpeBlock->Initialized = TRUE;
552114239Snjl    return_ACPI_STATUS (AE_OK);
553114239Snjl}
554114239Snjl
555231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
556