Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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
  50. ACPI_MODULE_NAME("evgpeblk")
  51. #if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
  52. /* Local prototypes */
  53. static acpi_status
  54. acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
  55.                           u32 interrupt_number);
  56.  
  57. static acpi_status
  58. acpi_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.  
  74. static acpi_status
  75. acpi_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.  
  114. unlock_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.  
  131. acpi_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.  
  181. unlock_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.  
  198. static acpi_status
  199. acpi_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.  
  301. error_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.  
  331. acpi_status
  332. acpi_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.  
  436. acpi_status
  437. acpi_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.