root/drivers/acpi/acpica/hwpci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpi_hw_derive_pci_id
  2. acpi_hw_build_pci_list
  3. acpi_hw_process_pci_list
  4. acpi_hw_delete_pci_list
  5. acpi_hw_get_pci_device_info

   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
  12 ACPI_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
  22 typedef struct acpi_pci_device {
  23         acpi_handle device;
  24         struct acpi_pci_device *next;
  25 
  26 } acpi_pci_device;
  27 
  28 /* Local prototypes */
  29 
  30 static acpi_status
  31 acpi_hw_build_pci_list(acpi_handle root_pci_device,
  32                        acpi_handle pci_region,
  33                        struct acpi_pci_device **return_list_head);
  34 
  35 static acpi_status
  36 acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
  37                          struct acpi_pci_device *list_head);
  38 
  39 static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
  40 
  41 static acpi_status
  42 acpi_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 
  85 acpi_status
  86 acpi_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 
 135 static acpi_status
 136 acpi_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 
 204 static acpi_status
 205 acpi_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 
 262 static 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 
 295 static acpi_status
 296 acpi_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 }

/* [<][>][^][v][top][bottom][index][help] */