linux/drivers/acpi/acpica/evgpeblk.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Module Name: evgpeblk - GPE block creation and initialization.
   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 <acpi/acpi.h>
  45#include "accommon.h"
  46#include "acevents.h"
  47#include "acnamesp.h"
  48
  49#define _COMPONENT          ACPI_EVENTS
  50ACPI_MODULE_NAME("evgpeblk")
  51#if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
  52/* Local prototypes */
  53static acpi_status
  54acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
  55                          u32 interrupt_number);
  56
  57static acpi_status
  58acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
  59
  60/*******************************************************************************
  61 *
  62 * FUNCTION:    acpi_ev_install_gpe_block
  63 *
  64 * PARAMETERS:  gpe_block               - New GPE block
  65 *              interrupt_number        - Xrupt to be associated with this
  66 *                                        GPE block
  67 *
  68 * RETURN:      Status
  69 *
  70 * DESCRIPTION: Install new GPE block with mutex support
  71 *
  72 ******************************************************************************/
  73
  74static acpi_status
  75acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
  76                          u32 interrupt_number)
  77{
  78        struct acpi_gpe_block_info *next_gpe_block;
  79        struct acpi_gpe_xrupt_info *gpe_xrupt_block;
  80        acpi_status status;
  81        acpi_cpu_flags flags;
  82
  83        ACPI_FUNCTION_TRACE(ev_install_gpe_block);
  84
  85        status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
  86        if (ACPI_FAILURE(status)) {
  87                return_ACPI_STATUS(status);
  88        }
  89
  90        status =
  91            acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
  92        if (ACPI_FAILURE(status)) {
  93                goto unlock_and_exit;
  94        }
  95
  96        /* Install the new block at the end of the list with lock */
  97
  98        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
  99        if (gpe_xrupt_block->gpe_block_list_head) {
 100                next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
 101                while (next_gpe_block->next) {
 102                        next_gpe_block = next_gpe_block->next;
 103                }
 104
 105                next_gpe_block->next = gpe_block;
 106                gpe_block->previous = next_gpe_block;
 107        } else {
 108                gpe_xrupt_block->gpe_block_list_head = gpe_block;
 109        }
 110
 111        gpe_block->xrupt_block = gpe_xrupt_block;
 112        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 113
 114unlock_and_exit:
 115        (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 116        return_ACPI_STATUS(status);
 117}
 118
 119/*******************************************************************************
 120 *
 121 * FUNCTION:    acpi_ev_delete_gpe_block
 122 *
 123 * PARAMETERS:  gpe_block           - Existing GPE block
 124 *
 125 * RETURN:      Status
 126 *
 127 * DESCRIPTION: Remove a GPE block
 128 *
 129 ******************************************************************************/
 130
 131acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
 132{
 133        acpi_status status;
 134        acpi_cpu_flags flags;
 135
 136        ACPI_FUNCTION_TRACE(ev_install_gpe_block);
 137
 138        status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
 139        if (ACPI_FAILURE(status)) {
 140                return_ACPI_STATUS(status);
 141        }
 142
 143        /* Disable all GPEs in this block */
 144
 145        status =
 146            acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
 147
 148        if (!gpe_block->previous && !gpe_block->next) {
 149
 150                /* This is the last gpe_block on this interrupt */
 151
 152                status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
 153                if (ACPI_FAILURE(status)) {
 154                        goto unlock_and_exit;
 155                }
 156        } else {
 157                /* Remove the block on this interrupt with lock */
 158
 159                flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 160                if (gpe_block->previous) {
 161                        gpe_block->previous->next = gpe_block->next;
 162                } else {
 163                        gpe_block->xrupt_block->gpe_block_list_head =
 164                            gpe_block->next;
 165                }
 166
 167                if (gpe_block->next) {
 168                        gpe_block->next->previous = gpe_block->previous;
 169                }
 170                acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 171        }
 172
 173        acpi_current_gpe_count -= gpe_block->gpe_count;
 174
 175        /* Free the gpe_block */
 176
 177        ACPI_FREE(gpe_block->register_info);
 178        ACPI_FREE(gpe_block->event_info);
 179        ACPI_FREE(gpe_block);
 180
 181unlock_and_exit:
 182        status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 183        return_ACPI_STATUS(status);
 184}
 185
 186/*******************************************************************************
 187 *
 188 * FUNCTION:    acpi_ev_create_gpe_info_blocks
 189 *
 190 * PARAMETERS:  gpe_block   - New GPE block
 191 *
 192 * RETURN:      Status
 193 *
 194 * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
 195 *
 196 ******************************************************************************/
 197
 198static acpi_status
 199acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
 200{
 201        struct acpi_gpe_register_info *gpe_register_info = NULL;
 202        struct acpi_gpe_event_info *gpe_event_info = NULL;
 203        struct acpi_gpe_event_info *this_event;
 204        struct acpi_gpe_register_info *this_register;
 205        u32 i;
 206        u32 j;
 207        acpi_status status;
 208
 209        ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
 210
 211        /* Allocate the GPE register information block */
 212
 213        gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->
 214                                                 register_count *
 215                                                 sizeof(struct
 216                                                        acpi_gpe_register_info));
 217        if (!gpe_register_info) {
 218                ACPI_ERROR((AE_INFO,
 219                            "Could not allocate the GpeRegisterInfo table"));
 220                return_ACPI_STATUS(AE_NO_MEMORY);
 221        }
 222
 223        /*
 224         * Allocate the GPE event_info block. There are eight distinct GPEs
 225         * per register. Initialization to zeros is sufficient.
 226         */
 227        gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->gpe_count *
 228                                              sizeof(struct
 229                                                     acpi_gpe_event_info));
 230        if (!gpe_event_info) {
 231                ACPI_ERROR((AE_INFO,
 232                            "Could not allocate the GpeEventInfo table"));
 233                status = AE_NO_MEMORY;
 234                goto error_exit;
 235        }
 236
 237        /* Save the new Info arrays in the GPE block */
 238
 239        gpe_block->register_info = gpe_register_info;
 240        gpe_block->event_info = gpe_event_info;
 241
 242        /*
 243         * Initialize the GPE Register and Event structures. A goal of these
 244         * tables is to hide the fact that there are two separate GPE register
 245         * sets in a given GPE hardware block, the status registers occupy the
 246         * first half, and the enable registers occupy the second half.
 247         */
 248        this_register = gpe_register_info;
 249        this_event = gpe_event_info;
 250
 251        for (i = 0; i < gpe_block->register_count; i++) {
 252
 253                /* Init the register_info for this GPE register (8 GPEs) */
 254
 255                this_register->base_gpe_number = (u16)
 256                    (gpe_block->block_base_number +
 257                     (i * ACPI_GPE_REGISTER_WIDTH));
 258
 259                this_register->status_address.address = gpe_block->address + i;
 260
 261                this_register->enable_address.address =
 262                    gpe_block->address + i + gpe_block->register_count;
 263
 264                this_register->status_address.space_id = gpe_block->space_id;
 265                this_register->enable_address.space_id = gpe_block->space_id;
 266                this_register->status_address.bit_width =
 267                    ACPI_GPE_REGISTER_WIDTH;
 268                this_register->enable_address.bit_width =
 269                    ACPI_GPE_REGISTER_WIDTH;
 270                this_register->status_address.bit_offset = 0;
 271                this_register->enable_address.bit_offset = 0;
 272
 273                /* Init the event_info for each GPE within this register */
 274
 275                for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
 276                        this_event->gpe_number =
 277                            (u8) (this_register->base_gpe_number + j);
 278                        this_event->register_info = this_register;
 279                        this_event++;
 280                }
 281
 282                /* Disable all GPEs within this register */
 283
 284                status = acpi_hw_write(0x00, &this_register->enable_address);
 285                if (ACPI_FAILURE(status)) {
 286                        goto error_exit;
 287                }
 288
 289                /* Clear any pending GPE events within this register */
 290
 291                status = acpi_hw_write(0xFF, &this_register->status_address);
 292                if (ACPI_FAILURE(status)) {
 293                        goto error_exit;
 294                }
 295
 296                this_register++;
 297        }
 298
 299        return_ACPI_STATUS(AE_OK);
 300
 301error_exit:
 302        if (gpe_register_info) {
 303                ACPI_FREE(gpe_register_info);
 304        }
 305        if (gpe_event_info) {
 306                ACPI_FREE(gpe_event_info);
 307        }
 308
 309        return_ACPI_STATUS(status);
 310}
 311
 312/*******************************************************************************
 313 *
 314 * FUNCTION:    acpi_ev_create_gpe_block
 315 *
 316 * PARAMETERS:  gpe_device          - Handle to the parent GPE block
 317 *              gpe_block_address   - Address and space_ID
 318 *              register_count      - Number of GPE register pairs in the block
 319 *              gpe_block_base_number - Starting GPE number for the block
 320 *              interrupt_number    - H/W interrupt for the block
 321 *              return_gpe_block    - Where the new block descriptor is returned
 322 *
 323 * RETURN:      Status
 324 *
 325 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
 326 *              the block are disabled at exit.
 327 *              Note: Assumes namespace is locked.
 328 *
 329 ******************************************************************************/
 330
 331acpi_status
 332acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
 333                         u64 address,
 334                         u8 space_id,
 335                         u32 register_count,
 336                         u16 gpe_block_base_number,
 337                         u32 interrupt_number,
 338                         struct acpi_gpe_block_info **return_gpe_block)
 339{
 340        acpi_status status;
 341        struct acpi_gpe_block_info *gpe_block;
 342        struct acpi_gpe_walk_info walk_info;
 343
 344        ACPI_FUNCTION_TRACE(ev_create_gpe_block);
 345
 346        if (!register_count) {
 347                return_ACPI_STATUS(AE_OK);
 348        }
 349
 350        /* Allocate a new GPE block */
 351
 352        gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
 353        if (!gpe_block) {
 354                return_ACPI_STATUS(AE_NO_MEMORY);
 355        }
 356
 357        /* Initialize the new GPE block */
 358
 359        gpe_block->address = address;
 360        gpe_block->space_id = space_id;
 361        gpe_block->node = gpe_device;
 362        gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
 363        gpe_block->initialized = FALSE;
 364        gpe_block->register_count = register_count;
 365        gpe_block->block_base_number = gpe_block_base_number;
 366
 367        /*
 368         * Create the register_info and event_info sub-structures
 369         * Note: disables and clears all GPEs in the block
 370         */
 371        status = acpi_ev_create_gpe_info_blocks(gpe_block);
 372        if (ACPI_FAILURE(status)) {
 373                ACPI_FREE(gpe_block);
 374                return_ACPI_STATUS(status);
 375        }
 376
 377        /* Install the new block in the global lists */
 378
 379        status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
 380        if (ACPI_FAILURE(status)) {
 381                ACPI_FREE(gpe_block->register_info);
 382                ACPI_FREE(gpe_block->event_info);
 383                ACPI_FREE(gpe_block);
 384                return_ACPI_STATUS(status);
 385        }
 386
 387        acpi_gbl_all_gpes_initialized = FALSE;
 388
 389        /* Find all GPE methods (_Lxx or_Exx) for this block */
 390
 391        walk_info.gpe_block = gpe_block;
 392        walk_info.gpe_device = gpe_device;
 393        walk_info.execute_by_owner_id = FALSE;
 394
 395        status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
 396                                        ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
 397                                        acpi_ev_match_gpe_method, NULL,
 398                                        &walk_info, NULL);
 399
 400        /* Return the new block */
 401
 402        if (return_gpe_block) {
 403                (*return_gpe_block) = gpe_block;
 404        }
 405
 406        ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
 407                              "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
 408                              (u32)gpe_block->block_base_number,
 409                              (u32)(gpe_block->block_base_number +
 410                                    (gpe_block->gpe_count - 1)),
 411                              gpe_device->name.ascii, gpe_block->register_count,
 412                              interrupt_number,
 413                              interrupt_number ==
 414                              acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
 415
 416        /* Update global count of currently available GPEs */
 417
 418        acpi_current_gpe_count += gpe_block->gpe_count;
 419        return_ACPI_STATUS(AE_OK);
 420}
 421
 422/*******************************************************************************
 423 *
 424 * FUNCTION:    acpi_ev_initialize_gpe_block
 425 *
 426 * PARAMETERS:  acpi_gpe_callback
 427 *
 428 * RETURN:      Status
 429 *
 430 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
 431 *              associated methods.
 432 *              Note: Assumes namespace is locked.
 433 *
 434 ******************************************************************************/
 435
 436acpi_status
 437acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 438                             struct acpi_gpe_block_info *gpe_block,
 439                             void *ignored)
 440{
 441        acpi_status status;
 442        struct acpi_gpe_event_info *gpe_event_info;
 443        u32 gpe_enabled_count;
 444        u32 gpe_index;
 445        u32 i;
 446        u32 j;
 447
 448        ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
 449
 450        /*
 451         * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
 452         * any GPE blocks that have been initialized already.
 453         */
 454        if (!gpe_block || gpe_block->initialized) {
 455                return_ACPI_STATUS(AE_OK);
 456        }
 457
 458        /*
 459         * Enable all GPEs that have a corresponding method and have the
 460         * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
 461         * must be enabled via the acpi_enable_gpe() interface.
 462         */
 463        gpe_enabled_count = 0;
 464
 465        for (i = 0; i < gpe_block->register_count; i++) {
 466                for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
 467
 468                        /* Get the info block for this particular GPE */
 469
 470                        gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
 471                        gpe_event_info = &gpe_block->event_info[gpe_index];
 472
 473                        /*
 474                         * Ignore GPEs that have no corresponding _Lxx/_Exx method
 475                         * and GPEs that are used to wake the system
 476                         */
 477                        if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
 478                             ACPI_GPE_DISPATCH_NONE)
 479                            || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
 480                                ACPI_GPE_DISPATCH_HANDLER)
 481                            || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
 482                                ACPI_GPE_DISPATCH_RAW_HANDLER)
 483                            || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
 484                                continue;
 485                        }
 486
 487                        status = acpi_ev_add_gpe_reference(gpe_event_info);
 488                        if (ACPI_FAILURE(status)) {
 489                                ACPI_EXCEPTION((AE_INFO, status,
 490                                        "Could not enable GPE 0x%02X",
 491                                        gpe_index +
 492                                        gpe_block->block_base_number));
 493                                continue;
 494                        }
 495
 496                        gpe_enabled_count++;
 497                }
 498        }
 499
 500        if (gpe_enabled_count) {
 501                ACPI_INFO((AE_INFO,
 502                           "Enabled %u GPEs in block %02X to %02X",
 503                           gpe_enabled_count, (u32)gpe_block->block_base_number,
 504                           (u32)(gpe_block->block_base_number +
 505                                 (gpe_block->gpe_count - 1))));
 506        }
 507
 508        gpe_block->initialized = TRUE;
 509
 510        return_ACPI_STATUS(AE_OK);
 511}
 512
 513#endif                          /* !ACPI_REDUCED_HARDWARE */
 514