linux/drivers/acpi/acpica/hwpci.c
<<
>>
Prefs
   1/*******************************************************************************
   2 *
   3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers
   4 *
   5 ******************************************************************************/
   6
   7/*
   8 * Copyright (C) 2000 - 2013, 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
  48ACPI_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
  58typedef struct acpi_pci_device {
  59        acpi_handle device;
  60        struct acpi_pci_device *next;
  61
  62} acpi_pci_device;
  63
  64/* Local prototypes */
  65
  66static acpi_status
  67acpi_hw_build_pci_list(acpi_handle root_pci_device,
  68                       acpi_handle pci_region,
  69                       struct acpi_pci_device **return_list_head);
  70
  71static acpi_status
  72acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
  73                         struct acpi_pci_device *list_head);
  74
  75static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
  76
  77static acpi_status
  78acpi_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
 121acpi_status
 122acpi_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 = NULL;
 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
 145        /* Always delete the list */
 146
 147        acpi_hw_delete_pci_list(list_head);
 148        return_ACPI_STATUS(status);
 149}
 150
 151/*******************************************************************************
 152 *
 153 * FUNCTION:    acpi_hw_build_pci_list
 154 *
 155 * PARAMETERS:  root_pci_device     - A handle to a PCI device object. This
 156 *                                    object is guaranteed to be a PCI Root
 157 *                                    Bridge having a _HID value of either
 158 *                                    PNP0A03 or PNP0A08
 159 *              pci_region          - A handle to the PCI configuration space
 160 *                                    Operation Region
 161 *              return_list_head    - Where the PCI device list is returned
 162 *
 163 * RETURN:      Status
 164 *
 165 * DESCRIPTION: Builds a list of devices from the input PCI region up to the
 166 *              Root PCI device for this namespace subtree.
 167 *
 168 ******************************************************************************/
 169
 170static acpi_status
 171acpi_hw_build_pci_list(acpi_handle root_pci_device,
 172                       acpi_handle pci_region,
 173                       struct acpi_pci_device **return_list_head)
 174{
 175        acpi_handle current_device;
 176        acpi_handle parent_device;
 177        acpi_status status;
 178        struct acpi_pci_device *list_element;
 179        struct acpi_pci_device *list_head = NULL;
 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        current_device = pci_region;
 187        while (1) {
 188                status = acpi_get_parent(current_device, &parent_device);
 189                if (ACPI_FAILURE(status)) {
 190                        return (status);
 191                }
 192
 193                /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
 194
 195                if (parent_device == root_pci_device) {
 196                        *return_list_head = list_head;
 197                        return (AE_OK);
 198                }
 199
 200                list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
 201                if (!list_element) {
 202                        return (AE_NO_MEMORY);
 203                }
 204
 205                /* Put new element at the head of the list */
 206
 207                list_element->next = list_head;
 208                list_element->device = parent_device;
 209                list_head = list_element;
 210
 211                current_device = parent_device;
 212        }
 213}
 214
 215/*******************************************************************************
 216 *
 217 * FUNCTION:    acpi_hw_process_pci_list
 218 *
 219 * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
 220 *                                    modified by this function.
 221 *              list_head           - Device list created by
 222 *                                    acpi_hw_build_pci_list
 223 *
 224 * RETURN:      Status
 225 *
 226 * DESCRIPTION: Walk downward through the PCI device list, getting the device
 227 *              info for each, via the PCI configuration space and updating
 228 *              the PCI ID as necessary. Deletes the list during traversal.
 229 *
 230 ******************************************************************************/
 231
 232static acpi_status
 233acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
 234                         struct acpi_pci_device *list_head)
 235{
 236        acpi_status status = AE_OK;
 237        struct acpi_pci_device *info;
 238        u16 bus_number;
 239        u8 is_bridge = TRUE;
 240
 241        ACPI_FUNCTION_NAME(hw_process_pci_list);
 242
 243        ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
 244                          "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
 245                          pci_id->segment, pci_id->bus, pci_id->device,
 246                          pci_id->function));
 247
 248        bus_number = pci_id->bus;
 249
 250        /*
 251         * Descend down the namespace tree, collecting PCI device, function,
 252         * and bus numbers. bus_number is only important for PCI bridges.
 253         * Algorithm: As we descend the tree, use the last valid PCI device,
 254         * function, and bus numbers that are discovered, and assign them
 255         * to the PCI ID for the target device.
 256         */
 257        info = list_head;
 258        while (info) {
 259                status = acpi_hw_get_pci_device_info(pci_id, info->device,
 260                                                     &bus_number, &is_bridge);
 261                if (ACPI_FAILURE(status)) {
 262                        return (status);
 263                }
 264
 265                info = info->next;
 266        }
 267
 268        ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
 269                          "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
 270                          "Status %X BusNumber %X IsBridge %X\n",
 271                          pci_id->segment, pci_id->bus, pci_id->device,
 272                          pci_id->function, status, bus_number, is_bridge));
 273
 274        return (AE_OK);
 275}
 276
 277/*******************************************************************************
 278 *
 279 * FUNCTION:    acpi_hw_delete_pci_list
 280 *
 281 * PARAMETERS:  list_head           - Device list created by
 282 *                                    acpi_hw_build_pci_list
 283 *
 284 * RETURN:      None
 285 *
 286 * DESCRIPTION: Free the entire PCI list.
 287 *
 288 ******************************************************************************/
 289
 290static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
 291{
 292        struct acpi_pci_device *next;
 293        struct acpi_pci_device *previous;
 294
 295        next = list_head;
 296        while (next) {
 297                previous = next;
 298                next = previous->next;
 299                ACPI_FREE(previous);
 300        }
 301}
 302
 303/*******************************************************************************
 304 *
 305 * FUNCTION:    acpi_hw_get_pci_device_info
 306 *
 307 * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
 308 *                                    modified by this function.
 309 *              pci_device          - Handle for the PCI device object
 310 *              bus_number          - Where a PCI bridge bus number is returned
 311 *              is_bridge           - Return value, indicates if this PCI
 312 *                                    device is a PCI bridge
 313 *
 314 * RETURN:      Status
 315 *
 316 * DESCRIPTION: Get the device info for a single PCI device object. Get the
 317 *              _ADR (contains PCI device and function numbers), and for PCI
 318 *              bridge devices, get the bus number from PCI configuration
 319 *              space.
 320 *
 321 ******************************************************************************/
 322
 323static acpi_status
 324acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
 325                            acpi_handle pci_device,
 326                            u16 *bus_number, u8 *is_bridge)
 327{
 328        acpi_status status;
 329        acpi_object_type object_type;
 330        u64 return_value;
 331        u64 pci_value;
 332
 333        /* We only care about objects of type Device */
 334
 335        status = acpi_get_type(pci_device, &object_type);
 336        if (ACPI_FAILURE(status)) {
 337                return (status);
 338        }
 339
 340        if (object_type != ACPI_TYPE_DEVICE) {
 341                return (AE_OK);
 342        }
 343
 344        /* We need an _ADR. Ignore device if not present */
 345
 346        status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
 347                                                 pci_device, &return_value);
 348        if (ACPI_FAILURE(status)) {
 349                return (AE_OK);
 350        }
 351
 352        /*
 353         * From _ADR, get the PCI Device and Function and
 354         * update the PCI ID.
 355         */
 356        pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
 357        pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
 358
 359        /*
 360         * If the previous device was a bridge, use the previous
 361         * device bus number
 362         */
 363        if (*is_bridge) {
 364                pci_id->bus = *bus_number;
 365        }
 366
 367        /*
 368         * Get the bus numbers from PCI Config space:
 369         *
 370         * First, get the PCI header_type
 371         */
 372        *is_bridge = FALSE;
 373        status = acpi_os_read_pci_configuration(pci_id,
 374                                                PCI_CFG_HEADER_TYPE_REG,
 375                                                &pci_value, 8);
 376        if (ACPI_FAILURE(status)) {
 377                return (status);
 378        }
 379
 380        /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
 381
 382        pci_value &= PCI_HEADER_TYPE_MASK;
 383
 384        if ((pci_value != PCI_TYPE_BRIDGE) &&
 385            (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
 386                return (AE_OK);
 387        }
 388
 389        /* Bridge: Get the Primary bus_number */
 390
 391        status = acpi_os_read_pci_configuration(pci_id,
 392                                                PCI_CFG_PRIMARY_BUS_NUMBER_REG,
 393                                                &pci_value, 8);
 394        if (ACPI_FAILURE(status)) {
 395                return (status);
 396        }
 397
 398        *is_bridge = TRUE;
 399        pci_id->bus = (u16)pci_value;
 400
 401        /* Bridge: Get the Secondary bus_number */
 402
 403        status = acpi_os_read_pci_configuration(pci_id,
 404                                                PCI_CFG_SECONDARY_BUS_NUMBER_REG,
 405                                                &pci_value, 8);
 406        if (ACPI_FAILURE(status)) {
 407                return (status);
 408        }
 409
 410        *bus_number = (u16)pci_value;
 411        return (AE_OK);
 412}
 413