LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - hwpci.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 68 81 84.0 %
Date: 2022-04-01 14:58:12 Functions: 5 5 100.0 %
Branches: 17 32 53.1 %

           Branch data     Line data    Source code
       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                 :          6 : acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
      87                 :            :                       acpi_handle root_pci_device, acpi_handle pci_region)
      88                 :            : {
      89                 :          6 :         acpi_status status;
      90                 :          6 :         struct acpi_pci_device *list_head;
      91                 :            : 
      92                 :          6 :         ACPI_FUNCTION_TRACE(hw_derive_pci_id);
      93                 :            : 
      94         [ +  - ]:          6 :         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                 :          6 :         status =
     101                 :          6 :             acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
     102         [ +  - ]:          6 :         if (ACPI_SUCCESS(status)) {
     103                 :            : 
     104                 :            :                 /* Walk the list, updating the PCI device/function/bus numbers */
     105                 :            : 
     106                 :          6 :                 status = acpi_hw_process_pci_list(pci_id, list_head);
     107                 :            : 
     108                 :            :                 /* Delete the list */
     109                 :            : 
     110                 :          6 :                 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                 :          6 : 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                 :          6 :         acpi_handle current_device;
     141                 :          6 :         acpi_handle parent_device;
     142                 :          6 :         acpi_status status;
     143                 :          6 :         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                 :          6 :         *return_list_head = NULL;
     151                 :          6 :         current_device = pci_region;
     152                 :         18 :         while (1) {
     153                 :         12 :                 status = acpi_get_parent(current_device, &parent_device);
     154         [ -  + ]:         12 :                 if (ACPI_FAILURE(status)) {
     155                 :            : 
     156                 :            :                         /* Must delete the list before exit */
     157                 :            : 
     158                 :          0 :                         acpi_hw_delete_pci_list(*return_list_head);
     159                 :          0 :                         return (status);
     160                 :            :                 }
     161                 :            : 
     162                 :            :                 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
     163                 :            : 
     164         [ +  + ]:         12 :                 if (parent_device == root_pci_device) {
     165                 :            :                         return (AE_OK);
     166                 :            :                 }
     167                 :            : 
     168                 :          6 :                 list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
     169         [ -  + ]:          6 :                 if (!list_element) {
     170                 :            : 
     171                 :            :                         /* Must delete the list before exit */
     172                 :            : 
     173                 :          0 :                         acpi_hw_delete_pci_list(*return_list_head);
     174                 :          0 :                         return (AE_NO_MEMORY);
     175                 :            :                 }
     176                 :            : 
     177                 :            :                 /* Put new element at the head of the list */
     178                 :            : 
     179                 :          6 :                 list_element->next = *return_list_head;
     180                 :          6 :                 list_element->device = parent_device;
     181                 :          6 :                 *return_list_head = list_element;
     182                 :            : 
     183                 :          6 :                 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                 :          6 : acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
     206                 :            :                          struct acpi_pci_device *list_head)
     207                 :            : {
     208                 :          6 :         acpi_status status = AE_OK;
     209                 :          6 :         struct acpi_pci_device *info;
     210                 :          6 :         u16 bus_number;
     211                 :          6 :         u8 is_bridge = TRUE;
     212                 :            : 
     213                 :          6 :         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                 :          6 :                           pci_id->function));
     219                 :            : 
     220                 :          6 :         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                 :          6 :         info = list_head;
     230         [ +  + ]:         12 :         while (info) {
     231                 :          6 :                 status = acpi_hw_get_pci_device_info(pci_id, info->device,
     232                 :            :                                                      &bus_number, &is_bridge);
     233         [ -  + ]:          6 :                 if (ACPI_FAILURE(status)) {
     234                 :          0 :                         return (status);
     235                 :            :                 }
     236                 :            : 
     237                 :          6 :                 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                 :          6 : static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
     263                 :            : {
     264                 :          6 :         struct acpi_pci_device *next;
     265                 :          6 :         struct acpi_pci_device *previous;
     266                 :            : 
     267                 :          6 :         next = list_head;
     268         [ +  + ]:         12 :         while (next) {
     269                 :          6 :                 previous = next;
     270                 :          6 :                 next = previous->next;
     271                 :          6 :                 ACPI_FREE(previous);
     272                 :            :         }
     273                 :          6 : }
     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                 :          6 : 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                 :          6 :         acpi_status status;
     301                 :          6 :         acpi_object_type object_type;
     302                 :          6 :         u64 return_value;
     303                 :          6 :         u64 pci_value;
     304                 :            : 
     305                 :            :         /* We only care about objects of type Device */
     306                 :            : 
     307                 :          6 :         status = acpi_get_type(pci_device, &object_type);
     308         [ +  - ]:          6 :         if (ACPI_FAILURE(status)) {
     309                 :            :                 return (status);
     310                 :            :         }
     311                 :            : 
     312         [ +  - ]:          6 :         if (object_type != ACPI_TYPE_DEVICE) {
     313                 :            :                 return (AE_OK);
     314                 :            :         }
     315                 :            : 
     316                 :            :         /* We need an _ADR. Ignore device if not present */
     317                 :            : 
     318                 :          6 :         status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
     319                 :            :                                                  pci_device, &return_value);
     320         [ +  - ]:          6 :         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                 :          6 :         pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
     329                 :          6 :         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         [ +  - ]:          6 :         if (*is_bridge) {
     336                 :          6 :                 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                 :          6 :         *is_bridge = FALSE;
     345                 :          6 :         status = acpi_os_read_pci_configuration(pci_id,
     346                 :            :                                                 PCI_CFG_HEADER_TYPE_REG,
     347                 :            :                                                 &pci_value, 8);
     348         [ +  - ]:          6 :         if (ACPI_FAILURE(status)) {
     349                 :            :                 return (status);
     350                 :            :         }
     351                 :            : 
     352                 :            :         /* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
     353                 :            : 
     354                 :          6 :         pci_value &= PCI_HEADER_TYPE_MASK;
     355                 :            : 
     356         [ -  + ]:          6 :         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                 :          0 :         status = acpi_os_read_pci_configuration(pci_id,
     364                 :            :                                                 PCI_CFG_PRIMARY_BUS_NUMBER_REG,
     365                 :            :                                                 &pci_value, 8);
     366         [ #  # ]:          0 :         if (ACPI_FAILURE(status)) {
     367                 :            :                 return (status);
     368                 :            :         }
     369                 :            : 
     370                 :          0 :         *is_bridge = TRUE;
     371                 :          0 :         pci_id->bus = (u16)pci_value;
     372                 :            : 
     373                 :            :         /* Bridge: Get the Secondary bus_number */
     374                 :            : 
     375                 :          0 :         status = acpi_os_read_pci_configuration(pci_id,
     376                 :            :                                                 PCI_CFG_SECONDARY_BUS_NUMBER_REG,
     377                 :            :                                                 &pci_value, 8);
     378         [ #  # ]:          0 :         if (ACPI_FAILURE(status)) {
     379                 :            :                 return (status);
     380                 :            :         }
     381                 :            : 
     382                 :          0 :         *bus_number = (u16)pci_value;
     383                 :          0 :         return (AE_OK);
     384                 :            : }

Generated by: LCOV version 1.14