Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*******************************************************************************
  2.  *
  3.  * Module Name: hwpci - Obtain PCI bus, device, and function numbers
  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.  
  47. #define _COMPONENT          ACPI_NAMESPACE
  48. ACPI_MODULE_NAME("hwpci")
  49.  
  50. /* PCI configuration space values */
  51. #define PCI_CFG_HEADER_TYPE_REG             0x0E
  52. #define PCI_CFG_PRIMARY_BUS_NUMBER_REG      0x18
  53. #define PCI_CFG_SECONDARY_BUS_NUMBER_REG    0x19
  54. /* PCI header values */
  55. #define PCI_HEADER_TYPE_MASK                0x7F
  56. #define PCI_TYPE_BRIDGE                     0x01
  57. #define PCI_TYPE_CARDBUS_BRIDGE             0x02
  58. typedef struct acpi_pci_device {
  59.         acpi_handle device;
  60.         struct acpi_pci_device *next;
  61.  
  62. } acpi_pci_device;
  63.  
  64. /* Local prototypes */
  65.  
  66. static acpi_status
  67. acpi_hw_build_pci_list(acpi_handle root_pci_device,
  68.                        acpi_handle pci_region,
  69.                        struct acpi_pci_device **return_list_head);
  70.  
  71. static acpi_status
  72. acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
  73.                          struct acpi_pci_device *list_head);
  74.  
  75. static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
  76.  
  77. static acpi_status
  78. acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
  79.                             acpi_handle pci_device,
  80.                             u16 *bus_number, u8 *is_bridge);
  81.  
  82. /*******************************************************************************
  83.  *
  84.  * FUNCTION:    acpi_hw_derive_pci_id
  85.  *
  86.  * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
  87.  *                                    modified by this function.
  88.  *              root_pci_device     - A handle to a PCI device object. This
  89.  *                                    object must be a PCI Root Bridge having a
  90.  *                                    _HID value of either PNP0A03 or PNP0A08
  91.  *              pci_region          - A handle to a PCI configuration space
  92.  *                                    Operation Region being initialized
  93.  *
  94.  * RETURN:      Status
  95.  *
  96.  * DESCRIPTION: This function derives a full PCI ID for a PCI device,
  97.  *              consisting of a Segment number, Bus number, Device number,
  98.  *              and function code.
  99.  *
  100.  *              The PCI hardware dynamically configures PCI bus numbers
  101.  *              depending on the bus topology discovered during system
  102.  *              initialization. This function is invoked during configuration
  103.  *              of a PCI_Config Operation Region in order to (possibly) update
  104.  *              the Bus/Device/Function numbers in the pci_id with the actual
  105.  *              values as determined by the hardware and operating system
  106.  *              configuration.
  107.  *
  108.  *              The pci_id parameter is initially populated during the Operation
  109.  *              Region initialization. This function is then called, and is
  110.  *              will make any necessary modifications to the Bus, Device, or
  111.  *              Function number PCI ID subfields as appropriate for the
  112.  *              current hardware and OS configuration.
  113.  *
  114.  * NOTE:        Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
  115.  *              interface since this feature is OS-independent. This module
  116.  *              specifically avoids any use of recursion by building a local
  117.  *              temporary device list.
  118.  *
  119.  ******************************************************************************/
  120.  
  121. acpi_status
  122. acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
  123.                       acpi_handle root_pci_device, acpi_handle pci_region)
  124. {
  125.         acpi_status status;
  126.         struct acpi_pci_device *list_head;
  127.  
  128.         ACPI_FUNCTION_TRACE(hw_derive_pci_id);
  129.  
  130.         if (!pci_id) {
  131.                 return_ACPI_STATUS(AE_BAD_PARAMETER);
  132.         }
  133.  
  134.         /* Build a list of PCI devices, from pci_region up to root_pci_device */
  135.  
  136.         status =
  137.             acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
  138.         if (ACPI_SUCCESS(status)) {
  139.  
  140.                 /* Walk the list, updating the PCI device/function/bus numbers */
  141.  
  142.                 status = acpi_hw_process_pci_list(pci_id, list_head);
  143.  
  144.                 /* Delete the list */
  145.  
  146.                 acpi_hw_delete_pci_list(list_head);
  147.         }
  148.  
  149.         return_ACPI_STATUS(status);
  150. }
  151.  
  152. /*******************************************************************************
  153.  *
  154.  * FUNCTION:    acpi_hw_build_pci_list
  155.  *
  156.  * PARAMETERS:  root_pci_device     - A handle to a PCI device object. This
  157.  *                                    object is guaranteed to be a PCI Root
  158.  *                                    Bridge having a _HID value of either
  159.  *                                    PNP0A03 or PNP0A08
  160.  *              pci_region          - A handle to the PCI configuration space
  161.  *                                    Operation Region
  162.  *              return_list_head    - Where the PCI device list is returned
  163.  *
  164.  * RETURN:      Status
  165.  *
  166.  * DESCRIPTION: Builds a list of devices from the input PCI region up to the
  167.  *              Root PCI device for this namespace subtree.
  168.  *
  169.  ******************************************************************************/
  170.  
  171. static acpi_status
  172. acpi_hw_build_pci_list(acpi_handle root_pci_device,
  173.                        acpi_handle pci_region,
  174.                        struct acpi_pci_device **return_list_head)
  175. {
  176.         acpi_handle current_device;
  177.         acpi_handle parent_device;
  178.         acpi_status status;
  179.         struct acpi_pci_device *list_element;
  180.  
  181.         /*
  182.          * Ascend namespace branch until the root_pci_device is reached, building
  183.          * a list of device nodes. Loop will exit when either the PCI device is
  184.          * found, or the root of the namespace is reached.
  185.          */
  186.         *return_list_head = NULL;
  187.         current_device = pci_region;
  188.         while (1) {
  189.                 status = acpi_get_parent(current_device, &parent_device);
  190.                 if (ACPI_FAILURE(status)) {
  191.  
  192.                         /* Must delete the list before exit */
  193.  
  194.                         acpi_hw_delete_pci_list(*return_list_head);
  195.                         return (status);
  196.                 }
  197.  
  198.                 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
  199.  
  200.                 if (parent_device == root_pci_device) {
  201.                         return (AE_OK);
  202.                 }
  203.  
  204.                 list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
  205.                 if (!list_element) {
  206.  
  207.                         /* Must delete the list before exit */
  208.  
  209.                         acpi_hw_delete_pci_list(*return_list_head);
  210.                         return (AE_NO_MEMORY);
  211.                 }
  212.  
  213.                 /* Put new element at the head of the list */
  214.  
  215.                 list_element->next = *return_list_head;
  216.                 list_element->device = parent_device;
  217.                 *return_list_head = list_element;
  218.  
  219.                 current_device = parent_device;
  220.         }
  221. }
  222.  
  223. /*******************************************************************************
  224.  *
  225.  * FUNCTION:    acpi_hw_process_pci_list
  226.  *
  227.  * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
  228.  *                                    modified by this function.
  229.  *              list_head           - Device list created by
  230.  *                                    acpi_hw_build_pci_list
  231.  *
  232.  * RETURN:      Status
  233.  *
  234.  * DESCRIPTION: Walk downward through the PCI device list, getting the device
  235.  *              info for each, via the PCI configuration space and updating
  236.  *              the PCI ID as necessary. Deletes the list during traversal.
  237.  *
  238.  ******************************************************************************/
  239.  
  240. static acpi_status
  241. acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
  242.                          struct acpi_pci_device *list_head)
  243. {
  244.         acpi_status status = AE_OK;
  245.         struct acpi_pci_device *info;
  246.         u16 bus_number;
  247.         u8 is_bridge = TRUE;
  248.  
  249.         ACPI_FUNCTION_NAME(hw_process_pci_list);
  250.  
  251.         ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
  252.                           "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
  253.                           pci_id->segment, pci_id->bus, pci_id->device,
  254.                           pci_id->function));
  255.  
  256.         bus_number = pci_id->bus;
  257.  
  258.         /*
  259.          * Descend down the namespace tree, collecting PCI device, function,
  260.          * and bus numbers. bus_number is only important for PCI bridges.
  261.          * Algorithm: As we descend the tree, use the last valid PCI device,
  262.          * function, and bus numbers that are discovered, and assign them
  263.          * to the PCI ID for the target device.
  264.          */
  265.         info = list_head;
  266.         while (info) {
  267.                 status = acpi_hw_get_pci_device_info(pci_id, info->device,
  268.                                                      &bus_number, &is_bridge);
  269.                 if (ACPI_FAILURE(status)) {
  270.                         return (status);
  271.                 }
  272.  
  273.                 info = info->next;
  274.         }
  275.  
  276.         ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
  277.                           "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
  278.                           "Status %X BusNumber %X IsBridge %X\n",
  279.                           pci_id->segment, pci_id->bus, pci_id->device,
  280.                           pci_id->function, status, bus_number, is_bridge));
  281.  
  282.         return (AE_OK);
  283. }
  284.  
  285. /*******************************************************************************
  286.  *
  287.  * FUNCTION:    acpi_hw_delete_pci_list
  288.  *
  289.  * PARAMETERS:  list_head           - Device list created by
  290.  *                                    acpi_hw_build_pci_list
  291.  *
  292.  * RETURN:      None
  293.  *
  294.  * DESCRIPTION: Free the entire PCI list.
  295.  *
  296.  ******************************************************************************/
  297.  
  298. static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
  299. {
  300.         struct acpi_pci_device *next;
  301.         struct acpi_pci_device *previous;
  302.  
  303.         next = list_head;
  304.         while (next) {
  305.                 previous = next;
  306.                 next = previous->next;
  307.                 ACPI_FREE(previous);
  308.         }
  309. }
  310.  
  311. /*******************************************************************************
  312.  *
  313.  * FUNCTION:    acpi_hw_get_pci_device_info
  314.  *
  315.  * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
  316.  *                                    modified by this function.
  317.  *              pci_device          - Handle for the PCI device object
  318.  *              bus_number          - Where a PCI bridge bus number is returned
  319.  *              is_bridge           - Return value, indicates if this PCI
  320.  *                                    device is a PCI bridge
  321.  *
  322.  * RETURN:      Status
  323.  *
  324.  * DESCRIPTION: Get the device info for a single PCI device object. Get the
  325.  *              _ADR (contains PCI device and function numbers), and for PCI
  326.  *              bridge devices, get the bus number from PCI configuration
  327.  *              space.
  328.  *
  329.  ******************************************************************************/
  330.  
  331. static acpi_status
  332. acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
  333.                             acpi_handle pci_device,
  334.                             u16 *bus_number, u8 *is_bridge)
  335. {
  336.         acpi_status status;
  337.         acpi_object_type object_type;
  338.         u64 return_value;
  339.         u64 pci_value;
  340.  
  341.         /* We only care about objects of type Device */
  342.  
  343.         status = acpi_get_type(pci_device, &object_type);
  344.         if (ACPI_FAILURE(status)) {
  345.                 return (status);
  346.         }
  347.  
  348.         if (object_type != ACPI_TYPE_DEVICE) {
  349.                 return (AE_OK);
  350.         }
  351.  
  352.         /* We need an _ADR. Ignore device if not present */
  353.  
  354.         status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
  355.                                                  pci_device, &return_value);
  356.         if (ACPI_FAILURE(status)) {
  357.                 return (AE_OK);
  358.         }
  359.  
  360.         /*
  361.          * From _ADR, get the PCI Device and Function and
  362.          * update the PCI ID.
  363.          */
  364.         pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
  365.         pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
  366.  
  367.         /*
  368.          * If the previous device was a bridge, use the previous
  369.          * device bus number
  370.          */
  371.         if (*is_bridge) {
  372.                 pci_id->bus = *bus_number;
  373.         }
  374.  
  375.         /*
  376.          * Get the bus numbers from PCI Config space:
  377.          *
  378.          * First, get the PCI header_type
  379.          */
  380.         *is_bridge = FALSE;
  381.         status = acpi_os_read_pci_configuration(pci_id,
  382.                                                 PCI_CFG_HEADER_TYPE_REG,
  383.                                                 &pci_value, 8);
  384.         if (ACPI_FAILURE(status)) {
  385.                 return (status);
  386.         }
  387.  
  388.         /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
  389.  
  390.         pci_value &= PCI_HEADER_TYPE_MASK;
  391.  
  392.         if ((pci_value != PCI_TYPE_BRIDGE) &&
  393.             (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
  394.                 return (AE_OK);
  395.         }
  396.  
  397.         /* Bridge: Get the Primary bus_number */
  398.  
  399.         status = acpi_os_read_pci_configuration(pci_id,
  400.                                                 PCI_CFG_PRIMARY_BUS_NUMBER_REG,
  401.                                                 &pci_value, 8);
  402.         if (ACPI_FAILURE(status)) {
  403.                 return (status);
  404.         }
  405.  
  406.         *is_bridge = TRUE;
  407.         pci_id->bus = (u16)pci_value;
  408.  
  409.         /* Bridge: Get the Secondary bus_number */
  410.  
  411.         status = acpi_os_read_pci_configuration(pci_id,
  412.                                                 PCI_CFG_SECONDARY_BUS_NUMBER_REG,
  413.                                                 &pci_value, 8);
  414.         if (ACPI_FAILURE(status)) {
  415.                 return (status);
  416.         }
  417.  
  418.         *bus_number = (u16)pci_value;
  419.         return (AE_OK);
  420. }
  421.