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