18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/mutex.h> 148c2ecf20Sopenharmony_ci#include <linux/pm.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci#include <linux/pci.h> 178c2ecf20Sopenharmony_ci#include <linux/pci-acpi.h> 188c2ecf20Sopenharmony_ci#include <linux/dmar.h> 198c2ecf20Sopenharmony_ci#include <linux/acpi.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/dmi.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/apple.h> 238c2ecf20Sopenharmony_ci#include "internal.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define ACPI_PCI_ROOT_CLASS "pci_bridge" 268c2ecf20Sopenharmony_ci#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" 278c2ecf20Sopenharmony_cistatic int acpi_pci_root_add(struct acpi_device *device, 288c2ecf20Sopenharmony_ci const struct acpi_device_id *not_used); 298c2ecf20Sopenharmony_cistatic void acpi_pci_root_remove(struct acpi_device *device); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int acpi_pci_root_scan_dependent(struct acpi_device *adev) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci acpiphp_check_host_bridge(adev); 348c2ecf20Sopenharmony_ci return 0; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \ 388c2ecf20Sopenharmony_ci | OSC_PCI_ASPM_SUPPORT \ 398c2ecf20Sopenharmony_ci | OSC_PCI_CLOCK_PM_SUPPORT \ 408c2ecf20Sopenharmony_ci | OSC_PCI_MSI_SUPPORT) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const struct acpi_device_id root_device_ids[] = { 438c2ecf20Sopenharmony_ci {"PNP0A03", 0}, 448c2ecf20Sopenharmony_ci {"", 0}, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct acpi_scan_handler pci_root_handler = { 488c2ecf20Sopenharmony_ci .ids = root_device_ids, 498c2ecf20Sopenharmony_ci .attach = acpi_pci_root_add, 508c2ecf20Sopenharmony_ci .detach = acpi_pci_root_remove, 518c2ecf20Sopenharmony_ci .hotplug = { 528c2ecf20Sopenharmony_ci .enabled = true, 538c2ecf20Sopenharmony_ci .scan_dependent = acpi_pci_root_scan_dependent, 548c2ecf20Sopenharmony_ci }, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(osc_lock); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/** 608c2ecf20Sopenharmony_ci * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge 618c2ecf20Sopenharmony_ci * @handle: the ACPI CA node in question. 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * Note: we could make this API take a struct acpi_device * instead, but 648c2ecf20Sopenharmony_ci * for now, it's more convenient to operate on an acpi_handle. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ciint acpi_is_root_bridge(acpi_handle handle) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci struct acpi_device *device; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = acpi_bus_get_device(handle, &device); 728c2ecf20Sopenharmony_ci if (ret) 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci ret = acpi_match_device_ids(device, root_device_ids); 768c2ecf20Sopenharmony_ci if (ret) 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci else 798c2ecf20Sopenharmony_ci return 1; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_is_root_bridge); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic acpi_status 848c2ecf20Sopenharmony_ciget_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct resource *res = data; 878c2ecf20Sopenharmony_ci struct acpi_resource_address64 address; 888c2ecf20Sopenharmony_ci acpi_status status; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci status = acpi_resource_to_address64(resource, &address); 918c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 928c2ecf20Sopenharmony_ci return AE_OK; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if ((address.address.address_length > 0) && 958c2ecf20Sopenharmony_ci (address.resource_type == ACPI_BUS_NUMBER_RANGE)) { 968c2ecf20Sopenharmony_ci res->start = address.address.minimum; 978c2ecf20Sopenharmony_ci res->end = address.address.minimum + address.address.address_length - 1; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return AE_OK; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic acpi_status try_get_root_bridge_busnr(acpi_handle handle, 1048c2ecf20Sopenharmony_ci struct resource *res) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci acpi_status status; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci res->start = -1; 1098c2ecf20Sopenharmony_ci status = 1108c2ecf20Sopenharmony_ci acpi_walk_resources(handle, METHOD_NAME__CRS, 1118c2ecf20Sopenharmony_ci get_root_bridge_busnr_callback, res); 1128c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1138c2ecf20Sopenharmony_ci return status; 1148c2ecf20Sopenharmony_ci if (res->start == -1) 1158c2ecf20Sopenharmony_ci return AE_ERROR; 1168c2ecf20Sopenharmony_ci return AE_OK; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistruct pci_osc_bit_struct { 1208c2ecf20Sopenharmony_ci u32 bit; 1218c2ecf20Sopenharmony_ci char *desc; 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic struct pci_osc_bit_struct pci_osc_support_bit[] = { 1258c2ecf20Sopenharmony_ci { OSC_PCI_EXT_CONFIG_SUPPORT, "ExtendedConfig" }, 1268c2ecf20Sopenharmony_ci { OSC_PCI_ASPM_SUPPORT, "ASPM" }, 1278c2ecf20Sopenharmony_ci { OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" }, 1288c2ecf20Sopenharmony_ci { OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" }, 1298c2ecf20Sopenharmony_ci { OSC_PCI_MSI_SUPPORT, "MSI" }, 1308c2ecf20Sopenharmony_ci { OSC_PCI_EDR_SUPPORT, "EDR" }, 1318c2ecf20Sopenharmony_ci { OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" }, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic struct pci_osc_bit_struct pci_osc_control_bit[] = { 1358c2ecf20Sopenharmony_ci { OSC_PCI_EXPRESS_NATIVE_HP_CONTROL, "PCIeHotplug" }, 1368c2ecf20Sopenharmony_ci { OSC_PCI_SHPC_NATIVE_HP_CONTROL, "SHPCHotplug" }, 1378c2ecf20Sopenharmony_ci { OSC_PCI_EXPRESS_PME_CONTROL, "PME" }, 1388c2ecf20Sopenharmony_ci { OSC_PCI_EXPRESS_AER_CONTROL, "AER" }, 1398c2ecf20Sopenharmony_ci { OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" }, 1408c2ecf20Sopenharmony_ci { OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" }, 1418c2ecf20Sopenharmony_ci { OSC_PCI_EXPRESS_DPC_CONTROL, "DPC" }, 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word, 1458c2ecf20Sopenharmony_ci struct pci_osc_bit_struct *table, int size) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci char buf[80]; 1488c2ecf20Sopenharmony_ci int i, len = 0; 1498c2ecf20Sopenharmony_ci struct pci_osc_bit_struct *entry; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci buf[0] = '\0'; 1528c2ecf20Sopenharmony_ci for (i = 0, entry = table; i < size; i++, entry++) 1538c2ecf20Sopenharmony_ci if (word & entry->bit) 1548c2ecf20Sopenharmony_ci len += scnprintf(buf + len, sizeof(buf) - len, "%s%s", 1558c2ecf20Sopenharmony_ci len ? " " : "", entry->desc); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci dev_info(&root->device->dev, "_OSC: %s [%s]\n", msg, buf); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void decode_osc_support(struct acpi_pci_root *root, char *msg, u32 word) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci decode_osc_bits(root, msg, word, pci_osc_support_bit, 1638c2ecf20Sopenharmony_ci ARRAY_SIZE(pci_osc_support_bit)); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void decode_osc_control(struct acpi_pci_root *root, char *msg, u32 word) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci decode_osc_bits(root, msg, word, pci_osc_control_bit, 1698c2ecf20Sopenharmony_ci ARRAY_SIZE(pci_osc_control_bit)); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic acpi_status acpi_pci_run_osc(acpi_handle handle, 1758c2ecf20Sopenharmony_ci const u32 *capbuf, u32 *retval) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct acpi_osc_context context = { 1788c2ecf20Sopenharmony_ci .uuid_str = pci_osc_uuid_str, 1798c2ecf20Sopenharmony_ci .rev = 1, 1808c2ecf20Sopenharmony_ci .cap.length = 12, 1818c2ecf20Sopenharmony_ci .cap.pointer = (void *)capbuf, 1828c2ecf20Sopenharmony_ci }; 1838c2ecf20Sopenharmony_ci acpi_status status; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci status = acpi_run_osc(handle, &context); 1868c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 1878c2ecf20Sopenharmony_ci *retval = *((u32 *)(context.ret.pointer + 8)); 1888c2ecf20Sopenharmony_ci kfree(context.ret.pointer); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci return status; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, 1948c2ecf20Sopenharmony_ci u32 support, 1958c2ecf20Sopenharmony_ci u32 *control) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci acpi_status status; 1988c2ecf20Sopenharmony_ci u32 result, capbuf[3]; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci support &= OSC_PCI_SUPPORT_MASKS; 2018c2ecf20Sopenharmony_ci support |= root->osc_support_set; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; 2048c2ecf20Sopenharmony_ci capbuf[OSC_SUPPORT_DWORD] = support; 2058c2ecf20Sopenharmony_ci if (control) { 2068c2ecf20Sopenharmony_ci *control &= OSC_PCI_CONTROL_MASKS; 2078c2ecf20Sopenharmony_ci capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set; 2088c2ecf20Sopenharmony_ci } else { 2098c2ecf20Sopenharmony_ci /* Run _OSC query only with existing controls. */ 2108c2ecf20Sopenharmony_ci capbuf[OSC_CONTROL_DWORD] = root->osc_control_set; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci status = acpi_pci_run_osc(root->device->handle, capbuf, &result); 2148c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 2158c2ecf20Sopenharmony_ci root->osc_support_set = support; 2168c2ecf20Sopenharmony_ci if (control) 2178c2ecf20Sopenharmony_ci *control = result; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci return status; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci acpi_status status; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci mutex_lock(&osc_lock); 2278c2ecf20Sopenharmony_ci status = acpi_pci_query_osc(root, flags, NULL); 2288c2ecf20Sopenharmony_ci mutex_unlock(&osc_lock); 2298c2ecf20Sopenharmony_ci return status; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistruct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct acpi_pci_root *root; 2358c2ecf20Sopenharmony_ci struct acpi_device *device; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (acpi_bus_get_device(handle, &device) || 2388c2ecf20Sopenharmony_ci acpi_match_device_ids(device, root_device_ids)) 2398c2ecf20Sopenharmony_ci return NULL; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci root = acpi_driver_data(device); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return root; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_pci_find_root); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct acpi_handle_node { 2488c2ecf20Sopenharmony_ci struct list_head node; 2498c2ecf20Sopenharmony_ci acpi_handle handle; 2508c2ecf20Sopenharmony_ci}; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/** 2538c2ecf20Sopenharmony_ci * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev 2548c2ecf20Sopenharmony_ci * @handle: the handle in question 2558c2ecf20Sopenharmony_ci * 2568c2ecf20Sopenharmony_ci * Given an ACPI CA handle, the desired PCI device is located in the 2578c2ecf20Sopenharmony_ci * list of PCI devices. 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * If the device is found, its reference count is increased and this 2608c2ecf20Sopenharmony_ci * function returns a pointer to its data structure. The caller must 2618c2ecf20Sopenharmony_ci * decrement the reference count by calling pci_dev_put(). 2628c2ecf20Sopenharmony_ci * If no device is found, %NULL is returned. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_cistruct pci_dev *acpi_get_pci_dev(acpi_handle handle) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int dev, fn; 2678c2ecf20Sopenharmony_ci unsigned long long adr; 2688c2ecf20Sopenharmony_ci acpi_status status; 2698c2ecf20Sopenharmony_ci acpi_handle phandle; 2708c2ecf20Sopenharmony_ci struct pci_bus *pbus; 2718c2ecf20Sopenharmony_ci struct pci_dev *pdev = NULL; 2728c2ecf20Sopenharmony_ci struct acpi_handle_node *node, *tmp; 2738c2ecf20Sopenharmony_ci struct acpi_pci_root *root; 2748c2ecf20Sopenharmony_ci LIST_HEAD(device_list); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * Walk up the ACPI CA namespace until we reach a PCI root bridge. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci phandle = handle; 2808c2ecf20Sopenharmony_ci while (!acpi_is_root_bridge(phandle)) { 2818c2ecf20Sopenharmony_ci node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL); 2828c2ecf20Sopenharmony_ci if (!node) 2838c2ecf20Sopenharmony_ci goto out; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&node->node); 2868c2ecf20Sopenharmony_ci node->handle = phandle; 2878c2ecf20Sopenharmony_ci list_add(&node->node, &device_list); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci status = acpi_get_parent(phandle, &phandle); 2908c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 2918c2ecf20Sopenharmony_ci goto out; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci root = acpi_pci_find_root(phandle); 2958c2ecf20Sopenharmony_ci if (!root) 2968c2ecf20Sopenharmony_ci goto out; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci pbus = root->bus; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * Now, walk back down the PCI device tree until we return to our 3028c2ecf20Sopenharmony_ci * original handle. Assumes that everything between the PCI root 3038c2ecf20Sopenharmony_ci * bridge and the device we're looking for must be a P2P bridge. 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci list_for_each_entry(node, &device_list, node) { 3068c2ecf20Sopenharmony_ci acpi_handle hnd = node->handle; 3078c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr); 3088c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 3098c2ecf20Sopenharmony_ci goto out; 3108c2ecf20Sopenharmony_ci dev = (adr >> 16) & 0xffff; 3118c2ecf20Sopenharmony_ci fn = adr & 0xffff; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn)); 3148c2ecf20Sopenharmony_ci if (!pdev || hnd == handle) 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pbus = pdev->subordinate; 3188c2ecf20Sopenharmony_ci pci_dev_put(pdev); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * This function may be called for a non-PCI device that has a 3228c2ecf20Sopenharmony_ci * PCI parent (eg. a disk under a PCI SATA controller). In that 3238c2ecf20Sopenharmony_ci * case pdev->subordinate will be NULL for the parent. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci if (!pbus) { 3268c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Not a PCI-to-PCI bridge\n"); 3278c2ecf20Sopenharmony_ci pdev = NULL; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ciout: 3328c2ecf20Sopenharmony_ci list_for_each_entry_safe(node, tmp, &device_list, node) 3338c2ecf20Sopenharmony_ci kfree(node); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return pdev; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_get_pci_dev); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/** 3408c2ecf20Sopenharmony_ci * acpi_pci_osc_control_set - Request control of PCI root _OSC features. 3418c2ecf20Sopenharmony_ci * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex). 3428c2ecf20Sopenharmony_ci * @mask: Mask of _OSC bits to request control of, place to store control mask. 3438c2ecf20Sopenharmony_ci * @req: Mask of _OSC bits the control of is essential to the caller. 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * Run _OSC query for @mask and if that is successful, compare the returned 3468c2ecf20Sopenharmony_ci * mask of control bits with @req. If all of the @req bits are set in the 3478c2ecf20Sopenharmony_ci * returned mask, run _OSC request for it. 3488c2ecf20Sopenharmony_ci * 3498c2ecf20Sopenharmony_ci * The variable at the @mask address may be modified regardless of whether or 3508c2ecf20Sopenharmony_ci * not the function returns success. On success it will contain the mask of 3518c2ecf20Sopenharmony_ci * _OSC bits the BIOS has granted control of, but its contents are meaningless 3528c2ecf20Sopenharmony_ci * on failure. 3538c2ecf20Sopenharmony_ci **/ 3548c2ecf20Sopenharmony_ciacpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct acpi_pci_root *root; 3578c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 3588c2ecf20Sopenharmony_ci u32 ctrl, capbuf[3]; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (!mask) 3618c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ctrl = *mask & OSC_PCI_CONTROL_MASKS; 3648c2ecf20Sopenharmony_ci if ((ctrl & req) != req) 3658c2ecf20Sopenharmony_ci return AE_TYPE; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci root = acpi_pci_find_root(handle); 3688c2ecf20Sopenharmony_ci if (!root) 3698c2ecf20Sopenharmony_ci return AE_NOT_EXIST; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci mutex_lock(&osc_lock); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci *mask = ctrl | root->osc_control_set; 3748c2ecf20Sopenharmony_ci /* No need to evaluate _OSC if the control was already granted. */ 3758c2ecf20Sopenharmony_ci if ((root->osc_control_set & ctrl) == ctrl) 3768c2ecf20Sopenharmony_ci goto out; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Need to check the available controls bits before requesting them. */ 3798c2ecf20Sopenharmony_ci while (*mask) { 3808c2ecf20Sopenharmony_ci status = acpi_pci_query_osc(root, root->osc_support_set, mask); 3818c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 3828c2ecf20Sopenharmony_ci goto out; 3838c2ecf20Sopenharmony_ci if (ctrl == *mask) 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci decode_osc_control(root, "platform does not support", 3868c2ecf20Sopenharmony_ci ctrl & ~(*mask)); 3878c2ecf20Sopenharmony_ci ctrl = *mask; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if ((ctrl & req) != req) { 3918c2ecf20Sopenharmony_ci decode_osc_control(root, "not requesting control; platform does not support", 3928c2ecf20Sopenharmony_ci req & ~(ctrl)); 3938c2ecf20Sopenharmony_ci status = AE_SUPPORT; 3948c2ecf20Sopenharmony_ci goto out; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci capbuf[OSC_QUERY_DWORD] = 0; 3988c2ecf20Sopenharmony_ci capbuf[OSC_SUPPORT_DWORD] = root->osc_support_set; 3998c2ecf20Sopenharmony_ci capbuf[OSC_CONTROL_DWORD] = ctrl; 4008c2ecf20Sopenharmony_ci status = acpi_pci_run_osc(handle, capbuf, mask); 4018c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 4028c2ecf20Sopenharmony_ci root->osc_control_set = *mask; 4038c2ecf20Sopenharmony_ciout: 4048c2ecf20Sopenharmony_ci mutex_unlock(&osc_lock); 4058c2ecf20Sopenharmony_ci return status; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_pci_osc_control_set); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, 4108c2ecf20Sopenharmony_ci bool is_pcie) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci u32 support, control, requested; 4138c2ecf20Sopenharmony_ci acpi_status status; 4148c2ecf20Sopenharmony_ci struct acpi_device *device = root->device; 4158c2ecf20Sopenharmony_ci acpi_handle handle = device->handle; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * Apple always return failure on _OSC calls when _OSI("Darwin") has 4198c2ecf20Sopenharmony_ci * been called successfully. We know the feature set supported by the 4208c2ecf20Sopenharmony_ci * platform, so avoid calling _OSC at all 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_ci if (x86_apple_machine) { 4238c2ecf20Sopenharmony_ci root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL; 4248c2ecf20Sopenharmony_ci decode_osc_control(root, "OS assumes control of", 4258c2ecf20Sopenharmony_ci root->osc_control_set); 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* 4308c2ecf20Sopenharmony_ci * All supported architectures that use ACPI have support for 4318c2ecf20Sopenharmony_ci * PCI domains, so we indicate this in _OSC support capabilities. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; 4348c2ecf20Sopenharmony_ci support |= OSC_PCI_HPX_TYPE_3_SUPPORT; 4358c2ecf20Sopenharmony_ci if (pci_ext_cfg_avail()) 4368c2ecf20Sopenharmony_ci support |= OSC_PCI_EXT_CONFIG_SUPPORT; 4378c2ecf20Sopenharmony_ci if (pcie_aspm_support_enabled()) 4388c2ecf20Sopenharmony_ci support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT; 4398c2ecf20Sopenharmony_ci if (pci_msi_enabled()) 4408c2ecf20Sopenharmony_ci support |= OSC_PCI_MSI_SUPPORT; 4418c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCIE_EDR)) 4428c2ecf20Sopenharmony_ci support |= OSC_PCI_EDR_SUPPORT; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci decode_osc_support(root, "OS supports", support); 4458c2ecf20Sopenharmony_ci status = acpi_pci_osc_support(root, support); 4468c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 4478c2ecf20Sopenharmony_ci *no_aspm = 1; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* _OSC is optional for PCI host bridges */ 4508c2ecf20Sopenharmony_ci if ((status == AE_NOT_FOUND) && !is_pcie) 4518c2ecf20Sopenharmony_ci return; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci dev_info(&device->dev, "_OSC failed (%s)%s\n", 4548c2ecf20Sopenharmony_ci acpi_format_exception(status), 4558c2ecf20Sopenharmony_ci pcie_aspm_support_enabled() ? "; disabling ASPM" : ""); 4568c2ecf20Sopenharmony_ci return; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (pcie_ports_disabled) { 4608c2ecf20Sopenharmony_ci dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n"); 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) { 4658c2ecf20Sopenharmony_ci decode_osc_support(root, "not requesting OS control; OS requires", 4668c2ecf20Sopenharmony_ci ACPI_PCIE_REQ_SUPPORT); 4678c2ecf20Sopenharmony_ci return; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL 4718c2ecf20Sopenharmony_ci | OSC_PCI_EXPRESS_PME_CONTROL; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCIEASPM)) 4748c2ecf20Sopenharmony_ci control |= OSC_PCI_EXPRESS_LTR_CONTROL; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) 4778c2ecf20Sopenharmony_ci control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) 4808c2ecf20Sopenharmony_ci control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (pci_aer_available()) 4838c2ecf20Sopenharmony_ci control |= OSC_PCI_EXPRESS_AER_CONTROL; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* 4868c2ecf20Sopenharmony_ci * Per the Downstream Port Containment Related Enhancements ECN to 4878c2ecf20Sopenharmony_ci * the PCI Firmware Spec, r3.2, sec 4.5.1, table 4-5, 4888c2ecf20Sopenharmony_ci * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC 4898c2ecf20Sopenharmony_ci * and EDR. 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR)) 4928c2ecf20Sopenharmony_ci control |= OSC_PCI_EXPRESS_DPC_CONTROL; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci requested = control; 4958c2ecf20Sopenharmony_ci status = acpi_pci_osc_control_set(handle, &control, 4968c2ecf20Sopenharmony_ci OSC_PCI_EXPRESS_CAPABILITY_CONTROL); 4978c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 4988c2ecf20Sopenharmony_ci decode_osc_control(root, "OS now controls", control); 4998c2ecf20Sopenharmony_ci if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { 5008c2ecf20Sopenharmony_ci /* 5018c2ecf20Sopenharmony_ci * We have ASPM control, but the FADT indicates that 5028c2ecf20Sopenharmony_ci * it's unsupported. Leave existing configuration 5038c2ecf20Sopenharmony_ci * intact and prevent the OS from touching it. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci dev_info(&device->dev, "FADT indicates ASPM is unsupported, using BIOS configuration\n"); 5068c2ecf20Sopenharmony_ci *no_aspm = 1; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci } else { 5098c2ecf20Sopenharmony_ci decode_osc_control(root, "OS requested", requested); 5108c2ecf20Sopenharmony_ci decode_osc_control(root, "platform willing to grant", control); 5118c2ecf20Sopenharmony_ci dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n", 5128c2ecf20Sopenharmony_ci acpi_format_exception(status)); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* 5158c2ecf20Sopenharmony_ci * We want to disable ASPM here, but aspm_disabled 5168c2ecf20Sopenharmony_ci * needs to remain in its state from boot so that we 5178c2ecf20Sopenharmony_ci * properly handle PCIe 1.1 devices. So we set this 5188c2ecf20Sopenharmony_ci * flag here, to defer the action until after the ACPI 5198c2ecf20Sopenharmony_ci * root scan. 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci *no_aspm = 1; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int acpi_pci_root_add(struct acpi_device *device, 5268c2ecf20Sopenharmony_ci const struct acpi_device_id *not_used) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci unsigned long long segment, bus; 5298c2ecf20Sopenharmony_ci acpi_status status; 5308c2ecf20Sopenharmony_ci int result; 5318c2ecf20Sopenharmony_ci struct acpi_pci_root *root; 5328c2ecf20Sopenharmony_ci acpi_handle handle = device->handle; 5338c2ecf20Sopenharmony_ci int no_aspm = 0; 5348c2ecf20Sopenharmony_ci bool hotadd = system_state == SYSTEM_RUNNING; 5358c2ecf20Sopenharmony_ci bool is_pcie; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); 5388c2ecf20Sopenharmony_ci if (!root) 5398c2ecf20Sopenharmony_ci return -ENOMEM; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci segment = 0; 5428c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, 5438c2ecf20Sopenharmony_ci &segment); 5448c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 5458c2ecf20Sopenharmony_ci dev_err(&device->dev, "can't evaluate _SEG\n"); 5468c2ecf20Sopenharmony_ci result = -ENODEV; 5478c2ecf20Sopenharmony_ci goto end; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ 5518c2ecf20Sopenharmony_ci root->secondary.flags = IORESOURCE_BUS; 5528c2ecf20Sopenharmony_ci status = try_get_root_bridge_busnr(handle, &root->secondary); 5538c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * We need both the start and end of the downstream bus range 5568c2ecf20Sopenharmony_ci * to interpret _CBA (MMCONFIG base address), so it really is 5578c2ecf20Sopenharmony_ci * supposed to be in _CRS. If we don't find it there, all we 5588c2ecf20Sopenharmony_ci * can do is assume [_BBN-0xFF] or [0-0xFF]. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci root->secondary.end = 0xFF; 5618c2ecf20Sopenharmony_ci dev_warn(&device->dev, 5628c2ecf20Sopenharmony_ci FW_BUG "no secondary bus range in _CRS\n"); 5638c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, 5648c2ecf20Sopenharmony_ci NULL, &bus); 5658c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 5668c2ecf20Sopenharmony_ci root->secondary.start = bus; 5678c2ecf20Sopenharmony_ci else if (status == AE_NOT_FOUND) 5688c2ecf20Sopenharmony_ci root->secondary.start = 0; 5698c2ecf20Sopenharmony_ci else { 5708c2ecf20Sopenharmony_ci dev_err(&device->dev, "can't evaluate _BBN\n"); 5718c2ecf20Sopenharmony_ci result = -ENODEV; 5728c2ecf20Sopenharmony_ci goto end; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci root->device = device; 5778c2ecf20Sopenharmony_ci root->segment = segment & 0xFFFF; 5788c2ecf20Sopenharmony_ci strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); 5798c2ecf20Sopenharmony_ci strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); 5808c2ecf20Sopenharmony_ci device->driver_data = root; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (hotadd && dmar_device_add(handle)) { 5838c2ecf20Sopenharmony_ci result = -ENXIO; 5848c2ecf20Sopenharmony_ci goto end; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci pr_info(PREFIX "%s [%s] (domain %04x %pR)\n", 5888c2ecf20Sopenharmony_ci acpi_device_name(device), acpi_device_bid(device), 5898c2ecf20Sopenharmony_ci root->segment, &root->secondary); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci is_pcie = strcmp(acpi_device_hid(device), "PNP0A08") == 0; 5948c2ecf20Sopenharmony_ci negotiate_os_control(root, &no_aspm, is_pcie); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * TBD: Need PCI interface for enumeration/configuration of roots. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* 6018c2ecf20Sopenharmony_ci * Scan the Root Bridge 6028c2ecf20Sopenharmony_ci * -------------------- 6038c2ecf20Sopenharmony_ci * Must do this prior to any attempt to bind the root device, as the 6048c2ecf20Sopenharmony_ci * PCI namespace does not get created until this call is made (and 6058c2ecf20Sopenharmony_ci * thus the root bridge's pci_dev does not exist). 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci root->bus = pci_acpi_scan_root(root); 6088c2ecf20Sopenharmony_ci if (!root->bus) { 6098c2ecf20Sopenharmony_ci dev_err(&device->dev, 6108c2ecf20Sopenharmony_ci "Bus %04x:%02x not present in PCI namespace\n", 6118c2ecf20Sopenharmony_ci root->segment, (unsigned int)root->secondary.start); 6128c2ecf20Sopenharmony_ci device->driver_data = NULL; 6138c2ecf20Sopenharmony_ci result = -ENODEV; 6148c2ecf20Sopenharmony_ci goto remove_dmar; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (no_aspm) 6188c2ecf20Sopenharmony_ci pcie_no_aspm(); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci pci_acpi_add_bus_pm_notifier(device); 6218c2ecf20Sopenharmony_ci device_set_wakeup_capable(root->bus->bridge, device->wakeup.flags.valid); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (hotadd) { 6248c2ecf20Sopenharmony_ci pcibios_resource_survey_bus(root->bus); 6258c2ecf20Sopenharmony_ci pci_assign_unassigned_root_bus_resources(root->bus); 6268c2ecf20Sopenharmony_ci /* 6278c2ecf20Sopenharmony_ci * This is only called for the hotadd case. For the boot-time 6288c2ecf20Sopenharmony_ci * case, we need to wait until after PCI initialization in 6298c2ecf20Sopenharmony_ci * order to deal with IOAPICs mapped in on a PCI BAR. 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * This is currently x86-specific, because acpi_ioapic_add() 6328c2ecf20Sopenharmony_ci * is an empty function without CONFIG_ACPI_HOTPLUG_IOAPIC. 6338c2ecf20Sopenharmony_ci * And CONFIG_ACPI_HOTPLUG_IOAPIC depends on CONFIG_X86_IO_APIC 6348c2ecf20Sopenharmony_ci * (see drivers/acpi/Kconfig). 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci acpi_ioapic_add(root->device->handle); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 6408c2ecf20Sopenharmony_ci pci_bus_add_devices(root->bus); 6418c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 6428c2ecf20Sopenharmony_ci return 1; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ciremove_dmar: 6458c2ecf20Sopenharmony_ci if (hotadd) 6468c2ecf20Sopenharmony_ci dmar_device_remove(handle); 6478c2ecf20Sopenharmony_ciend: 6488c2ecf20Sopenharmony_ci kfree(root); 6498c2ecf20Sopenharmony_ci return result; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void acpi_pci_root_remove(struct acpi_device *device) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct acpi_pci_root *root = acpi_driver_data(device); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci pci_stop_root_bus(root->bus); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci pci_ioapic_remove(root); 6618c2ecf20Sopenharmony_ci device_set_wakeup_capable(root->bus->bridge, false); 6628c2ecf20Sopenharmony_ci pci_acpi_remove_bus_pm_notifier(device); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci pci_remove_root_bus(root->bus); 6658c2ecf20Sopenharmony_ci WARN_ON(acpi_ioapic_remove(root)); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci dmar_device_remove(device->handle); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci kfree(root); 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci/* 6758c2ecf20Sopenharmony_ci * Following code to support acpi_pci_root_create() is copied from 6768c2ecf20Sopenharmony_ci * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64 6778c2ecf20Sopenharmony_ci * and ARM64. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_cistatic void acpi_pci_root_validate_resources(struct device *dev, 6808c2ecf20Sopenharmony_ci struct list_head *resources, 6818c2ecf20Sopenharmony_ci unsigned long type) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci LIST_HEAD(list); 6848c2ecf20Sopenharmony_ci struct resource *res1, *res2, *root = NULL; 6858c2ecf20Sopenharmony_ci struct resource_entry *tmp, *entry, *entry2; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); 6888c2ecf20Sopenharmony_ci root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci list_splice_init(resources, &list); 6918c2ecf20Sopenharmony_ci resource_list_for_each_entry_safe(entry, tmp, &list) { 6928c2ecf20Sopenharmony_ci bool free = false; 6938c2ecf20Sopenharmony_ci resource_size_t end; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci res1 = entry->res; 6968c2ecf20Sopenharmony_ci if (!(res1->flags & type)) 6978c2ecf20Sopenharmony_ci goto next; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Exclude non-addressable range or non-addressable portion */ 7008c2ecf20Sopenharmony_ci end = min(res1->end, root->end); 7018c2ecf20Sopenharmony_ci if (end <= res1->start) { 7028c2ecf20Sopenharmony_ci dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", 7038c2ecf20Sopenharmony_ci res1); 7048c2ecf20Sopenharmony_ci free = true; 7058c2ecf20Sopenharmony_ci goto next; 7068c2ecf20Sopenharmony_ci } else if (res1->end != end) { 7078c2ecf20Sopenharmony_ci dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", 7088c2ecf20Sopenharmony_ci res1, (unsigned long long)end + 1, 7098c2ecf20Sopenharmony_ci (unsigned long long)res1->end); 7108c2ecf20Sopenharmony_ci res1->end = end; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci resource_list_for_each_entry(entry2, resources) { 7148c2ecf20Sopenharmony_ci res2 = entry2->res; 7158c2ecf20Sopenharmony_ci if (!(res2->flags & type)) 7168c2ecf20Sopenharmony_ci continue; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * I don't like throwing away windows because then 7208c2ecf20Sopenharmony_ci * our resources no longer match the ACPI _CRS, but 7218c2ecf20Sopenharmony_ci * the kernel resource tree doesn't allow overlaps. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_ci if (resource_overlaps(res1, res2)) { 7248c2ecf20Sopenharmony_ci res2->start = min(res1->start, res2->start); 7258c2ecf20Sopenharmony_ci res2->end = max(res1->end, res2->end); 7268c2ecf20Sopenharmony_ci dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", 7278c2ecf20Sopenharmony_ci res2, res1); 7288c2ecf20Sopenharmony_ci free = true; 7298c2ecf20Sopenharmony_ci goto next; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cinext: 7348c2ecf20Sopenharmony_ci resource_list_del(entry); 7358c2ecf20Sopenharmony_ci if (free) 7368c2ecf20Sopenharmony_ci resource_list_free_entry(entry); 7378c2ecf20Sopenharmony_ci else 7388c2ecf20Sopenharmony_ci resource_list_add_tail(entry, resources); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic void acpi_pci_root_remap_iospace(struct fwnode_handle *fwnode, 7438c2ecf20Sopenharmony_ci struct resource_entry *entry) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci#ifdef PCI_IOBASE 7468c2ecf20Sopenharmony_ci struct resource *res = entry->res; 7478c2ecf20Sopenharmony_ci resource_size_t cpu_addr = res->start; 7488c2ecf20Sopenharmony_ci resource_size_t pci_addr = cpu_addr - entry->offset; 7498c2ecf20Sopenharmony_ci resource_size_t length = resource_size(res); 7508c2ecf20Sopenharmony_ci unsigned long port; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (pci_register_io_range(fwnode, cpu_addr, length)) 7538c2ecf20Sopenharmony_ci goto err; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci port = pci_address_to_pio(cpu_addr); 7568c2ecf20Sopenharmony_ci if (port == (unsigned long)-1) 7578c2ecf20Sopenharmony_ci goto err; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci res->start = port; 7608c2ecf20Sopenharmony_ci res->end = port + length - 1; 7618c2ecf20Sopenharmony_ci entry->offset = port - pci_addr; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (pci_remap_iospace(res, cpu_addr) < 0) 7648c2ecf20Sopenharmony_ci goto err; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res); 7678c2ecf20Sopenharmony_ci return; 7688c2ecf20Sopenharmony_cierr: 7698c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_DISABLED; 7708c2ecf20Sopenharmony_ci#endif 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ciint acpi_pci_probe_root_resources(struct acpi_pci_root_info *info) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci int ret; 7768c2ecf20Sopenharmony_ci struct list_head *list = &info->resources; 7778c2ecf20Sopenharmony_ci struct acpi_device *device = info->bridge; 7788c2ecf20Sopenharmony_ci struct resource_entry *entry, *tmp; 7798c2ecf20Sopenharmony_ci unsigned long flags; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT; 7828c2ecf20Sopenharmony_ci ret = acpi_dev_get_resources(device, list, 7838c2ecf20Sopenharmony_ci acpi_dev_filter_resource_type_cb, 7848c2ecf20Sopenharmony_ci (void *)flags); 7858c2ecf20Sopenharmony_ci if (ret < 0) 7868c2ecf20Sopenharmony_ci dev_warn(&device->dev, 7878c2ecf20Sopenharmony_ci "failed to parse _CRS method, error code %d\n", ret); 7888c2ecf20Sopenharmony_ci else if (ret == 0) 7898c2ecf20Sopenharmony_ci dev_dbg(&device->dev, 7908c2ecf20Sopenharmony_ci "no IO and memory resources present in _CRS\n"); 7918c2ecf20Sopenharmony_ci else { 7928c2ecf20Sopenharmony_ci resource_list_for_each_entry_safe(entry, tmp, list) { 7938c2ecf20Sopenharmony_ci if (entry->res->flags & IORESOURCE_IO) 7948c2ecf20Sopenharmony_ci acpi_pci_root_remap_iospace(&device->fwnode, 7958c2ecf20Sopenharmony_ci entry); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (entry->res->flags & IORESOURCE_DISABLED) 7988c2ecf20Sopenharmony_ci resource_list_destroy_entry(entry); 7998c2ecf20Sopenharmony_ci else 8008c2ecf20Sopenharmony_ci entry->res->name = info->name; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci acpi_pci_root_validate_resources(&device->dev, list, 8038c2ecf20Sopenharmony_ci IORESOURCE_MEM); 8048c2ecf20Sopenharmony_ci acpi_pci_root_validate_resources(&device->dev, list, 8058c2ecf20Sopenharmony_ci IORESOURCE_IO); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci return ret; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic void pci_acpi_root_add_resources(struct acpi_pci_root_info *info) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct resource_entry *entry, *tmp; 8148c2ecf20Sopenharmony_ci struct resource *res, *conflict, *root = NULL; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci resource_list_for_each_entry_safe(entry, tmp, &info->resources) { 8178c2ecf20Sopenharmony_ci res = entry->res; 8188c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_MEM) 8198c2ecf20Sopenharmony_ci root = &iomem_resource; 8208c2ecf20Sopenharmony_ci else if (res->flags & IORESOURCE_IO) 8218c2ecf20Sopenharmony_ci root = &ioport_resource; 8228c2ecf20Sopenharmony_ci else 8238c2ecf20Sopenharmony_ci continue; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* 8268c2ecf20Sopenharmony_ci * Some legacy x86 host bridge drivers use iomem_resource and 8278c2ecf20Sopenharmony_ci * ioport_resource as default resource pool, skip it. 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_ci if (res == root) 8308c2ecf20Sopenharmony_ci continue; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci conflict = insert_resource_conflict(root, res); 8338c2ecf20Sopenharmony_ci if (conflict) { 8348c2ecf20Sopenharmony_ci dev_info(&info->bridge->dev, 8358c2ecf20Sopenharmony_ci "ignoring host bridge window %pR (conflicts with %s %pR)\n", 8368c2ecf20Sopenharmony_ci res, conflict->name, conflict); 8378c2ecf20Sopenharmony_ci resource_list_destroy_entry(entry); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic void __acpi_pci_root_release_info(struct acpi_pci_root_info *info) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct resource *res; 8458c2ecf20Sopenharmony_ci struct resource_entry *entry, *tmp; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (!info) 8488c2ecf20Sopenharmony_ci return; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci resource_list_for_each_entry_safe(entry, tmp, &info->resources) { 8518c2ecf20Sopenharmony_ci res = entry->res; 8528c2ecf20Sopenharmony_ci if (res->parent && 8538c2ecf20Sopenharmony_ci (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) 8548c2ecf20Sopenharmony_ci release_resource(res); 8558c2ecf20Sopenharmony_ci resource_list_destroy_entry(entry); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci info->ops->release_info(info); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void acpi_pci_root_release_info(struct pci_host_bridge *bridge) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct resource *res; 8648c2ecf20Sopenharmony_ci struct resource_entry *entry; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci resource_list_for_each_entry(entry, &bridge->windows) { 8678c2ecf20Sopenharmony_ci res = entry->res; 8688c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_IO) 8698c2ecf20Sopenharmony_ci pci_unmap_iospace(res); 8708c2ecf20Sopenharmony_ci if (res->parent && 8718c2ecf20Sopenharmony_ci (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) 8728c2ecf20Sopenharmony_ci release_resource(res); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci __acpi_pci_root_release_info(bridge->release_data); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistruct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, 8788c2ecf20Sopenharmony_ci struct acpi_pci_root_ops *ops, 8798c2ecf20Sopenharmony_ci struct acpi_pci_root_info *info, 8808c2ecf20Sopenharmony_ci void *sysdata) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci int ret, busnum = root->secondary.start; 8838c2ecf20Sopenharmony_ci struct acpi_device *device = root->device; 8848c2ecf20Sopenharmony_ci int node = acpi_get_node(device->handle); 8858c2ecf20Sopenharmony_ci struct pci_bus *bus; 8868c2ecf20Sopenharmony_ci struct pci_host_bridge *host_bridge; 8878c2ecf20Sopenharmony_ci union acpi_object *obj; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci info->root = root; 8908c2ecf20Sopenharmony_ci info->bridge = device; 8918c2ecf20Sopenharmony_ci info->ops = ops; 8928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&info->resources); 8938c2ecf20Sopenharmony_ci snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x", 8948c2ecf20Sopenharmony_ci root->segment, busnum); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (ops->init_info && ops->init_info(info)) 8978c2ecf20Sopenharmony_ci goto out_release_info; 8988c2ecf20Sopenharmony_ci if (ops->prepare_resources) 8998c2ecf20Sopenharmony_ci ret = ops->prepare_resources(info); 9008c2ecf20Sopenharmony_ci else 9018c2ecf20Sopenharmony_ci ret = acpi_pci_probe_root_resources(info); 9028c2ecf20Sopenharmony_ci if (ret < 0) 9038c2ecf20Sopenharmony_ci goto out_release_info; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci pci_acpi_root_add_resources(info); 9068c2ecf20Sopenharmony_ci pci_add_resource(&info->resources, &root->secondary); 9078c2ecf20Sopenharmony_ci bus = pci_create_root_bus(NULL, busnum, ops->pci_ops, 9088c2ecf20Sopenharmony_ci sysdata, &info->resources); 9098c2ecf20Sopenharmony_ci if (!bus) 9108c2ecf20Sopenharmony_ci goto out_release_info; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci host_bridge = to_pci_host_bridge(bus->bridge); 9138c2ecf20Sopenharmony_ci if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) 9148c2ecf20Sopenharmony_ci host_bridge->native_pcie_hotplug = 0; 9158c2ecf20Sopenharmony_ci if (!(root->osc_control_set & OSC_PCI_SHPC_NATIVE_HP_CONTROL)) 9168c2ecf20Sopenharmony_ci host_bridge->native_shpc_hotplug = 0; 9178c2ecf20Sopenharmony_ci if (!(root->osc_control_set & OSC_PCI_EXPRESS_AER_CONTROL)) 9188c2ecf20Sopenharmony_ci host_bridge->native_aer = 0; 9198c2ecf20Sopenharmony_ci if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL)) 9208c2ecf20Sopenharmony_ci host_bridge->native_pme = 0; 9218c2ecf20Sopenharmony_ci if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL)) 9228c2ecf20Sopenharmony_ci host_bridge->native_ltr = 0; 9238c2ecf20Sopenharmony_ci if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL)) 9248c2ecf20Sopenharmony_ci host_bridge->native_dpc = 0; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* 9278c2ecf20Sopenharmony_ci * Evaluate the "PCI Boot Configuration" _DSM Function. If it 9288c2ecf20Sopenharmony_ci * exists and returns 0, we must preserve any PCI resource 9298c2ecf20Sopenharmony_ci * assignments made by firmware for this host bridge. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_ci obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, 9328c2ecf20Sopenharmony_ci DSM_PCI_PRESERVE_BOOT_CONFIG, NULL); 9338c2ecf20Sopenharmony_ci if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0) 9348c2ecf20Sopenharmony_ci host_bridge->preserve_config = 1; 9358c2ecf20Sopenharmony_ci ACPI_FREE(obj); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci pci_scan_child_bus(bus); 9388c2ecf20Sopenharmony_ci pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info, 9398c2ecf20Sopenharmony_ci info); 9408c2ecf20Sopenharmony_ci if (node != NUMA_NO_NODE) 9418c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node); 9428c2ecf20Sopenharmony_ci return bus; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ciout_release_info: 9458c2ecf20Sopenharmony_ci __acpi_pci_root_release_info(info); 9468c2ecf20Sopenharmony_ci return NULL; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_civoid __init acpi_pci_root_init(void) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci if (acpi_pci_disabled) 9528c2ecf20Sopenharmony_ci return; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci pci_acpi_crs_quirks(); 9558c2ecf20Sopenharmony_ci acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root"); 9568c2ecf20Sopenharmony_ci} 957