evhandler.c revision 281075
1/******************************************************************************
2 *
3 * Module Name: evhandler - Support for Address Space handlers
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2015, 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    ("evhandler")
52
53
54/* Local prototypes */
55
56static ACPI_STATUS
57AcpiEvInstallHandler (
58    ACPI_HANDLE             ObjHandle,
59    UINT32                  Level,
60    void                    *Context,
61    void                    **ReturnValue);
62
63/* These are the address spaces that will get default handlers */
64
65UINT8        AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] =
66{
67    ACPI_ADR_SPACE_SYSTEM_MEMORY,
68    ACPI_ADR_SPACE_SYSTEM_IO,
69    ACPI_ADR_SPACE_PCI_CONFIG,
70    ACPI_ADR_SPACE_DATA_TABLE
71};
72
73
74/*******************************************************************************
75 *
76 * FUNCTION:    AcpiEvInstallRegionHandlers
77 *
78 * PARAMETERS:  None
79 *
80 * RETURN:      Status
81 *
82 * DESCRIPTION: Installs the core subsystem default address space handlers.
83 *
84 ******************************************************************************/
85
86ACPI_STATUS
87AcpiEvInstallRegionHandlers (
88    void)
89{
90    ACPI_STATUS             Status;
91    UINT32                  i;
92
93
94    ACPI_FUNCTION_TRACE (EvInstallRegionHandlers);
95
96
97    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
98    if (ACPI_FAILURE (Status))
99    {
100        return_ACPI_STATUS (Status);
101    }
102
103    /*
104     * All address spaces (PCI Config, EC, SMBus) are scope dependent and
105     * registration must occur for a specific device.
106     *
107     * In the case of the system memory and IO address spaces there is
108     * currently no device associated with the address space. For these we
109     * use the root.
110     *
111     * We install the default PCI config space handler at the root so that
112     * this space is immediately available even though the we have not
113     * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
114     * specification which states that the PCI config space must be always
115     * available -- even though we are nowhere near ready to find the PCI root
116     * buses at this point.
117     *
118     * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
119     * has already been installed (via AcpiInstallAddressSpaceHandler).
120     * Similar for AE_SAME_HANDLER.
121     */
122    for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++)
123    {
124        Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode,
125                    AcpiGbl_DefaultAddressSpaces[i],
126                    ACPI_DEFAULT_HANDLER, NULL, NULL);
127        switch (Status)
128        {
129        case AE_OK:
130        case AE_SAME_HANDLER:
131        case AE_ALREADY_EXISTS:
132
133            /* These exceptions are all OK */
134
135            Status = AE_OK;
136            break;
137
138        default:
139
140            goto UnlockAndExit;
141        }
142    }
143
144UnlockAndExit:
145    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
146    return_ACPI_STATUS (Status);
147}
148
149
150/*******************************************************************************
151 *
152 * FUNCTION:    AcpiEvHasDefaultHandler
153 *
154 * PARAMETERS:  Node                - Namespace node for the device
155 *              SpaceId             - The address space ID
156 *
157 * RETURN:      TRUE if default handler is installed, FALSE otherwise
158 *
159 * DESCRIPTION: Check if the default handler is installed for the requested
160 *              space ID.
161 *
162 ******************************************************************************/
163
164BOOLEAN
165AcpiEvHasDefaultHandler (
166    ACPI_NAMESPACE_NODE     *Node,
167    ACPI_ADR_SPACE_TYPE     SpaceId)
168{
169    ACPI_OPERAND_OBJECT     *ObjDesc;
170    ACPI_OPERAND_OBJECT     *HandlerObj;
171
172
173    /* Must have an existing internal object */
174
175    ObjDesc = AcpiNsGetAttachedObject (Node);
176    if (ObjDesc)
177    {
178        HandlerObj = ObjDesc->Device.Handler;
179
180        /* Walk the linked list of handlers for this object */
181
182        while (HandlerObj)
183        {
184            if (HandlerObj->AddressSpace.SpaceId == SpaceId)
185            {
186                if (HandlerObj->AddressSpace.HandlerFlags &
187                        ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
188                {
189                    return (TRUE);
190                }
191            }
192
193            HandlerObj = HandlerObj->AddressSpace.Next;
194        }
195    }
196
197    return (FALSE);
198}
199
200
201/*******************************************************************************
202 *
203 * FUNCTION:    AcpiEvInstallHandler
204 *
205 * PARAMETERS:  WalkNamespace callback
206 *
207 * DESCRIPTION: This routine installs an address handler into objects that are
208 *              of type Region or Device.
209 *
210 *              If the Object is a Device, and the device has a handler of
211 *              the same type then the search is terminated in that branch.
212 *
213 *              This is because the existing handler is closer in proximity
214 *              to any more regions than the one we are trying to install.
215 *
216 ******************************************************************************/
217
218static ACPI_STATUS
219AcpiEvInstallHandler (
220    ACPI_HANDLE             ObjHandle,
221    UINT32                  Level,
222    void                    *Context,
223    void                    **ReturnValue)
224{
225    ACPI_OPERAND_OBJECT     *HandlerObj;
226    ACPI_OPERAND_OBJECT     *NextHandlerObj;
227    ACPI_OPERAND_OBJECT     *ObjDesc;
228    ACPI_NAMESPACE_NODE     *Node;
229    ACPI_STATUS             Status;
230
231
232    ACPI_FUNCTION_NAME (EvInstallHandler);
233
234
235    HandlerObj = (ACPI_OPERAND_OBJECT  *) Context;
236
237    /* Parameter validation */
238
239    if (!HandlerObj)
240    {
241        return (AE_OK);
242    }
243
244    /* Convert and validate the device handle */
245
246    Node = AcpiNsValidateHandle (ObjHandle);
247    if (!Node)
248    {
249        return (AE_BAD_PARAMETER);
250    }
251
252    /*
253     * We only care about regions and objects that are allowed to have
254     * address space handlers
255     */
256    if ((Node->Type != ACPI_TYPE_DEVICE) &&
257        (Node->Type != ACPI_TYPE_REGION) &&
258        (Node != AcpiGbl_RootNode))
259    {
260        return (AE_OK);
261    }
262
263    /* Check for an existing internal object */
264
265    ObjDesc = AcpiNsGetAttachedObject (Node);
266    if (!ObjDesc)
267    {
268        /* No object, just exit */
269
270        return (AE_OK);
271    }
272
273    /* Devices are handled different than regions */
274
275    if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE)
276    {
277        /* Check if this Device already has a handler for this address space */
278
279        NextHandlerObj = ObjDesc->Device.Handler;
280        while (NextHandlerObj)
281        {
282            /* Found a handler, is it for the same address space? */
283
284            if (NextHandlerObj->AddressSpace.SpaceId ==
285                    HandlerObj->AddressSpace.SpaceId)
286            {
287                ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
288                    "Found handler for region [%s] in device %p(%p) "
289                    "handler %p\n",
290                    AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId),
291                    ObjDesc, NextHandlerObj, HandlerObj));
292
293                /*
294                 * Since the object we found it on was a device, then it
295                 * means that someone has already installed a handler for
296                 * the branch of the namespace from this device on. Just
297                 * bail out telling the walk routine to not traverse this
298                 * branch. This preserves the scoping rule for handlers.
299                 */
300                return (AE_CTRL_DEPTH);
301            }
302
303            /* Walk the linked list of handlers attached to this device */
304
305            NextHandlerObj = NextHandlerObj->AddressSpace.Next;
306        }
307
308        /*
309         * As long as the device didn't have a handler for this space we
310         * don't care about it. We just ignore it and proceed.
311         */
312        return (AE_OK);
313    }
314
315    /* Object is a Region */
316
317    if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId)
318    {
319        /* This region is for a different address space, just ignore it */
320
321        return (AE_OK);
322    }
323
324    /*
325     * Now we have a region and it is for the handler's address space type.
326     *
327     * First disconnect region for any previous handler (if any)
328     */
329    AcpiEvDetachRegion (ObjDesc, FALSE);
330
331    /* Connect the region to the new handler */
332
333    Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE);
334    return (Status);
335}
336
337
338/*******************************************************************************
339 *
340 * FUNCTION:    AcpiEvInstallSpaceHandler
341 *
342 * PARAMETERS:  Node            - Namespace node for the device
343 *              SpaceId         - The address space ID
344 *              Handler         - Address of the handler
345 *              Setup           - Address of the setup function
346 *              Context         - Value passed to the handler on each access
347 *
348 * RETURN:      Status
349 *
350 * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId.
351 *              Assumes namespace is locked
352 *
353 ******************************************************************************/
354
355ACPI_STATUS
356AcpiEvInstallSpaceHandler (
357    ACPI_NAMESPACE_NODE     *Node,
358    ACPI_ADR_SPACE_TYPE     SpaceId,
359    ACPI_ADR_SPACE_HANDLER  Handler,
360    ACPI_ADR_SPACE_SETUP    Setup,
361    void                    *Context)
362{
363    ACPI_OPERAND_OBJECT     *ObjDesc;
364    ACPI_OPERAND_OBJECT     *HandlerObj;
365    ACPI_STATUS             Status;
366    ACPI_OBJECT_TYPE        Type;
367    UINT8                  Flags = 0;
368
369
370    ACPI_FUNCTION_TRACE (EvInstallSpaceHandler);
371
372
373    /*
374     * This registration is valid for only the types below and the root. This
375     * is where the default handlers get placed.
376     */
377    if ((Node->Type != ACPI_TYPE_DEVICE)     &&
378        (Node->Type != ACPI_TYPE_PROCESSOR)  &&
379        (Node->Type != ACPI_TYPE_THERMAL)    &&
380        (Node != AcpiGbl_RootNode))
381    {
382        Status = AE_BAD_PARAMETER;
383        goto UnlockAndExit;
384    }
385
386    if (Handler == ACPI_DEFAULT_HANDLER)
387    {
388        Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
389
390        switch (SpaceId)
391        {
392        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
393
394            Handler = AcpiExSystemMemorySpaceHandler;
395            Setup   = AcpiEvSystemMemoryRegionSetup;
396            break;
397
398        case ACPI_ADR_SPACE_SYSTEM_IO:
399
400            Handler = AcpiExSystemIoSpaceHandler;
401            Setup   = AcpiEvIoSpaceRegionSetup;
402            break;
403
404        case ACPI_ADR_SPACE_PCI_CONFIG:
405
406            Handler = AcpiExPciConfigSpaceHandler;
407            Setup   = AcpiEvPciConfigRegionSetup;
408            break;
409
410        case ACPI_ADR_SPACE_CMOS:
411
412            Handler = AcpiExCmosSpaceHandler;
413            Setup   = AcpiEvCmosRegionSetup;
414            break;
415
416        case ACPI_ADR_SPACE_PCI_BAR_TARGET:
417
418            Handler = AcpiExPciBarSpaceHandler;
419            Setup   = AcpiEvPciBarRegionSetup;
420            break;
421
422        case ACPI_ADR_SPACE_DATA_TABLE:
423
424            Handler = AcpiExDataTableSpaceHandler;
425            Setup   = NULL;
426            break;
427
428        default:
429
430            Status = AE_BAD_PARAMETER;
431            goto UnlockAndExit;
432        }
433    }
434
435    /* If the caller hasn't specified a setup routine, use the default */
436
437    if (!Setup)
438    {
439        Setup = AcpiEvDefaultRegionSetup;
440    }
441
442    /* Check for an existing internal object */
443
444    ObjDesc = AcpiNsGetAttachedObject (Node);
445    if (ObjDesc)
446    {
447        /*
448         * The attached device object already exists. Make sure the handler
449         * is not already installed.
450         */
451        HandlerObj = ObjDesc->Device.Handler;
452
453        /* Walk the handler list for this device */
454
455        while (HandlerObj)
456        {
457            /* Same SpaceId indicates a handler already installed */
458
459            if (HandlerObj->AddressSpace.SpaceId == SpaceId)
460            {
461                if (HandlerObj->AddressSpace.Handler == Handler)
462                {
463                    /*
464                     * It is (relatively) OK to attempt to install the SAME
465                     * handler twice. This can easily happen with the
466                     * PCI_Config space.
467                     */
468                    Status = AE_SAME_HANDLER;
469                    goto UnlockAndExit;
470                }
471                else
472                {
473                    /* A handler is already installed */
474
475                    Status = AE_ALREADY_EXISTS;
476                }
477                goto UnlockAndExit;
478            }
479
480            /* Walk the linked list of handlers */
481
482            HandlerObj = HandlerObj->AddressSpace.Next;
483        }
484    }
485    else
486    {
487        ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
488            "Creating object on Device %p while installing handler\n", Node));
489
490        /* ObjDesc does not exist, create one */
491
492        if (Node->Type == ACPI_TYPE_ANY)
493        {
494            Type = ACPI_TYPE_DEVICE;
495        }
496        else
497        {
498            Type = Node->Type;
499        }
500
501        ObjDesc = AcpiUtCreateInternalObject (Type);
502        if (!ObjDesc)
503        {
504            Status = AE_NO_MEMORY;
505            goto UnlockAndExit;
506        }
507
508        /* Init new descriptor */
509
510        ObjDesc->Common.Type = (UINT8) Type;
511
512        /* Attach the new object to the Node */
513
514        Status = AcpiNsAttachObject (Node, ObjDesc, Type);
515
516        /* Remove local reference to the object */
517
518        AcpiUtRemoveReference (ObjDesc);
519
520        if (ACPI_FAILURE (Status))
521        {
522            goto UnlockAndExit;
523        }
524    }
525
526    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
527        "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
528        AcpiUtGetRegionName (SpaceId), SpaceId,
529        AcpiUtGetNodeName (Node), Node, ObjDesc));
530
531    /*
532     * Install the handler
533     *
534     * At this point there is no existing handler. Just allocate the object
535     * for the handler and link it into the list.
536     */
537    HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
538    if (!HandlerObj)
539    {
540        Status = AE_NO_MEMORY;
541        goto UnlockAndExit;
542    }
543
544    /* Init handler obj */
545
546    HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId;
547    HandlerObj->AddressSpace.HandlerFlags = Flags;
548    HandlerObj->AddressSpace.RegionList = NULL;
549    HandlerObj->AddressSpace.Node = Node;
550    HandlerObj->AddressSpace.Handler = Handler;
551    HandlerObj->AddressSpace.Context = Context;
552    HandlerObj->AddressSpace.Setup  = Setup;
553
554    /* Install at head of Device.AddressSpace list */
555
556    HandlerObj->AddressSpace.Next = ObjDesc->Device.Handler;
557
558    /*
559     * The Device object is the first reference on the HandlerObj.
560     * Each region that uses the handler adds a reference.
561     */
562    ObjDesc->Device.Handler = HandlerObj;
563
564    /*
565     * Walk the namespace finding all of the regions this
566     * handler will manage.
567     *
568     * Start at the device and search the branch toward
569     * the leaf nodes until either the leaf is encountered or
570     * a device is detected that has an address handler of the
571     * same type.
572     *
573     * In either case, back up and search down the remainder
574     * of the branch
575     */
576    Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
577                ACPI_NS_WALK_UNLOCK, AcpiEvInstallHandler, NULL,
578                HandlerObj, NULL);
579
580UnlockAndExit:
581    return_ACPI_STATUS (Status);
582}
583