1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $) 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 61da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 9ccde83e3SHanjun Guo #define pr_fmt(fmt) "ACPI: " fmt 10ccde83e3SHanjun Guo 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/types.h> 15d0020f65STaku Izumi #include <linux/mutex.h> 161da177e4SLinus Torvalds #include <linux/pm.h> 17b67ea761SRafael J. Wysocki #include <linux/pm_runtime.h> 181da177e4SLinus Torvalds #include <linux/pci.h> 19990a7ac5SAndrew Patterson #include <linux/pci-acpi.h> 20864b94adSJiang Liu #include <linux/dmar.h> 211da177e4SLinus Torvalds #include <linux/acpi.h> 225a0e3ad6STejun Heo #include <linux/slab.h> 237bc5a2baSMatthew Garrett #include <linux/dmi.h> 24630b3affSLukas Wunner #include <linux/platform_data/x86/apple.h> 25ace8238bSRafael J. Wysocki #include "internal.h" 26ace8238bSRafael J. Wysocki 271da177e4SLinus Torvalds #define ACPI_PCI_ROOT_CLASS "pci_bridge" 281da177e4SLinus Torvalds #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" 2900c43b96SRafael J. Wysocki static int acpi_pci_root_add(struct acpi_device *device, 3000c43b96SRafael J. Wysocki const struct acpi_device_id *not_used); 3100c43b96SRafael J. Wysocki static void acpi_pci_root_remove(struct acpi_device *device); 321da177e4SLinus Torvalds 333338db00SRafael J. Wysocki static int acpi_pci_root_scan_dependent(struct acpi_device *adev) 343338db00SRafael J. Wysocki { 351f7c164bSRafael J. Wysocki acpiphp_check_host_bridge(adev); 363338db00SRafael J. Wysocki return 0; 373338db00SRafael J. Wysocki } 383338db00SRafael J. Wysocki 397dab9ef4SBjorn Helgaas #define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \ 407dab9ef4SBjorn Helgaas | OSC_PCI_ASPM_SUPPORT \ 417dab9ef4SBjorn Helgaas | OSC_PCI_CLOCK_PM_SUPPORT \ 427dab9ef4SBjorn Helgaas | OSC_PCI_MSI_SUPPORT) 43415e12b2SRafael J. Wysocki 44c97adf9eSMárton Németh static const struct acpi_device_id root_device_ids[] = { 451ba90e3aSThomas Renninger {"PNP0A03", 0}, 461ba90e3aSThomas Renninger {"", 0}, 471ba90e3aSThomas Renninger }; 481ba90e3aSThomas Renninger 4900c43b96SRafael J. Wysocki static struct acpi_scan_handler pci_root_handler = { 501ba90e3aSThomas Renninger .ids = root_device_ids, 5100c43b96SRafael J. Wysocki .attach = acpi_pci_root_add, 5200c43b96SRafael J. Wysocki .detach = acpi_pci_root_remove, 53ca499fc8SToshi Kani .hotplug = { 543338db00SRafael J. Wysocki .enabled = true, 553338db00SRafael J. Wysocki .scan_dependent = acpi_pci_root_scan_dependent, 56ca499fc8SToshi Kani }, 571da177e4SLinus Torvalds }; 581da177e4SLinus Torvalds 5927558203SAlexander Chiang /** 6027558203SAlexander Chiang * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge 618e8883ceSTian Tao * @handle: the ACPI CA node in question. 6227558203SAlexander Chiang * 6327558203SAlexander Chiang * Note: we could make this API take a struct acpi_device * instead, but 6427558203SAlexander Chiang * for now, it's more convenient to operate on an acpi_handle. 6527558203SAlexander Chiang */ 6627558203SAlexander Chiang int acpi_is_root_bridge(acpi_handle handle) 6727558203SAlexander Chiang { 6899ece713SRafael J. Wysocki struct acpi_device *device = acpi_fetch_acpi_dev(handle); 6927558203SAlexander Chiang int ret; 7027558203SAlexander Chiang 7199ece713SRafael J. Wysocki if (!device) 7227558203SAlexander Chiang return 0; 7327558203SAlexander Chiang 7427558203SAlexander Chiang ret = acpi_match_device_ids(device, root_device_ids); 7527558203SAlexander Chiang if (ret) 7627558203SAlexander Chiang return 0; 7727558203SAlexander Chiang else 7827558203SAlexander Chiang return 1; 7927558203SAlexander Chiang } 8027558203SAlexander Chiang EXPORT_SYMBOL_GPL(acpi_is_root_bridge); 8127558203SAlexander Chiang 821da177e4SLinus Torvalds static acpi_status 831da177e4SLinus Torvalds get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) 841da177e4SLinus Torvalds { 856ad95513SBjorn Helgaas struct resource *res = data; 861da177e4SLinus Torvalds struct acpi_resource_address64 address; 87f6c1c8ffSBjorn Helgaas acpi_status status; 881da177e4SLinus Torvalds 89f6c1c8ffSBjorn Helgaas status = acpi_resource_to_address64(resource, &address); 90f6c1c8ffSBjorn Helgaas if (ACPI_FAILURE(status)) 911da177e4SLinus Torvalds return AE_OK; 921da177e4SLinus Torvalds 93a45de93eSLv Zheng if ((address.address.address_length > 0) && 946ad95513SBjorn Helgaas (address.resource_type == ACPI_BUS_NUMBER_RANGE)) { 95a45de93eSLv Zheng res->start = address.address.minimum; 96a45de93eSLv Zheng res->end = address.address.minimum + address.address.address_length - 1; 976ad95513SBjorn Helgaas } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds return AE_OK; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 102f5eebbe1SBjorn Helgaas static acpi_status try_get_root_bridge_busnr(acpi_handle handle, 1036ad95513SBjorn Helgaas struct resource *res) 1041da177e4SLinus Torvalds { 1051da177e4SLinus Torvalds acpi_status status; 1061da177e4SLinus Torvalds 1076ad95513SBjorn Helgaas res->start = -1; 1084be44fcdSLen Brown status = 1094be44fcdSLen Brown acpi_walk_resources(handle, METHOD_NAME__CRS, 1106ad95513SBjorn Helgaas get_root_bridge_busnr_callback, res); 1111da177e4SLinus Torvalds if (ACPI_FAILURE(status)) 1121da177e4SLinus Torvalds return status; 1136ad95513SBjorn Helgaas if (res->start == -1) 1141da177e4SLinus Torvalds return AE_ERROR; 1151da177e4SLinus Torvalds return AE_OK; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 118955f14b4SBjorn Helgaas struct pci_osc_bit_struct { 119955f14b4SBjorn Helgaas u32 bit; 120955f14b4SBjorn Helgaas char *desc; 121955f14b4SBjorn Helgaas }; 122955f14b4SBjorn Helgaas 123955f14b4SBjorn Helgaas static struct pci_osc_bit_struct pci_osc_support_bit[] = { 124955f14b4SBjorn Helgaas { OSC_PCI_EXT_CONFIG_SUPPORT, "ExtendedConfig" }, 125955f14b4SBjorn Helgaas { OSC_PCI_ASPM_SUPPORT, "ASPM" }, 126955f14b4SBjorn Helgaas { OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" }, 127955f14b4SBjorn Helgaas { OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" }, 128955f14b4SBjorn Helgaas { OSC_PCI_MSI_SUPPORT, "MSI" }, 129ac1c8e35SKuppuswamy Sathyanarayanan { OSC_PCI_EDR_SUPPORT, "EDR" }, 130ba11edc6SAlexandru Gagniuc { OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" }, 131955f14b4SBjorn Helgaas }; 132955f14b4SBjorn Helgaas 133955f14b4SBjorn Helgaas static struct pci_osc_bit_struct pci_osc_control_bit[] = { 134955f14b4SBjorn Helgaas { OSC_PCI_EXPRESS_NATIVE_HP_CONTROL, "PCIeHotplug" }, 135955f14b4SBjorn Helgaas { OSC_PCI_SHPC_NATIVE_HP_CONTROL, "SHPCHotplug" }, 136955f14b4SBjorn Helgaas { OSC_PCI_EXPRESS_PME_CONTROL, "PME" }, 137955f14b4SBjorn Helgaas { OSC_PCI_EXPRESS_AER_CONTROL, "AER" }, 138955f14b4SBjorn Helgaas { OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" }, 139af8bb9f8SBjorn Helgaas { OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" }, 140ac1c8e35SKuppuswamy Sathyanarayanan { OSC_PCI_EXPRESS_DPC_CONTROL, "DPC" }, 141955f14b4SBjorn Helgaas }; 142955f14b4SBjorn Helgaas 14356368029SVishal Verma static struct pci_osc_bit_struct cxl_osc_support_bit[] = { 14456368029SVishal Verma { OSC_CXL_1_1_PORT_REG_ACCESS_SUPPORT, "CXL11PortRegAccess" }, 14556368029SVishal Verma { OSC_CXL_2_0_PORT_DEV_REG_ACCESS_SUPPORT, "CXL20PortDevRegAccess" }, 14656368029SVishal Verma { OSC_CXL_PROTOCOL_ERR_REPORTING_SUPPORT, "CXLProtocolErrorReporting" }, 14756368029SVishal Verma { OSC_CXL_NATIVE_HP_SUPPORT, "CXLNativeHotPlug" }, 14856368029SVishal Verma }; 14956368029SVishal Verma 15056368029SVishal Verma static struct pci_osc_bit_struct cxl_osc_control_bit[] = { 15156368029SVishal Verma { OSC_CXL_ERROR_REPORTING_CONTROL, "CXLMemErrorReporting" }, 15256368029SVishal Verma }; 15356368029SVishal Verma 154955f14b4SBjorn Helgaas static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word, 155955f14b4SBjorn Helgaas struct pci_osc_bit_struct *table, int size) 156955f14b4SBjorn Helgaas { 157955f14b4SBjorn Helgaas char buf[80]; 158955f14b4SBjorn Helgaas int i, len = 0; 159955f14b4SBjorn Helgaas struct pci_osc_bit_struct *entry; 160955f14b4SBjorn Helgaas 161955f14b4SBjorn Helgaas buf[0] = '\0'; 162955f14b4SBjorn Helgaas for (i = 0, entry = table; i < size; i++, entry++) 163955f14b4SBjorn Helgaas if (word & entry->bit) 164edd66086STakashi Iwai len += scnprintf(buf + len, sizeof(buf) - len, "%s%s", 165955f14b4SBjorn Helgaas len ? " " : "", entry->desc); 166955f14b4SBjorn Helgaas 167955f14b4SBjorn Helgaas dev_info(&root->device->dev, "_OSC: %s [%s]\n", msg, buf); 168955f14b4SBjorn Helgaas } 169955f14b4SBjorn Helgaas 170955f14b4SBjorn Helgaas static void decode_osc_support(struct acpi_pci_root *root, char *msg, u32 word) 171955f14b4SBjorn Helgaas { 172955f14b4SBjorn Helgaas decode_osc_bits(root, msg, word, pci_osc_support_bit, 173955f14b4SBjorn Helgaas ARRAY_SIZE(pci_osc_support_bit)); 174955f14b4SBjorn Helgaas } 175955f14b4SBjorn Helgaas 176955f14b4SBjorn Helgaas static void decode_osc_control(struct acpi_pci_root *root, char *msg, u32 word) 177955f14b4SBjorn Helgaas { 178955f14b4SBjorn Helgaas decode_osc_bits(root, msg, word, pci_osc_control_bit, 179955f14b4SBjorn Helgaas ARRAY_SIZE(pci_osc_control_bit)); 180955f14b4SBjorn Helgaas } 181955f14b4SBjorn Helgaas 18256368029SVishal Verma static void decode_cxl_osc_support(struct acpi_pci_root *root, char *msg, u32 word) 18356368029SVishal Verma { 18456368029SVishal Verma decode_osc_bits(root, msg, word, cxl_osc_support_bit, 18556368029SVishal Verma ARRAY_SIZE(cxl_osc_support_bit)); 18656368029SVishal Verma } 18763f10f0fSKenji Kaneshige 18856368029SVishal Verma static void decode_cxl_osc_control(struct acpi_pci_root *root, char *msg, u32 word) 18956368029SVishal Verma { 19056368029SVishal Verma decode_osc_bits(root, msg, word, cxl_osc_control_bit, 19156368029SVishal Verma ARRAY_SIZE(cxl_osc_control_bit)); 19256368029SVishal Verma } 19356368029SVishal Verma 194241d26bcSDan Williams static inline bool is_pcie(struct acpi_pci_root *root) 195241d26bcSDan Williams { 196241d26bcSDan Williams return root->bridge_type == ACPI_BRIDGE_TYPE_PCIE; 197241d26bcSDan Williams } 19863f10f0fSKenji Kaneshige 199241d26bcSDan Williams static inline bool is_cxl(struct acpi_pci_root *root) 200241d26bcSDan Williams { 201241d26bcSDan Williams return root->bridge_type == ACPI_BRIDGE_TYPE_CXL; 202241d26bcSDan Williams } 203241d26bcSDan Williams 204241d26bcSDan Williams static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; 205241d26bcSDan Williams static u8 cxl_osc_uuid_str[] = "68F2D50B-C469-4d8A-BD3D-941A103FD3FC"; 206241d26bcSDan Williams 207241d26bcSDan Williams static char *to_uuid(struct acpi_pci_root *root) 208241d26bcSDan Williams { 209241d26bcSDan Williams if (is_cxl(root)) 210241d26bcSDan Williams return cxl_osc_uuid_str; 211241d26bcSDan Williams return pci_osc_uuid_str; 212241d26bcSDan Williams } 213241d26bcSDan Williams 214241d26bcSDan Williams static int cap_length(struct acpi_pci_root *root) 215241d26bcSDan Williams { 216241d26bcSDan Williams if (is_cxl(root)) 217241d26bcSDan Williams return sizeof(u32) * OSC_CXL_CAPABILITY_DWORDS; 218241d26bcSDan Williams return sizeof(u32) * OSC_PCI_CAPABILITY_DWORDS; 219241d26bcSDan Williams } 220241d26bcSDan Williams 221241d26bcSDan Williams static acpi_status acpi_pci_run_osc(struct acpi_pci_root *root, 22256368029SVishal Verma const u32 *capbuf, u32 *pci_control, 22356368029SVishal Verma u32 *cxl_control) 22463f10f0fSKenji Kaneshige { 2253a9622dcSShaohua Li struct acpi_osc_context context = { 226241d26bcSDan Williams .uuid_str = to_uuid(root), 2273a9622dcSShaohua Li .rev = 1, 228241d26bcSDan Williams .cap.length = cap_length(root), 2293a9622dcSShaohua Li .cap.pointer = (void *)capbuf, 2303a9622dcSShaohua Li }; 23163f10f0fSKenji Kaneshige acpi_status status; 23263f10f0fSKenji Kaneshige 233241d26bcSDan Williams status = acpi_run_osc(root->device->handle, &context); 2343a9622dcSShaohua Li if (ACPI_SUCCESS(status)) { 23556368029SVishal Verma *pci_control = acpi_osc_ctx_get_pci_control(&context); 23656368029SVishal Verma if (is_cxl(root)) 23756368029SVishal Verma *cxl_control = acpi_osc_ctx_get_cxl_control(&context); 2383a9622dcSShaohua Li kfree(context.ret.pointer); 23963f10f0fSKenji Kaneshige } 24063f10f0fSKenji Kaneshige return status; 24163f10f0fSKenji Kaneshige } 24263f10f0fSKenji Kaneshige 24356368029SVishal Verma static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 support, 24456368029SVishal Verma u32 *control, u32 cxl_support, 24556368029SVishal Verma u32 *cxl_control) 24663f10f0fSKenji Kaneshige { 24763f10f0fSKenji Kaneshige acpi_status status; 24856368029SVishal Verma u32 pci_result, cxl_result, capbuf[OSC_CXL_CAPABILITY_DWORDS]; 24963f10f0fSKenji Kaneshige 250ab8e8957SRafael J. Wysocki support |= root->osc_support_set; 251ab8e8957SRafael J. Wysocki 252b938a229SBjorn Helgaas capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; 253b938a229SBjorn Helgaas capbuf[OSC_SUPPORT_DWORD] = support; 254b938a229SBjorn Helgaas capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set; 25563f10f0fSKenji Kaneshige 25656368029SVishal Verma if (is_cxl(root)) { 25756368029SVishal Verma cxl_support |= root->osc_ext_support_set; 25856368029SVishal Verma capbuf[OSC_EXT_SUPPORT_DWORD] = cxl_support; 25956368029SVishal Verma capbuf[OSC_EXT_CONTROL_DWORD] = *cxl_control | root->osc_ext_control_set; 26056368029SVishal Verma } 26156368029SVishal Verma 262241d26bcSDan Williams retry: 26356368029SVishal Verma status = acpi_pci_run_osc(root, capbuf, &pci_result, &cxl_result); 26463f10f0fSKenji Kaneshige if (ACPI_SUCCESS(status)) { 265ab8e8957SRafael J. Wysocki root->osc_support_set = support; 26656368029SVishal Verma *control = pci_result; 26756368029SVishal Verma if (is_cxl(root)) { 26856368029SVishal Verma root->osc_ext_support_set = cxl_support; 26956368029SVishal Verma *cxl_control = cxl_result; 27056368029SVishal Verma } 271241d26bcSDan Williams } else if (is_cxl(root)) { 272241d26bcSDan Williams /* 273241d26bcSDan Williams * CXL _OSC is optional on CXL 1.1 hosts. Fall back to PCIe _OSC 274241d26bcSDan Williams * upon any failure using CXL _OSC. 275241d26bcSDan Williams */ 276241d26bcSDan Williams root->bridge_type = ACPI_BRIDGE_TYPE_PCIE; 277241d26bcSDan Williams goto retry; 278ab8e8957SRafael J. Wysocki } 27963f10f0fSKenji Kaneshige return status; 28063f10f0fSKenji Kaneshige } 28163f10f0fSKenji Kaneshige 28276d56de5SAlex Chiang struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) 28363f10f0fSKenji Kaneshige { 28499ece713SRafael J. Wysocki struct acpi_device *device = acpi_fetch_acpi_dev(handle); 28563f10f0fSKenji Kaneshige struct acpi_pci_root *root; 286c1aec834SBjorn Helgaas 28799ece713SRafael J. Wysocki if (!device || acpi_match_device_ids(device, root_device_ids)) 28863f10f0fSKenji Kaneshige return NULL; 289cd4faf9cSTaku Izumi 290cd4faf9cSTaku Izumi root = acpi_driver_data(device); 291cd4faf9cSTaku Izumi 292cd4faf9cSTaku Izumi return root; 29363f10f0fSKenji Kaneshige } 29476d56de5SAlex Chiang EXPORT_SYMBOL_GPL(acpi_pci_find_root); 29563f10f0fSKenji Kaneshige 2962f7bbcebSAlexander Chiang struct acpi_handle_node { 2972f7bbcebSAlexander Chiang struct list_head node; 2982f7bbcebSAlexander Chiang acpi_handle handle; 2992f7bbcebSAlexander Chiang }; 3002f7bbcebSAlexander Chiang 3012f7bbcebSAlexander Chiang /** 3022f7bbcebSAlexander Chiang * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev 3032f7bbcebSAlexander Chiang * @handle: the handle in question 3042f7bbcebSAlexander Chiang * 3052f7bbcebSAlexander Chiang * Given an ACPI CA handle, the desired PCI device is located in the 3062f7bbcebSAlexander Chiang * list of PCI devices. 3072f7bbcebSAlexander Chiang * 3082f7bbcebSAlexander Chiang * If the device is found, its reference count is increased and this 3092f7bbcebSAlexander Chiang * function returns a pointer to its data structure. The caller must 3102f7bbcebSAlexander Chiang * decrement the reference count by calling pci_dev_put(). 3112f7bbcebSAlexander Chiang * If no device is found, %NULL is returned. 3122f7bbcebSAlexander Chiang */ 3132f7bbcebSAlexander Chiang struct pci_dev *acpi_get_pci_dev(acpi_handle handle) 3142f7bbcebSAlexander Chiang { 315*63f534b8SRafael J. Wysocki struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 316*63f534b8SRafael J. Wysocki struct acpi_device_physical_node *pn; 317*63f534b8SRafael J. Wysocki struct pci_dev *pci_dev = NULL; 3182f7bbcebSAlexander Chiang 319*63f534b8SRafael J. Wysocki if (!adev) 320*63f534b8SRafael J. Wysocki return NULL; 3212f7bbcebSAlexander Chiang 322*63f534b8SRafael J. Wysocki mutex_lock(&adev->physical_node_lock); 3232f7bbcebSAlexander Chiang 324*63f534b8SRafael J. Wysocki list_for_each_entry(pn, &adev->physical_node_list, node) { 325*63f534b8SRafael J. Wysocki if (dev_is_pci(pn->dev)) { 326*63f534b8SRafael J. Wysocki pci_dev = to_pci_dev(pn->dev); 327497fb54fSRafael J. Wysocki break; 328497fb54fSRafael J. Wysocki } 3292f7bbcebSAlexander Chiang } 3302f7bbcebSAlexander Chiang 331*63f534b8SRafael J. Wysocki mutex_unlock(&adev->physical_node_lock); 332*63f534b8SRafael J. Wysocki 333*63f534b8SRafael J. Wysocki return pci_dev; 3342f7bbcebSAlexander Chiang } 3352f7bbcebSAlexander Chiang EXPORT_SYMBOL_GPL(acpi_get_pci_dev); 3362f7bbcebSAlexander Chiang 33763f10f0fSKenji Kaneshige /** 33875fb60f2SRafael J. Wysocki * acpi_pci_osc_control_set - Request control of PCI root _OSC features. 33975fb60f2SRafael J. Wysocki * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex). 34075fb60f2SRafael J. Wysocki * @mask: Mask of _OSC bits to request control of, place to store control mask. 341843438deSYang Li * @support: _OSC supported capability. 34256368029SVishal Verma * @cxl_mask: Mask of CXL _OSC control bits, place to store control mask. 34356368029SVishal Verma * @cxl_support: CXL _OSC supported capability. 34463f10f0fSKenji Kaneshige * 34575fb60f2SRafael J. Wysocki * Run _OSC query for @mask and if that is successful, compare the returned 34675fb60f2SRafael J. Wysocki * mask of control bits with @req. If all of the @req bits are set in the 34775fb60f2SRafael J. Wysocki * returned mask, run _OSC request for it. 34875fb60f2SRafael J. Wysocki * 34975fb60f2SRafael J. Wysocki * The variable at the @mask address may be modified regardless of whether or 35075fb60f2SRafael J. Wysocki * not the function returns success. On success it will contain the mask of 35175fb60f2SRafael J. Wysocki * _OSC bits the BIOS has granted control of, but its contents are meaningless 35275fb60f2SRafael J. Wysocki * on failure. 35363f10f0fSKenji Kaneshige **/ 35456368029SVishal Verma static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, 35556368029SVishal Verma u32 support, u32 *cxl_mask, 35656368029SVishal Verma u32 cxl_support) 35763f10f0fSKenji Kaneshige { 3586bc779eeSJoerg Roedel u32 req = OSC_PCI_EXPRESS_CAPABILITY_CONTROL; 35963f10f0fSKenji Kaneshige struct acpi_pci_root *root; 360866e61fcSBjorn Helgaas acpi_status status; 36156368029SVishal Verma u32 ctrl, cxl_ctrl = 0, capbuf[OSC_CXL_CAPABILITY_DWORDS]; 36263f10f0fSKenji Kaneshige 36375fb60f2SRafael J. Wysocki if (!mask) 36475fb60f2SRafael J. Wysocki return AE_BAD_PARAMETER; 36575fb60f2SRafael J. Wysocki 36663f10f0fSKenji Kaneshige root = acpi_pci_find_root(handle); 36763f10f0fSKenji Kaneshige if (!root) 36863f10f0fSKenji Kaneshige return AE_NOT_EXIST; 36963f10f0fSKenji Kaneshige 3706bc779eeSJoerg Roedel ctrl = *mask; 3716bc779eeSJoerg Roedel *mask |= root->osc_control_set; 37263f10f0fSKenji Kaneshige 37356368029SVishal Verma if (is_cxl(root)) { 37456368029SVishal Verma cxl_ctrl = *cxl_mask; 37556368029SVishal Verma *cxl_mask |= root->osc_ext_control_set; 37656368029SVishal Verma } 37756368029SVishal Verma 37875fb60f2SRafael J. Wysocki /* Need to check the available controls bits before requesting them. */ 3796bc779eeSJoerg Roedel do { 38056368029SVishal Verma u32 pci_missing = 0, cxl_missing = 0; 38156368029SVishal Verma 38256368029SVishal Verma status = acpi_pci_query_osc(root, support, mask, cxl_support, 38356368029SVishal Verma cxl_mask); 38463f10f0fSKenji Kaneshige if (ACPI_FAILURE(status)) 385866e61fcSBjorn Helgaas return status; 38656368029SVishal Verma if (is_cxl(root)) { 38756368029SVishal Verma if (ctrl == *mask && cxl_ctrl == *cxl_mask) 38856368029SVishal Verma break; 38956368029SVishal Verma pci_missing = ctrl & ~(*mask); 39056368029SVishal Verma cxl_missing = cxl_ctrl & ~(*cxl_mask); 39156368029SVishal Verma } else { 39275fb60f2SRafael J. Wysocki if (ctrl == *mask) 39375fb60f2SRafael J. Wysocki break; 39456368029SVishal Verma pci_missing = ctrl & ~(*mask); 39556368029SVishal Verma } 39656368029SVishal Verma if (pci_missing) 397955f14b4SBjorn Helgaas decode_osc_control(root, "platform does not support", 39856368029SVishal Verma pci_missing); 39956368029SVishal Verma if (cxl_missing) 40056368029SVishal Verma decode_cxl_osc_control(root, "CXL platform does not support", 40156368029SVishal Verma cxl_missing); 40275fb60f2SRafael J. Wysocki ctrl = *mask; 40356368029SVishal Verma cxl_ctrl = *cxl_mask; 40456368029SVishal Verma } while (*mask || *cxl_mask); 4056bc779eeSJoerg Roedel 4066bc779eeSJoerg Roedel /* No need to request _OSC if the control was already granted. */ 40756368029SVishal Verma if ((root->osc_control_set & ctrl) == ctrl && 40856368029SVishal Verma (root->osc_ext_control_set & cxl_ctrl) == cxl_ctrl) 4096bc779eeSJoerg Roedel return AE_OK; 4102b8fd918SRafael J. Wysocki 41175fb60f2SRafael J. Wysocki if ((ctrl & req) != req) { 412955f14b4SBjorn Helgaas decode_osc_control(root, "not requesting control; platform does not support", 413955f14b4SBjorn Helgaas req & ~(ctrl)); 414866e61fcSBjorn Helgaas return AE_SUPPORT; 41563f10f0fSKenji Kaneshige } 41663f10f0fSKenji Kaneshige 417b938a229SBjorn Helgaas capbuf[OSC_QUERY_DWORD] = 0; 418b938a229SBjorn Helgaas capbuf[OSC_SUPPORT_DWORD] = root->osc_support_set; 419b938a229SBjorn Helgaas capbuf[OSC_CONTROL_DWORD] = ctrl; 42056368029SVishal Verma if (is_cxl(root)) { 42156368029SVishal Verma capbuf[OSC_EXT_SUPPORT_DWORD] = root->osc_ext_support_set; 42256368029SVishal Verma capbuf[OSC_EXT_CONTROL_DWORD] = cxl_ctrl; 42356368029SVishal Verma } 42456368029SVishal Verma 42556368029SVishal Verma status = acpi_pci_run_osc(root, capbuf, mask, cxl_mask); 426866e61fcSBjorn Helgaas if (ACPI_FAILURE(status)) 42763f10f0fSKenji Kaneshige return status; 428866e61fcSBjorn Helgaas 429866e61fcSBjorn Helgaas root->osc_control_set = *mask; 43056368029SVishal Verma root->osc_ext_control_set = *cxl_mask; 431866e61fcSBjorn Helgaas return AE_OK; 43263f10f0fSKenji Kaneshige } 43363f10f0fSKenji Kaneshige 4344c6f6060SJoerg Roedel static u32 calculate_support(void) 4354c6f6060SJoerg Roedel { 4364c6f6060SJoerg Roedel u32 support; 4374c6f6060SJoerg Roedel 4384c6f6060SJoerg Roedel /* 4394c6f6060SJoerg Roedel * All supported architectures that use ACPI have support for 4404c6f6060SJoerg Roedel * PCI domains, so we indicate this in _OSC support capabilities. 4414c6f6060SJoerg Roedel */ 4424c6f6060SJoerg Roedel support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; 4434c6f6060SJoerg Roedel support |= OSC_PCI_HPX_TYPE_3_SUPPORT; 4444c6f6060SJoerg Roedel if (pci_ext_cfg_avail()) 4454c6f6060SJoerg Roedel support |= OSC_PCI_EXT_CONFIG_SUPPORT; 4464c6f6060SJoerg Roedel if (pcie_aspm_support_enabled()) 4474c6f6060SJoerg Roedel support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT; 4484c6f6060SJoerg Roedel if (pci_msi_enabled()) 4494c6f6060SJoerg Roedel support |= OSC_PCI_MSI_SUPPORT; 4504c6f6060SJoerg Roedel if (IS_ENABLED(CONFIG_PCIE_EDR)) 4514c6f6060SJoerg Roedel support |= OSC_PCI_EDR_SUPPORT; 4524c6f6060SJoerg Roedel 4534c6f6060SJoerg Roedel return support; 4544c6f6060SJoerg Roedel } 4554c6f6060SJoerg Roedel 45656368029SVishal Verma /* 45756368029SVishal Verma * Background on hotplug support, and making it depend on only 45856368029SVishal Verma * CONFIG_HOTPLUG_PCI_PCIE vs. also considering CONFIG_MEMORY_HOTPLUG: 45956368029SVishal Verma * 46056368029SVishal Verma * CONFIG_ACPI_HOTPLUG_MEMORY does depend on CONFIG_MEMORY_HOTPLUG, but 46156368029SVishal Verma * there is no existing _OSC for memory hotplug support. The reason is that 46256368029SVishal Verma * ACPI memory hotplug requires the OS to acknowledge / coordinate with 46356368029SVishal Verma * memory plug events via a scan handler. On the CXL side the equivalent 46456368029SVishal Verma * would be if Linux supported the Mechanical Retention Lock [1], or 46556368029SVishal Verma * otherwise had some coordination for the driver of a PCI device 46656368029SVishal Verma * undergoing hotplug to be consulted on whether the hotplug should 46756368029SVishal Verma * proceed or not. 46856368029SVishal Verma * 46956368029SVishal Verma * The concern is that if Linux says no to supporting CXL hotplug then 47056368029SVishal Verma * the BIOS may say no to giving the OS hotplug control of any other PCIe 47156368029SVishal Verma * device. So the question here is not whether hotplug is enabled, it's 47256368029SVishal Verma * whether it is handled natively by the at all OS, and if 47356368029SVishal Verma * CONFIG_HOTPLUG_PCI_PCIE is enabled then the answer is "yes". 47456368029SVishal Verma * 47556368029SVishal Verma * Otherwise, the plan for CXL coordinated remove, since the kernel does 47656368029SVishal Verma * not support blocking hotplug, is to require the memory device to be 47756368029SVishal Verma * disabled before hotplug is attempted. When CONFIG_MEMORY_HOTPLUG is 47856368029SVishal Verma * disabled that step will fail and the remove attempt cancelled by the 47956368029SVishal Verma * user. If that is not honored and the card is removed anyway then it 48056368029SVishal Verma * does not matter if CONFIG_MEMORY_HOTPLUG is enabled or not, it will 48156368029SVishal Verma * cause a crash and other badness. 48256368029SVishal Verma * 48356368029SVishal Verma * Therefore, just say yes to CXL hotplug and require removal to 48456368029SVishal Verma * be coordinated by userspace unless and until the kernel grows better 48556368029SVishal Verma * mechanisms for doing "managed" removal of devices in consultation with 48656368029SVishal Verma * the driver. 48756368029SVishal Verma * 48856368029SVishal Verma * [1]: https://lore.kernel.org/all/20201122014203.4706-1-ashok.raj@intel.com/ 48956368029SVishal Verma */ 49056368029SVishal Verma static u32 calculate_cxl_support(void) 49156368029SVishal Verma { 49256368029SVishal Verma u32 support; 49356368029SVishal Verma 49456368029SVishal Verma support = OSC_CXL_2_0_PORT_DEV_REG_ACCESS_SUPPORT; 49556368029SVishal Verma if (pci_aer_available()) 49656368029SVishal Verma support |= OSC_CXL_PROTOCOL_ERR_REPORTING_SUPPORT; 49756368029SVishal Verma if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) 49856368029SVishal Verma support |= OSC_CXL_NATIVE_HP_SUPPORT; 49956368029SVishal Verma 50056368029SVishal Verma return support; 50156368029SVishal Verma } 50256368029SVishal Verma 5034c6f6060SJoerg Roedel static u32 calculate_control(void) 5044c6f6060SJoerg Roedel { 5054c6f6060SJoerg Roedel u32 control; 5064c6f6060SJoerg Roedel 5074c6f6060SJoerg Roedel control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL 5084c6f6060SJoerg Roedel | OSC_PCI_EXPRESS_PME_CONTROL; 5094c6f6060SJoerg Roedel 5104c6f6060SJoerg Roedel if (IS_ENABLED(CONFIG_PCIEASPM)) 5114c6f6060SJoerg Roedel control |= OSC_PCI_EXPRESS_LTR_CONTROL; 5124c6f6060SJoerg Roedel 5134c6f6060SJoerg Roedel if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) 5144c6f6060SJoerg Roedel control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; 5154c6f6060SJoerg Roedel 5164c6f6060SJoerg Roedel if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) 5174c6f6060SJoerg Roedel control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; 5184c6f6060SJoerg Roedel 5194c6f6060SJoerg Roedel if (pci_aer_available()) 5204c6f6060SJoerg Roedel control |= OSC_PCI_EXPRESS_AER_CONTROL; 5214c6f6060SJoerg Roedel 5224c6f6060SJoerg Roedel /* 5234c6f6060SJoerg Roedel * Per the Downstream Port Containment Related Enhancements ECN to 5244c6f6060SJoerg Roedel * the PCI Firmware Spec, r3.2, sec 4.5.1, table 4-5, 5254c6f6060SJoerg Roedel * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC 5264c6f6060SJoerg Roedel * and EDR. 5274c6f6060SJoerg Roedel */ 5284c6f6060SJoerg Roedel if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR)) 5294c6f6060SJoerg Roedel control |= OSC_PCI_EXPRESS_DPC_CONTROL; 5304c6f6060SJoerg Roedel 5314c6f6060SJoerg Roedel return control; 5324c6f6060SJoerg Roedel } 5334c6f6060SJoerg Roedel 53456368029SVishal Verma static u32 calculate_cxl_control(void) 53556368029SVishal Verma { 53656368029SVishal Verma u32 control = 0; 53756368029SVishal Verma 53856368029SVishal Verma if (IS_ENABLED(CONFIG_MEMORY_FAILURE)) 53956368029SVishal Verma control |= OSC_CXL_ERROR_REPORTING_CONTROL; 54056368029SVishal Verma 54156368029SVishal Verma return control; 54256368029SVishal Verma } 54356368029SVishal Verma 54487f1f87aSJoerg Roedel static bool os_control_query_checks(struct acpi_pci_root *root, u32 support) 54587f1f87aSJoerg Roedel { 54687f1f87aSJoerg Roedel struct acpi_device *device = root->device; 54787f1f87aSJoerg Roedel 54887f1f87aSJoerg Roedel if (pcie_ports_disabled) { 54987f1f87aSJoerg Roedel dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n"); 55087f1f87aSJoerg Roedel return false; 55187f1f87aSJoerg Roedel } 55287f1f87aSJoerg Roedel 55387f1f87aSJoerg Roedel if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) { 55487f1f87aSJoerg Roedel decode_osc_support(root, "not requesting OS control; OS requires", 55587f1f87aSJoerg Roedel ACPI_PCIE_REQ_SUPPORT); 55687f1f87aSJoerg Roedel return false; 55787f1f87aSJoerg Roedel } 55887f1f87aSJoerg Roedel 55987f1f87aSJoerg Roedel return true; 56087f1f87aSJoerg Roedel } 56187f1f87aSJoerg Roedel 562241d26bcSDan Williams static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) 5633e43abb0SBjorn Helgaas { 5646bc779eeSJoerg Roedel u32 support, control = 0, requested = 0; 56556368029SVishal Verma u32 cxl_support = 0, cxl_control = 0, cxl_requested = 0; 5663e43abb0SBjorn Helgaas acpi_status status; 5673e43abb0SBjorn Helgaas struct acpi_device *device = root->device; 5683e43abb0SBjorn Helgaas acpi_handle handle = device->handle; 5693e43abb0SBjorn Helgaas 5703e43abb0SBjorn Helgaas /* 5717bc5a2baSMatthew Garrett * Apple always return failure on _OSC calls when _OSI("Darwin") has 5727bc5a2baSMatthew Garrett * been called successfully. We know the feature set supported by the 5737bc5a2baSMatthew Garrett * platform, so avoid calling _OSC at all 5747bc5a2baSMatthew Garrett */ 575630b3affSLukas Wunner if (x86_apple_machine) { 5767bc5a2baSMatthew Garrett root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL; 5777bc5a2baSMatthew Garrett decode_osc_control(root, "OS assumes control of", 5787bc5a2baSMatthew Garrett root->osc_control_set); 5797bc5a2baSMatthew Garrett return; 5807bc5a2baSMatthew Garrett } 5817bc5a2baSMatthew Garrett 5824c6f6060SJoerg Roedel support = calculate_support(); 583955f14b4SBjorn Helgaas 584955f14b4SBjorn Helgaas decode_osc_support(root, "OS supports", support); 585c238252fSSinan Kaya 5866bc779eeSJoerg Roedel if (os_control_query_checks(root, support)) 5874c6f6060SJoerg Roedel requested = control = calculate_control(); 5883e43abb0SBjorn Helgaas 58956368029SVishal Verma if (is_cxl(root)) { 59056368029SVishal Verma cxl_support = calculate_cxl_support(); 59156368029SVishal Verma decode_cxl_osc_support(root, "OS supports", cxl_support); 59256368029SVishal Verma cxl_requested = cxl_control = calculate_cxl_control(); 59356368029SVishal Verma } 59456368029SVishal Verma 59556368029SVishal Verma status = acpi_pci_osc_control_set(handle, &control, support, 59656368029SVishal Verma &cxl_control, cxl_support); 5973e43abb0SBjorn Helgaas if (ACPI_SUCCESS(status)) { 5986bc779eeSJoerg Roedel if (control) 599955f14b4SBjorn Helgaas decode_osc_control(root, "OS now controls", control); 60056368029SVishal Verma if (cxl_control) 60156368029SVishal Verma decode_cxl_osc_control(root, "OS now controls", 60256368029SVishal Verma cxl_control); 6036bc779eeSJoerg Roedel 6043e43abb0SBjorn Helgaas if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { 6053e43abb0SBjorn Helgaas /* 606387d3757SMatthew Garrett * We have ASPM control, but the FADT indicates that 607387d3757SMatthew Garrett * it's unsupported. Leave existing configuration 608387d3757SMatthew Garrett * intact and prevent the OS from touching it. 6093e43abb0SBjorn Helgaas */ 610387d3757SMatthew Garrett dev_info(&device->dev, "FADT indicates ASPM is unsupported, using BIOS configuration\n"); 611387d3757SMatthew Garrett *no_aspm = 1; 6123e43abb0SBjorn Helgaas } 6133e43abb0SBjorn Helgaas } else { 6143e43abb0SBjorn Helgaas /* 6153e43abb0SBjorn Helgaas * We want to disable ASPM here, but aspm_disabled 6163e43abb0SBjorn Helgaas * needs to remain in its state from boot so that we 6173e43abb0SBjorn Helgaas * properly handle PCIe 1.1 devices. So we set this 6183e43abb0SBjorn Helgaas * flag here, to defer the action until after the ACPI 6193e43abb0SBjorn Helgaas * root scan. 6203e43abb0SBjorn Helgaas */ 6213e43abb0SBjorn Helgaas *no_aspm = 1; 6226bc779eeSJoerg Roedel 6236bc779eeSJoerg Roedel /* _OSC is optional for PCI host bridges */ 624241d26bcSDan Williams if (status == AE_NOT_FOUND && !is_pcie(root)) 6256bc779eeSJoerg Roedel return; 6266bc779eeSJoerg Roedel 6276bc779eeSJoerg Roedel if (control) { 6286bc779eeSJoerg Roedel decode_osc_control(root, "OS requested", requested); 6296bc779eeSJoerg Roedel decode_osc_control(root, "platform willing to grant", control); 6306bc779eeSJoerg Roedel } 63156368029SVishal Verma if (cxl_control) { 63256368029SVishal Verma decode_cxl_osc_control(root, "OS requested", cxl_requested); 63356368029SVishal Verma decode_cxl_osc_control(root, "platform willing to grant", 63456368029SVishal Verma cxl_control); 63556368029SVishal Verma } 6366bc779eeSJoerg Roedel 6376bc779eeSJoerg Roedel dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", 6386bc779eeSJoerg Roedel acpi_format_exception(status)); 6393e43abb0SBjorn Helgaas } 6403e43abb0SBjorn Helgaas } 6413e43abb0SBjorn Helgaas 64200c43b96SRafael J. Wysocki static int acpi_pci_root_add(struct acpi_device *device, 64300c43b96SRafael J. Wysocki const struct acpi_device_id *not_used) 6441da177e4SLinus Torvalds { 645f5eebbe1SBjorn Helgaas unsigned long long segment, bus; 646f5eebbe1SBjorn Helgaas acpi_status status; 647f5eebbe1SBjorn Helgaas int result; 648f5eebbe1SBjorn Helgaas struct acpi_pci_root *root; 649bfe2414aSJiang Liu acpi_handle handle = device->handle; 650387d3757SMatthew Garrett int no_aspm = 0; 6519762b33dSThomas Gleixner bool hotadd = system_state == SYSTEM_RUNNING; 652241d26bcSDan Williams const char *acpi_hid; 6531da177e4SLinus Torvalds 6546ad95513SBjorn Helgaas root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); 6556ad95513SBjorn Helgaas if (!root) 6566ad95513SBjorn Helgaas return -ENOMEM; 6576ad95513SBjorn Helgaas 658f5eebbe1SBjorn Helgaas segment = 0; 659bfe2414aSJiang Liu status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, 660f5eebbe1SBjorn Helgaas &segment); 661f5eebbe1SBjorn Helgaas if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 6626dc7d22cSJiang Liu dev_err(&device->dev, "can't evaluate _SEG\n"); 6636ad95513SBjorn Helgaas result = -ENODEV; 6646ad95513SBjorn Helgaas goto end; 665f5eebbe1SBjorn Helgaas } 6661da177e4SLinus Torvalds 667f5eebbe1SBjorn Helgaas /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ 6686ad95513SBjorn Helgaas root->secondary.flags = IORESOURCE_BUS; 669bfe2414aSJiang Liu status = try_get_root_bridge_busnr(handle, &root->secondary); 670f5eebbe1SBjorn Helgaas if (ACPI_FAILURE(status)) { 6716ad95513SBjorn Helgaas /* 6726ad95513SBjorn Helgaas * We need both the start and end of the downstream bus range 6736ad95513SBjorn Helgaas * to interpret _CBA (MMCONFIG base address), so it really is 6746ad95513SBjorn Helgaas * supposed to be in _CRS. If we don't find it there, all we 6756ad95513SBjorn Helgaas * can do is assume [_BBN-0xFF] or [0-0xFF]. 6766ad95513SBjorn Helgaas */ 6776ad95513SBjorn Helgaas root->secondary.end = 0xFF; 6786dc7d22cSJiang Liu dev_warn(&device->dev, 6796dc7d22cSJiang Liu FW_BUG "no secondary bus range in _CRS\n"); 680bfe2414aSJiang Liu status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, 681e545b55aSJon Mason NULL, &bus); 6826ad95513SBjorn Helgaas if (ACPI_SUCCESS(status)) 6836ad95513SBjorn Helgaas root->secondary.start = bus; 6846ad95513SBjorn Helgaas else if (status == AE_NOT_FOUND) 6856ad95513SBjorn Helgaas root->secondary.start = 0; 6866ad95513SBjorn Helgaas else { 6876dc7d22cSJiang Liu dev_err(&device->dev, "can't evaluate _BBN\n"); 6886ad95513SBjorn Helgaas result = -ENODEV; 6896ad95513SBjorn Helgaas goto end; 690f5eebbe1SBjorn Helgaas } 691f5eebbe1SBjorn Helgaas } 6921da177e4SLinus Torvalds 69332917e5bSPatrick Mochel root->device = device; 6940705495dSBjorn Helgaas root->segment = segment & 0xFFFF; 6951da177e4SLinus Torvalds strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); 6961da177e4SLinus Torvalds strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); 697db89b4f0SPavel Machek device->driver_data = root; 6981da177e4SLinus Torvalds 699864b94adSJiang Liu if (hotadd && dmar_device_add(handle)) { 700864b94adSJiang Liu result = -ENXIO; 701864b94adSJiang Liu goto end; 702864b94adSJiang Liu } 703864b94adSJiang Liu 704ccde83e3SHanjun Guo pr_info("%s [%s] (domain %04x %pR)\n", 705d4761ba2SBjorn Helgaas acpi_device_name(device), acpi_device_bid(device), 706d4761ba2SBjorn Helgaas root->segment, &root->secondary); 707d4761ba2SBjorn Helgaas 708bfe2414aSJiang Liu root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); 709f4b57a3bSJiang Liu 710241d26bcSDan Williams acpi_hid = acpi_device_hid(root->device); 711241d26bcSDan Williams if (strcmp(acpi_hid, "PNP0A08") == 0) 712241d26bcSDan Williams root->bridge_type = ACPI_BRIDGE_TYPE_PCIE; 713241d26bcSDan Williams else if (strcmp(acpi_hid, "ACPI0016") == 0) 714241d26bcSDan Williams root->bridge_type = ACPI_BRIDGE_TYPE_CXL; 715241d26bcSDan Williams else 716241d26bcSDan Williams dev_dbg(&device->dev, "Assuming non-PCIe host bridge\n"); 717241d26bcSDan Williams 718241d26bcSDan Williams negotiate_os_control(root, &no_aspm); 719415e12b2SRafael J. Wysocki 7203dc48af3SNeil Horman /* 7213dc48af3SNeil Horman * TBD: Need PCI interface for enumeration/configuration of roots. 7223dc48af3SNeil Horman */ 7233dc48af3SNeil Horman 7243dc48af3SNeil Horman /* 7253dc48af3SNeil Horman * Scan the Root Bridge 7263dc48af3SNeil Horman * -------------------- 7273dc48af3SNeil Horman * Must do this prior to any attempt to bind the root device, as the 7283dc48af3SNeil Horman * PCI namespace does not get created until this call is made (and 7293dc48af3SNeil Horman * thus the root bridge's pci_dev does not exist). 7303dc48af3SNeil Horman */ 7313dc48af3SNeil Horman root->bus = pci_acpi_scan_root(root); 7323dc48af3SNeil Horman if (!root->bus) { 7333dc48af3SNeil Horman dev_err(&device->dev, 7343dc48af3SNeil Horman "Bus %04x:%02x not present in PCI namespace\n", 7353dc48af3SNeil Horman root->segment, (unsigned int)root->secondary.start); 736f516bde5SRafael J. Wysocki device->driver_data = NULL; 7373dc48af3SNeil Horman result = -ENODEV; 738864b94adSJiang Liu goto remove_dmar; 7393dc48af3SNeil Horman } 7403dc48af3SNeil Horman 7413dc48af3SNeil Horman if (no_aspm) 7423dc48af3SNeil Horman pcie_no_aspm(); 7433dc48af3SNeil Horman 744c072530fSRafael J. Wysocki pci_acpi_add_bus_pm_notifier(device); 745de3ef1ebSRafael J. Wysocki device_set_wakeup_capable(root->bus->bridge, device->wakeup.flags.valid); 746b67ea761SRafael J. Wysocki 747864b94adSJiang Liu if (hotadd) { 7483c449ed0SYinghai Lu pcibios_resource_survey_bus(root->bus); 74939772038SYinghai Lu pci_assign_unassigned_root_bus_resources(root->bus); 750584c5c42SRui Wang /* 751584c5c42SRui Wang * This is only called for the hotadd case. For the boot-time 752584c5c42SRui Wang * case, we need to wait until after PCI initialization in 753584c5c42SRui Wang * order to deal with IOAPICs mapped in on a PCI BAR. 754584c5c42SRui Wang * 755584c5c42SRui Wang * This is currently x86-specific, because acpi_ioapic_add() 756584c5c42SRui Wang * is an empty function without CONFIG_ACPI_HOTPLUG_IOAPIC. 757584c5c42SRui Wang * And CONFIG_ACPI_HOTPLUG_IOAPIC depends on CONFIG_X86_IO_APIC 758584c5c42SRui Wang * (see drivers/acpi/Kconfig). 759584c5c42SRui Wang */ 760fe7bd58fSRui Wang acpi_ioapic_add(root->device->handle); 761516ca223SJiang Liu } 76262a08c5aSYinghai Lu 7637a3bb55eSRafael J. Wysocki pci_lock_rescan_remove(); 764c431ada4SRajesh Shah pci_bus_add_devices(root->bus); 7657a3bb55eSRafael J. Wysocki pci_unlock_rescan_remove(); 76600c43b96SRafael J. Wysocki return 1; 76747525cdaSRafael J. Wysocki 768864b94adSJiang Liu remove_dmar: 769864b94adSJiang Liu if (hotadd) 770864b94adSJiang Liu dmar_device_remove(handle); 77147525cdaSRafael J. Wysocki end: 77247525cdaSRafael J. Wysocki kfree(root); 77347525cdaSRafael J. Wysocki return result; 774c431ada4SRajesh Shah } 7751da177e4SLinus Torvalds 77600c43b96SRafael J. Wysocki static void acpi_pci_root_remove(struct acpi_device *device) 7771da177e4SLinus Torvalds { 778caf420c6SBjorn Helgaas struct acpi_pci_root *root = acpi_driver_data(device); 779c8e9afb1SJiang Liu 7807a3bb55eSRafael J. Wysocki pci_lock_rescan_remove(); 7817a3bb55eSRafael J. Wysocki 7829738a1fdSYinghai Lu pci_stop_root_bus(root->bus); 7839738a1fdSYinghai Lu 784f2ae5da7SRui Wang pci_ioapic_remove(root); 785de3ef1ebSRafael J. Wysocki device_set_wakeup_capable(root->bus->bridge, false); 786b67ea761SRafael J. Wysocki pci_acpi_remove_bus_pm_notifier(device); 787b67ea761SRafael J. Wysocki 7889738a1fdSYinghai Lu pci_remove_root_bus(root->bus); 789f2ae5da7SRui Wang WARN_ON(acpi_ioapic_remove(root)); 7909738a1fdSYinghai Lu 791864b94adSJiang Liu dmar_device_remove(device->handle); 792864b94adSJiang Liu 7937a3bb55eSRafael J. Wysocki pci_unlock_rescan_remove(); 7947a3bb55eSRafael J. Wysocki 7951da177e4SLinus Torvalds kfree(root); 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds 7982c204383SJiang Liu /* 7992c204383SJiang Liu * Following code to support acpi_pci_root_create() is copied from 8002c204383SJiang Liu * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64 8012c204383SJiang Liu * and ARM64. 8022c204383SJiang Liu */ 8032c204383SJiang Liu static void acpi_pci_root_validate_resources(struct device *dev, 8042c204383SJiang Liu struct list_head *resources, 8052c204383SJiang Liu unsigned long type) 8062c204383SJiang Liu { 8072c204383SJiang Liu LIST_HEAD(list); 8082c204383SJiang Liu struct resource *res1, *res2, *root = NULL; 8092c204383SJiang Liu struct resource_entry *tmp, *entry, *entry2; 8102c204383SJiang Liu 8112c204383SJiang Liu BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); 8122c204383SJiang Liu root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; 8132c204383SJiang Liu 8142c204383SJiang Liu list_splice_init(resources, &list); 8152c204383SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &list) { 8162c204383SJiang Liu bool free = false; 8172c204383SJiang Liu resource_size_t end; 8182c204383SJiang Liu 8192c204383SJiang Liu res1 = entry->res; 8202c204383SJiang Liu if (!(res1->flags & type)) 8212c204383SJiang Liu goto next; 8222c204383SJiang Liu 8232c204383SJiang Liu /* Exclude non-addressable range or non-addressable portion */ 8242c204383SJiang Liu end = min(res1->end, root->end); 8252c204383SJiang Liu if (end <= res1->start) { 8262c204383SJiang Liu dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", 8272c204383SJiang Liu res1); 8282c204383SJiang Liu free = true; 8292c204383SJiang Liu goto next; 8302c204383SJiang Liu } else if (res1->end != end) { 8312c204383SJiang Liu dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", 8322c204383SJiang Liu res1, (unsigned long long)end + 1, 8332c204383SJiang Liu (unsigned long long)res1->end); 8342c204383SJiang Liu res1->end = end; 8352c204383SJiang Liu } 8362c204383SJiang Liu 8372c204383SJiang Liu resource_list_for_each_entry(entry2, resources) { 8382c204383SJiang Liu res2 = entry2->res; 8392c204383SJiang Liu if (!(res2->flags & type)) 8402c204383SJiang Liu continue; 8412c204383SJiang Liu 8422c204383SJiang Liu /* 8432c204383SJiang Liu * I don't like throwing away windows because then 8442c204383SJiang Liu * our resources no longer match the ACPI _CRS, but 8452c204383SJiang Liu * the kernel resource tree doesn't allow overlaps. 8462c204383SJiang Liu */ 84707aec68eSAndy Shevchenko if (resource_union(res1, res2, res2)) { 8482c204383SJiang Liu dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", 8492c204383SJiang Liu res2, res1); 8502c204383SJiang Liu free = true; 8512c204383SJiang Liu goto next; 8522c204383SJiang Liu } 8532c204383SJiang Liu } 8542c204383SJiang Liu 8552c204383SJiang Liu next: 8562c204383SJiang Liu resource_list_del(entry); 8572c204383SJiang Liu if (free) 8582c204383SJiang Liu resource_list_free_entry(entry); 8592c204383SJiang Liu else 8602c204383SJiang Liu resource_list_add_tail(entry, resources); 8612c204383SJiang Liu } 8622c204383SJiang Liu } 8632c204383SJiang Liu 864fcfaab30SGabriele Paoloni static void acpi_pci_root_remap_iospace(struct fwnode_handle *fwnode, 865fcfaab30SGabriele Paoloni struct resource_entry *entry) 8660a70abb3SJayachandran C { 8670a70abb3SJayachandran C #ifdef PCI_IOBASE 8680a70abb3SJayachandran C struct resource *res = entry->res; 8690a70abb3SJayachandran C resource_size_t cpu_addr = res->start; 8700a70abb3SJayachandran C resource_size_t pci_addr = cpu_addr - entry->offset; 8710a70abb3SJayachandran C resource_size_t length = resource_size(res); 8720a70abb3SJayachandran C unsigned long port; 8730a70abb3SJayachandran C 874fcfaab30SGabriele Paoloni if (pci_register_io_range(fwnode, cpu_addr, length)) 8750a70abb3SJayachandran C goto err; 8760a70abb3SJayachandran C 8770a70abb3SJayachandran C port = pci_address_to_pio(cpu_addr); 8780a70abb3SJayachandran C if (port == (unsigned long)-1) 8790a70abb3SJayachandran C goto err; 8800a70abb3SJayachandran C 8810a70abb3SJayachandran C res->start = port; 8820a70abb3SJayachandran C res->end = port + length - 1; 8830a70abb3SJayachandran C entry->offset = port - pci_addr; 8840a70abb3SJayachandran C 8850a70abb3SJayachandran C if (pci_remap_iospace(res, cpu_addr) < 0) 8860a70abb3SJayachandran C goto err; 8870a70abb3SJayachandran C 8880a70abb3SJayachandran C pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res); 8890a70abb3SJayachandran C return; 8900a70abb3SJayachandran C err: 8910a70abb3SJayachandran C res->flags |= IORESOURCE_DISABLED; 8920a70abb3SJayachandran C #endif 8930a70abb3SJayachandran C } 8940a70abb3SJayachandran C 8952c204383SJiang Liu int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info) 8962c204383SJiang Liu { 8972c204383SJiang Liu int ret; 8982c204383SJiang Liu struct list_head *list = &info->resources; 8992c204383SJiang Liu struct acpi_device *device = info->bridge; 9002c204383SJiang Liu struct resource_entry *entry, *tmp; 9012c204383SJiang Liu unsigned long flags; 9022c204383SJiang Liu 9032c204383SJiang Liu flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT; 9042c204383SJiang Liu ret = acpi_dev_get_resources(device, list, 9052c204383SJiang Liu acpi_dev_filter_resource_type_cb, 9062c204383SJiang Liu (void *)flags); 9072c204383SJiang Liu if (ret < 0) 9082c204383SJiang Liu dev_warn(&device->dev, 9092c204383SJiang Liu "failed to parse _CRS method, error code %d\n", ret); 9102c204383SJiang Liu else if (ret == 0) 9112c204383SJiang Liu dev_dbg(&device->dev, 9122c204383SJiang Liu "no IO and memory resources present in _CRS\n"); 9132c204383SJiang Liu else { 9142c204383SJiang Liu resource_list_for_each_entry_safe(entry, tmp, list) { 9150a70abb3SJayachandran C if (entry->res->flags & IORESOURCE_IO) 916fcfaab30SGabriele Paoloni acpi_pci_root_remap_iospace(&device->fwnode, 917fcfaab30SGabriele Paoloni entry); 9180a70abb3SJayachandran C 9192c204383SJiang Liu if (entry->res->flags & IORESOURCE_DISABLED) 9202c204383SJiang Liu resource_list_destroy_entry(entry); 9212c204383SJiang Liu else 9222c204383SJiang Liu entry->res->name = info->name; 9232c204383SJiang Liu } 9242c204383SJiang Liu acpi_pci_root_validate_resources(&device->dev, list, 9252c204383SJiang Liu IORESOURCE_MEM); 9262c204383SJiang Liu acpi_pci_root_validate_resources(&device->dev, list, 9272c204383SJiang Liu IORESOURCE_IO); 9282c204383SJiang Liu } 9292c204383SJiang Liu 9302c204383SJiang Liu return ret; 9312c204383SJiang Liu } 9322c204383SJiang Liu 9332c204383SJiang Liu static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info) 9342c204383SJiang Liu { 9352c204383SJiang Liu struct resource_entry *entry, *tmp; 9362c204383SJiang Liu struct resource *res, *conflict, *root = NULL; 9372c204383SJiang Liu 9382c204383SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &info->resources) { 9392c204383SJiang Liu res = entry->res; 9402c204383SJiang Liu if (res->flags & IORESOURCE_MEM) 9412c204383SJiang Liu root = &iomem_resource; 9422c204383SJiang Liu else if (res->flags & IORESOURCE_IO) 9432c204383SJiang Liu root = &ioport_resource; 9442c204383SJiang Liu else 9452c204383SJiang Liu continue; 9462c204383SJiang Liu 947727ae8beSLiu Jiang /* 948727ae8beSLiu Jiang * Some legacy x86 host bridge drivers use iomem_resource and 949727ae8beSLiu Jiang * ioport_resource as default resource pool, skip it. 950727ae8beSLiu Jiang */ 951727ae8beSLiu Jiang if (res == root) 952727ae8beSLiu Jiang continue; 953727ae8beSLiu Jiang 9542c204383SJiang Liu conflict = insert_resource_conflict(root, res); 9552c204383SJiang Liu if (conflict) { 9562c204383SJiang Liu dev_info(&info->bridge->dev, 9572c204383SJiang Liu "ignoring host bridge window %pR (conflicts with %s %pR)\n", 9582c204383SJiang Liu res, conflict->name, conflict); 9592c204383SJiang Liu resource_list_destroy_entry(entry); 9602c204383SJiang Liu } 9612c204383SJiang Liu } 9622c204383SJiang Liu } 9632c204383SJiang Liu 9642c204383SJiang Liu static void __acpi_pci_root_release_info(struct acpi_pci_root_info *info) 9652c204383SJiang Liu { 9662c204383SJiang Liu struct resource *res; 9672c204383SJiang Liu struct resource_entry *entry, *tmp; 9682c204383SJiang Liu 9692c204383SJiang Liu if (!info) 9702c204383SJiang Liu return; 9712c204383SJiang Liu 9722c204383SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &info->resources) { 9732c204383SJiang Liu res = entry->res; 9742c204383SJiang Liu if (res->parent && 9752c204383SJiang Liu (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) 9762c204383SJiang Liu release_resource(res); 9772c204383SJiang Liu resource_list_destroy_entry(entry); 9782c204383SJiang Liu } 9792c204383SJiang Liu 9802c204383SJiang Liu info->ops->release_info(info); 9812c204383SJiang Liu } 9822c204383SJiang Liu 9832c204383SJiang Liu static void acpi_pci_root_release_info(struct pci_host_bridge *bridge) 9842c204383SJiang Liu { 9852c204383SJiang Liu struct resource *res; 9862c204383SJiang Liu struct resource_entry *entry; 9872c204383SJiang Liu 9882c204383SJiang Liu resource_list_for_each_entry(entry, &bridge->windows) { 9892c204383SJiang Liu res = entry->res; 9900a70abb3SJayachandran C if (res->flags & IORESOURCE_IO) 9910a70abb3SJayachandran C pci_unmap_iospace(res); 9922c204383SJiang Liu if (res->parent && 9932c204383SJiang Liu (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) 9942c204383SJiang Liu release_resource(res); 9952c204383SJiang Liu } 9962c204383SJiang Liu __acpi_pci_root_release_info(bridge->release_data); 9972c204383SJiang Liu } 9982c204383SJiang Liu 9992c204383SJiang Liu struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, 10002c204383SJiang Liu struct acpi_pci_root_ops *ops, 10012c204383SJiang Liu struct acpi_pci_root_info *info, 10022c204383SJiang Liu void *sysdata) 10032c204383SJiang Liu { 10042c204383SJiang Liu int ret, busnum = root->secondary.start; 10052c204383SJiang Liu struct acpi_device *device = root->device; 10062c204383SJiang Liu int node = acpi_get_node(device->handle); 10072c204383SJiang Liu struct pci_bus *bus; 100802bfeb48SBjorn Helgaas struct pci_host_bridge *host_bridge; 1009a78cf965SBenjamin Herrenschmidt union acpi_object *obj; 10102c204383SJiang Liu 10112c204383SJiang Liu info->root = root; 10122c204383SJiang Liu info->bridge = device; 10132c204383SJiang Liu info->ops = ops; 10142c204383SJiang Liu INIT_LIST_HEAD(&info->resources); 10152c204383SJiang Liu snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x", 10162c204383SJiang Liu root->segment, busnum); 10172c204383SJiang Liu 10182c204383SJiang Liu if (ops->init_info && ops->init_info(info)) 10192c204383SJiang Liu goto out_release_info; 10202c204383SJiang Liu if (ops->prepare_resources) 10212c204383SJiang Liu ret = ops->prepare_resources(info); 10222c204383SJiang Liu else 10232c204383SJiang Liu ret = acpi_pci_probe_root_resources(info); 10242c204383SJiang Liu if (ret < 0) 10252c204383SJiang Liu goto out_release_info; 10262c204383SJiang Liu 10272c204383SJiang Liu pci_acpi_root_add_resources(info); 10282c204383SJiang Liu pci_add_resource(&info->resources, &root->secondary); 10292c204383SJiang Liu bus = pci_create_root_bus(NULL, busnum, ops->pci_ops, 10302c204383SJiang Liu sysdata, &info->resources); 10312c204383SJiang Liu if (!bus) 10322c204383SJiang Liu goto out_release_info; 10332c204383SJiang Liu 103402bfeb48SBjorn Helgaas host_bridge = to_pci_host_bridge(bus->bridge); 103502bfeb48SBjorn Helgaas if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) 10369310f0dcSMika Westerberg host_bridge->native_pcie_hotplug = 0; 10371df81a6dSMika Westerberg if (!(root->osc_control_set & OSC_PCI_SHPC_NATIVE_HP_CONTROL)) 10381df81a6dSMika Westerberg host_bridge->native_shpc_hotplug = 0; 103902bfeb48SBjorn Helgaas if (!(root->osc_control_set & OSC_PCI_EXPRESS_AER_CONTROL)) 104002bfeb48SBjorn Helgaas host_bridge->native_aer = 0; 104102bfeb48SBjorn Helgaas if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL)) 104202bfeb48SBjorn Helgaas host_bridge->native_pme = 0; 1043af8bb9f8SBjorn Helgaas if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL)) 1044af8bb9f8SBjorn Helgaas host_bridge->native_ltr = 0; 1045ac1c8e35SKuppuswamy Sathyanarayanan if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL)) 1046ac1c8e35SKuppuswamy Sathyanarayanan host_bridge->native_dpc = 0; 104702bfeb48SBjorn Helgaas 1048a78cf965SBenjamin Herrenschmidt /* 1049a78cf965SBenjamin Herrenschmidt * Evaluate the "PCI Boot Configuration" _DSM Function. If it 1050a78cf965SBenjamin Herrenschmidt * exists and returns 0, we must preserve any PCI resource 1051a78cf965SBenjamin Herrenschmidt * assignments made by firmware for this host bridge. 1052a78cf965SBenjamin Herrenschmidt */ 1053a78cf965SBenjamin Herrenschmidt obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, 10543910ebacSKrzysztof Wilczyński DSM_PCI_PRESERVE_BOOT_CONFIG, NULL); 1055a78cf965SBenjamin Herrenschmidt if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0) 1056a78cf965SBenjamin Herrenschmidt host_bridge->preserve_config = 1; 1057a78cf965SBenjamin Herrenschmidt ACPI_FREE(obj); 1058a78cf965SBenjamin Herrenschmidt 105962d52871SRafael J. Wysocki acpi_dev_power_up_children_with_adr(device); 106062d52871SRafael J. Wysocki 10612c204383SJiang Liu pci_scan_child_bus(bus); 106202bfeb48SBjorn Helgaas pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info, 106302bfeb48SBjorn Helgaas info); 10642c204383SJiang Liu if (node != NUMA_NO_NODE) 10652c204383SJiang Liu dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node); 10662c204383SJiang Liu return bus; 10672c204383SJiang Liu 10682c204383SJiang Liu out_release_info: 10692c204383SJiang Liu __acpi_pci_root_release_info(info); 10702c204383SJiang Liu return NULL; 10712c204383SJiang Liu } 10722c204383SJiang Liu 107300c43b96SRafael J. Wysocki void __init acpi_pci_root_init(void) 10741da177e4SLinus Torvalds { 10753338db00SRafael J. Wysocki if (acpi_pci_disabled) 10763338db00SRafael J. Wysocki return; 1077d3072e6aSRafael J. Wysocki 10787bc5e3f2SBjorn Helgaas pci_acpi_crs_quirks(); 10793338db00SRafael J. Wysocki acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root"); 1080668192b6SYinghai Lu } 1081