162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCI support in ACPI 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 David Shaohua Li <shaohua.li@intel.com> 662306a36Sopenharmony_ci * Copyright (C) 2004 Tom Long Nguyen <tom.l.nguyen@intel.com> 762306a36Sopenharmony_ci * Copyright (C) 2004 Intel Corp. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/irqdomain.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/msi.h> 1562306a36Sopenharmony_ci#include <linux/pci_hotplug.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/pci-acpi.h> 1862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1962306a36Sopenharmony_ci#include <linux/pm_qos.h> 2062306a36Sopenharmony_ci#include <linux/rwsem.h> 2162306a36Sopenharmony_ci#include "pci.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * The GUID is defined in the PCI Firmware Specification available 2562306a36Sopenharmony_ci * here to PCI-SIG members: 2662306a36Sopenharmony_ci * https://members.pcisig.com/wg/PCI-SIG/document/15350 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ciconst guid_t pci_acpi_dsm_guid = 2962306a36Sopenharmony_ci GUID_INIT(0xe5c937d0, 0x3553, 0x4d7a, 3062306a36Sopenharmony_ci 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64) 3362306a36Sopenharmony_cistatic int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct device *dev = &adev->dev; 3662306a36Sopenharmony_ci struct resource_entry *entry; 3762306a36Sopenharmony_ci struct list_head list; 3862306a36Sopenharmony_ci unsigned long flags; 3962306a36Sopenharmony_ci int ret; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci INIT_LIST_HEAD(&list); 4262306a36Sopenharmony_ci flags = IORESOURCE_MEM; 4362306a36Sopenharmony_ci ret = acpi_dev_get_resources(adev, &list, 4462306a36Sopenharmony_ci acpi_dev_filter_resource_type_cb, 4562306a36Sopenharmony_ci (void *) flags); 4662306a36Sopenharmony_ci if (ret < 0) { 4762306a36Sopenharmony_ci dev_err(dev, "failed to parse _CRS method, error code %d\n", 4862306a36Sopenharmony_ci ret); 4962306a36Sopenharmony_ci return ret; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (ret == 0) { 5362306a36Sopenharmony_ci dev_err(dev, "no IO and memory resources present in _CRS\n"); 5462306a36Sopenharmony_ci return -EINVAL; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci entry = list_first_entry(&list, struct resource_entry, node); 5862306a36Sopenharmony_ci *res = *entry->res; 5962306a36Sopenharmony_ci acpi_dev_free_resource_list(&list); 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic acpi_status acpi_match_rc(acpi_handle handle, u32 lvl, void *context, 6462306a36Sopenharmony_ci void **retval) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci u16 *segment = context; 6762306a36Sopenharmony_ci unsigned long long uid; 6862306a36Sopenharmony_ci acpi_status status; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid); 7162306a36Sopenharmony_ci if (ACPI_FAILURE(status) || uid != *segment) 7262306a36Sopenharmony_ci return AE_CTRL_DEPTH; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci *(acpi_handle *)retval = handle; 7562306a36Sopenharmony_ci return AE_CTRL_TERMINATE; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciint acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment, 7962306a36Sopenharmony_ci struct resource *res) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct acpi_device *adev; 8262306a36Sopenharmony_ci acpi_status status; 8362306a36Sopenharmony_ci acpi_handle handle; 8462306a36Sopenharmony_ci int ret; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci status = acpi_get_devices(hid, acpi_match_rc, &segment, &handle); 8762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 8862306a36Sopenharmony_ci dev_err(dev, "can't find _HID %s device to locate resources\n", 8962306a36Sopenharmony_ci hid); 9062306a36Sopenharmony_ci return -ENODEV; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci adev = acpi_fetch_acpi_dev(handle); 9462306a36Sopenharmony_ci if (!adev) 9562306a36Sopenharmony_ci return -ENODEV; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci ret = acpi_get_rc_addr(adev, res); 9862306a36Sopenharmony_ci if (ret) { 9962306a36Sopenharmony_ci dev_err(dev, "can't get resource from %s\n", 10062306a36Sopenharmony_ci dev_name(&adev->dev)); 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci#endif 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciphys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci acpi_status status = AE_NOT_EXIST; 11162306a36Sopenharmony_ci unsigned long long mcfg_addr; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (handle) 11462306a36Sopenharmony_ci status = acpi_evaluate_integer(handle, METHOD_NAME__CBA, 11562306a36Sopenharmony_ci NULL, &mcfg_addr); 11662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return (phys_addr_t)mcfg_addr; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* _HPX PCI Setting Record (Type 0); same as _HPP */ 12362306a36Sopenharmony_cistruct hpx_type0 { 12462306a36Sopenharmony_ci u32 revision; /* Not present in _HPP */ 12562306a36Sopenharmony_ci u8 cache_line_size; /* Not applicable to PCIe */ 12662306a36Sopenharmony_ci u8 latency_timer; /* Not applicable to PCIe */ 12762306a36Sopenharmony_ci u8 enable_serr; 12862306a36Sopenharmony_ci u8 enable_perr; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic struct hpx_type0 pci_default_type0 = { 13262306a36Sopenharmony_ci .revision = 1, 13362306a36Sopenharmony_ci .cache_line_size = 8, 13462306a36Sopenharmony_ci .latency_timer = 0x40, 13562306a36Sopenharmony_ci .enable_serr = 0, 13662306a36Sopenharmony_ci .enable_perr = 0, 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void program_hpx_type0(struct pci_dev *dev, struct hpx_type0 *hpx) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u16 pci_cmd, pci_bctl; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!hpx) 14462306a36Sopenharmony_ci hpx = &pci_default_type0; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (hpx->revision > 1) { 14762306a36Sopenharmony_ci pci_warn(dev, "PCI settings rev %d not supported; using defaults\n", 14862306a36Sopenharmony_ci hpx->revision); 14962306a36Sopenharmony_ci hpx = &pci_default_type0; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpx->cache_line_size); 15362306a36Sopenharmony_ci pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpx->latency_timer); 15462306a36Sopenharmony_ci pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); 15562306a36Sopenharmony_ci if (hpx->enable_serr) 15662306a36Sopenharmony_ci pci_cmd |= PCI_COMMAND_SERR; 15762306a36Sopenharmony_ci if (hpx->enable_perr) 15862306a36Sopenharmony_ci pci_cmd |= PCI_COMMAND_PARITY; 15962306a36Sopenharmony_ci pci_write_config_word(dev, PCI_COMMAND, pci_cmd); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Program bridge control value */ 16262306a36Sopenharmony_ci if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 16362306a36Sopenharmony_ci pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 16462306a36Sopenharmony_ci hpx->latency_timer); 16562306a36Sopenharmony_ci pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); 16662306a36Sopenharmony_ci if (hpx->enable_perr) 16762306a36Sopenharmony_ci pci_bctl |= PCI_BRIDGE_CTL_PARITY; 16862306a36Sopenharmony_ci pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic acpi_status decode_type0_hpx_record(union acpi_object *record, 17362306a36Sopenharmony_ci struct hpx_type0 *hpx0) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci int i; 17662306a36Sopenharmony_ci union acpi_object *fields = record->package.elements; 17762306a36Sopenharmony_ci u32 revision = fields[1].integer.value; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci switch (revision) { 18062306a36Sopenharmony_ci case 1: 18162306a36Sopenharmony_ci if (record->package.count != 6) 18262306a36Sopenharmony_ci return AE_ERROR; 18362306a36Sopenharmony_ci for (i = 2; i < 6; i++) 18462306a36Sopenharmony_ci if (fields[i].type != ACPI_TYPE_INTEGER) 18562306a36Sopenharmony_ci return AE_ERROR; 18662306a36Sopenharmony_ci hpx0->revision = revision; 18762306a36Sopenharmony_ci hpx0->cache_line_size = fields[2].integer.value; 18862306a36Sopenharmony_ci hpx0->latency_timer = fields[3].integer.value; 18962306a36Sopenharmony_ci hpx0->enable_serr = fields[4].integer.value; 19062306a36Sopenharmony_ci hpx0->enable_perr = fields[5].integer.value; 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci default: 19362306a36Sopenharmony_ci pr_warn("%s: Type 0 Revision %d record not supported\n", 19462306a36Sopenharmony_ci __func__, revision); 19562306a36Sopenharmony_ci return AE_ERROR; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci return AE_OK; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* _HPX PCI-X Setting Record (Type 1) */ 20162306a36Sopenharmony_cistruct hpx_type1 { 20262306a36Sopenharmony_ci u32 revision; 20362306a36Sopenharmony_ci u8 max_mem_read; 20462306a36Sopenharmony_ci u8 avg_max_split; 20562306a36Sopenharmony_ci u16 tot_max_split; 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void program_hpx_type1(struct pci_dev *dev, struct hpx_type1 *hpx) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int pos; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!hpx) 21362306a36Sopenharmony_ci return; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); 21662306a36Sopenharmony_ci if (!pos) 21762306a36Sopenharmony_ci return; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci pci_warn(dev, "PCI-X settings not supported\n"); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic acpi_status decode_type1_hpx_record(union acpi_object *record, 22362306a36Sopenharmony_ci struct hpx_type1 *hpx1) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci int i; 22662306a36Sopenharmony_ci union acpi_object *fields = record->package.elements; 22762306a36Sopenharmony_ci u32 revision = fields[1].integer.value; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci switch (revision) { 23062306a36Sopenharmony_ci case 1: 23162306a36Sopenharmony_ci if (record->package.count != 5) 23262306a36Sopenharmony_ci return AE_ERROR; 23362306a36Sopenharmony_ci for (i = 2; i < 5; i++) 23462306a36Sopenharmony_ci if (fields[i].type != ACPI_TYPE_INTEGER) 23562306a36Sopenharmony_ci return AE_ERROR; 23662306a36Sopenharmony_ci hpx1->revision = revision; 23762306a36Sopenharmony_ci hpx1->max_mem_read = fields[2].integer.value; 23862306a36Sopenharmony_ci hpx1->avg_max_split = fields[3].integer.value; 23962306a36Sopenharmony_ci hpx1->tot_max_split = fields[4].integer.value; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci default: 24262306a36Sopenharmony_ci pr_warn("%s: Type 1 Revision %d record not supported\n", 24362306a36Sopenharmony_ci __func__, revision); 24462306a36Sopenharmony_ci return AE_ERROR; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci return AE_OK; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic bool pcie_root_rcb_set(struct pci_dev *dev) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct pci_dev *rp = pcie_find_root_port(dev); 25262306a36Sopenharmony_ci u16 lnkctl; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (!rp) 25562306a36Sopenharmony_ci return false; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl); 25862306a36Sopenharmony_ci if (lnkctl & PCI_EXP_LNKCTL_RCB) 25962306a36Sopenharmony_ci return true; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return false; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* _HPX PCI Express Setting Record (Type 2) */ 26562306a36Sopenharmony_cistruct hpx_type2 { 26662306a36Sopenharmony_ci u32 revision; 26762306a36Sopenharmony_ci u32 unc_err_mask_and; 26862306a36Sopenharmony_ci u32 unc_err_mask_or; 26962306a36Sopenharmony_ci u32 unc_err_sever_and; 27062306a36Sopenharmony_ci u32 unc_err_sever_or; 27162306a36Sopenharmony_ci u32 cor_err_mask_and; 27262306a36Sopenharmony_ci u32 cor_err_mask_or; 27362306a36Sopenharmony_ci u32 adv_err_cap_and; 27462306a36Sopenharmony_ci u32 adv_err_cap_or; 27562306a36Sopenharmony_ci u16 pci_exp_devctl_and; 27662306a36Sopenharmony_ci u16 pci_exp_devctl_or; 27762306a36Sopenharmony_ci u16 pci_exp_lnkctl_and; 27862306a36Sopenharmony_ci u16 pci_exp_lnkctl_or; 27962306a36Sopenharmony_ci u32 sec_unc_err_sever_and; 28062306a36Sopenharmony_ci u32 sec_unc_err_sever_or; 28162306a36Sopenharmony_ci u32 sec_unc_err_mask_and; 28262306a36Sopenharmony_ci u32 sec_unc_err_mask_or; 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int pos; 28862306a36Sopenharmony_ci u32 reg32; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!hpx) 29162306a36Sopenharmony_ci return; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (!pci_is_pcie(dev)) 29462306a36Sopenharmony_ci return; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (hpx->revision > 1) { 29762306a36Sopenharmony_ci pci_warn(dev, "PCIe settings rev %d not supported\n", 29862306a36Sopenharmony_ci hpx->revision); 29962306a36Sopenharmony_ci return; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* 30362306a36Sopenharmony_ci * Don't allow _HPX to change MPS or MRRS settings. We manage 30462306a36Sopenharmony_ci * those to make sure they're consistent with the rest of the 30562306a36Sopenharmony_ci * platform. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD | 30862306a36Sopenharmony_ci PCI_EXP_DEVCTL_READRQ; 30962306a36Sopenharmony_ci hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD | 31062306a36Sopenharmony_ci PCI_EXP_DEVCTL_READRQ); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Initialize Device Control Register */ 31362306a36Sopenharmony_ci pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, 31462306a36Sopenharmony_ci ~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Initialize Link Control Register */ 31762306a36Sopenharmony_ci if (pcie_cap_has_lnkctl(dev)) { 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * If the Root Port supports Read Completion Boundary of 32162306a36Sopenharmony_ci * 128, set RCB to 128. Otherwise, clear it. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB; 32462306a36Sopenharmony_ci hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB; 32562306a36Sopenharmony_ci if (pcie_root_rcb_set(dev)) 32662306a36Sopenharmony_ci hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, 32962306a36Sopenharmony_ci ~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Find Advanced Error Reporting Enhanced Capability */ 33362306a36Sopenharmony_ci pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 33462306a36Sopenharmony_ci if (!pos) 33562306a36Sopenharmony_ci return; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Initialize Uncorrectable Error Mask Register */ 33862306a36Sopenharmony_ci pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); 33962306a36Sopenharmony_ci reg32 = (reg32 & hpx->unc_err_mask_and) | hpx->unc_err_mask_or; 34062306a36Sopenharmony_ci pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Initialize Uncorrectable Error Severity Register */ 34362306a36Sopenharmony_ci pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); 34462306a36Sopenharmony_ci reg32 = (reg32 & hpx->unc_err_sever_and) | hpx->unc_err_sever_or; 34562306a36Sopenharmony_ci pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* Initialize Correctable Error Mask Register */ 34862306a36Sopenharmony_ci pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); 34962306a36Sopenharmony_ci reg32 = (reg32 & hpx->cor_err_mask_and) | hpx->cor_err_mask_or; 35062306a36Sopenharmony_ci pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Initialize Advanced Error Capabilities and Control Register */ 35362306a36Sopenharmony_ci pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); 35462306a36Sopenharmony_ci reg32 = (reg32 & hpx->adv_err_cap_and) | hpx->adv_err_cap_or; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Don't enable ECRC generation or checking if unsupported */ 35762306a36Sopenharmony_ci if (!(reg32 & PCI_ERR_CAP_ECRC_GENC)) 35862306a36Sopenharmony_ci reg32 &= ~PCI_ERR_CAP_ECRC_GENE; 35962306a36Sopenharmony_ci if (!(reg32 & PCI_ERR_CAP_ECRC_CHKC)) 36062306a36Sopenharmony_ci reg32 &= ~PCI_ERR_CAP_ECRC_CHKE; 36162306a36Sopenharmony_ci pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * FIXME: The following two registers are not supported yet. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * o Secondary Uncorrectable Error Severity Register 36762306a36Sopenharmony_ci * o Secondary Uncorrectable Error Mask Register 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic acpi_status decode_type2_hpx_record(union acpi_object *record, 37262306a36Sopenharmony_ci struct hpx_type2 *hpx2) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci int i; 37562306a36Sopenharmony_ci union acpi_object *fields = record->package.elements; 37662306a36Sopenharmony_ci u32 revision = fields[1].integer.value; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci switch (revision) { 37962306a36Sopenharmony_ci case 1: 38062306a36Sopenharmony_ci if (record->package.count != 18) 38162306a36Sopenharmony_ci return AE_ERROR; 38262306a36Sopenharmony_ci for (i = 2; i < 18; i++) 38362306a36Sopenharmony_ci if (fields[i].type != ACPI_TYPE_INTEGER) 38462306a36Sopenharmony_ci return AE_ERROR; 38562306a36Sopenharmony_ci hpx2->revision = revision; 38662306a36Sopenharmony_ci hpx2->unc_err_mask_and = fields[2].integer.value; 38762306a36Sopenharmony_ci hpx2->unc_err_mask_or = fields[3].integer.value; 38862306a36Sopenharmony_ci hpx2->unc_err_sever_and = fields[4].integer.value; 38962306a36Sopenharmony_ci hpx2->unc_err_sever_or = fields[5].integer.value; 39062306a36Sopenharmony_ci hpx2->cor_err_mask_and = fields[6].integer.value; 39162306a36Sopenharmony_ci hpx2->cor_err_mask_or = fields[7].integer.value; 39262306a36Sopenharmony_ci hpx2->adv_err_cap_and = fields[8].integer.value; 39362306a36Sopenharmony_ci hpx2->adv_err_cap_or = fields[9].integer.value; 39462306a36Sopenharmony_ci hpx2->pci_exp_devctl_and = fields[10].integer.value; 39562306a36Sopenharmony_ci hpx2->pci_exp_devctl_or = fields[11].integer.value; 39662306a36Sopenharmony_ci hpx2->pci_exp_lnkctl_and = fields[12].integer.value; 39762306a36Sopenharmony_ci hpx2->pci_exp_lnkctl_or = fields[13].integer.value; 39862306a36Sopenharmony_ci hpx2->sec_unc_err_sever_and = fields[14].integer.value; 39962306a36Sopenharmony_ci hpx2->sec_unc_err_sever_or = fields[15].integer.value; 40062306a36Sopenharmony_ci hpx2->sec_unc_err_mask_and = fields[16].integer.value; 40162306a36Sopenharmony_ci hpx2->sec_unc_err_mask_or = fields[17].integer.value; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci default: 40462306a36Sopenharmony_ci pr_warn("%s: Type 2 Revision %d record not supported\n", 40562306a36Sopenharmony_ci __func__, revision); 40662306a36Sopenharmony_ci return AE_ERROR; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci return AE_OK; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/* _HPX PCI Express Setting Record (Type 3) */ 41262306a36Sopenharmony_cistruct hpx_type3 { 41362306a36Sopenharmony_ci u16 device_type; 41462306a36Sopenharmony_ci u16 function_type; 41562306a36Sopenharmony_ci u16 config_space_location; 41662306a36Sopenharmony_ci u16 pci_exp_cap_id; 41762306a36Sopenharmony_ci u16 pci_exp_cap_ver; 41862306a36Sopenharmony_ci u16 pci_exp_vendor_id; 41962306a36Sopenharmony_ci u16 dvsec_id; 42062306a36Sopenharmony_ci u16 dvsec_rev; 42162306a36Sopenharmony_ci u16 match_offset; 42262306a36Sopenharmony_ci u32 match_mask_and; 42362306a36Sopenharmony_ci u32 match_value; 42462306a36Sopenharmony_ci u16 reg_offset; 42562306a36Sopenharmony_ci u32 reg_mask_and; 42662306a36Sopenharmony_ci u32 reg_mask_or; 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cienum hpx_type3_dev_type { 43062306a36Sopenharmony_ci HPX_TYPE_ENDPOINT = BIT(0), 43162306a36Sopenharmony_ci HPX_TYPE_LEG_END = BIT(1), 43262306a36Sopenharmony_ci HPX_TYPE_RC_END = BIT(2), 43362306a36Sopenharmony_ci HPX_TYPE_RC_EC = BIT(3), 43462306a36Sopenharmony_ci HPX_TYPE_ROOT_PORT = BIT(4), 43562306a36Sopenharmony_ci HPX_TYPE_UPSTREAM = BIT(5), 43662306a36Sopenharmony_ci HPX_TYPE_DOWNSTREAM = BIT(6), 43762306a36Sopenharmony_ci HPX_TYPE_PCI_BRIDGE = BIT(7), 43862306a36Sopenharmony_ci HPX_TYPE_PCIE_BRIDGE = BIT(8), 43962306a36Sopenharmony_ci}; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic u16 hpx3_device_type(struct pci_dev *dev) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci u16 pcie_type = pci_pcie_type(dev); 44462306a36Sopenharmony_ci static const int pcie_to_hpx3_type[] = { 44562306a36Sopenharmony_ci [PCI_EXP_TYPE_ENDPOINT] = HPX_TYPE_ENDPOINT, 44662306a36Sopenharmony_ci [PCI_EXP_TYPE_LEG_END] = HPX_TYPE_LEG_END, 44762306a36Sopenharmony_ci [PCI_EXP_TYPE_RC_END] = HPX_TYPE_RC_END, 44862306a36Sopenharmony_ci [PCI_EXP_TYPE_RC_EC] = HPX_TYPE_RC_EC, 44962306a36Sopenharmony_ci [PCI_EXP_TYPE_ROOT_PORT] = HPX_TYPE_ROOT_PORT, 45062306a36Sopenharmony_ci [PCI_EXP_TYPE_UPSTREAM] = HPX_TYPE_UPSTREAM, 45162306a36Sopenharmony_ci [PCI_EXP_TYPE_DOWNSTREAM] = HPX_TYPE_DOWNSTREAM, 45262306a36Sopenharmony_ci [PCI_EXP_TYPE_PCI_BRIDGE] = HPX_TYPE_PCI_BRIDGE, 45362306a36Sopenharmony_ci [PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE, 45462306a36Sopenharmony_ci }; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type)) 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return pcie_to_hpx3_type[pcie_type]; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cienum hpx_type3_fn_type { 46362306a36Sopenharmony_ci HPX_FN_NORMAL = BIT(0), 46462306a36Sopenharmony_ci HPX_FN_SRIOV_PHYS = BIT(1), 46562306a36Sopenharmony_ci HPX_FN_SRIOV_VIRT = BIT(2), 46662306a36Sopenharmony_ci}; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic u8 hpx3_function_type(struct pci_dev *dev) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci if (dev->is_virtfn) 47162306a36Sopenharmony_ci return HPX_FN_SRIOV_VIRT; 47262306a36Sopenharmony_ci else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0) 47362306a36Sopenharmony_ci return HPX_FN_SRIOV_PHYS; 47462306a36Sopenharmony_ci else 47562306a36Sopenharmony_ci return HPX_FN_NORMAL; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci u8 cap_ver = hpx3_cap_id & 0xf; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id) 48362306a36Sopenharmony_ci return true; 48462306a36Sopenharmony_ci else if (cap_ver == pcie_cap_id) 48562306a36Sopenharmony_ci return true; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return false; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cienum hpx_type3_cfg_loc { 49162306a36Sopenharmony_ci HPX_CFG_PCICFG = 0, 49262306a36Sopenharmony_ci HPX_CFG_PCIE_CAP = 1, 49362306a36Sopenharmony_ci HPX_CFG_PCIE_CAP_EXT = 2, 49462306a36Sopenharmony_ci HPX_CFG_VEND_CAP = 3, 49562306a36Sopenharmony_ci HPX_CFG_DVSEC = 4, 49662306a36Sopenharmony_ci HPX_CFG_MAX, 49762306a36Sopenharmony_ci}; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void program_hpx_type3_register(struct pci_dev *dev, 50062306a36Sopenharmony_ci const struct hpx_type3 *reg) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci u32 match_reg, write_reg, header, orig_value; 50362306a36Sopenharmony_ci u16 pos; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (!(hpx3_device_type(dev) & reg->device_type)) 50662306a36Sopenharmony_ci return; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!(hpx3_function_type(dev) & reg->function_type)) 50962306a36Sopenharmony_ci return; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci switch (reg->config_space_location) { 51262306a36Sopenharmony_ci case HPX_CFG_PCICFG: 51362306a36Sopenharmony_ci pos = 0; 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci case HPX_CFG_PCIE_CAP: 51662306a36Sopenharmony_ci pos = pci_find_capability(dev, reg->pci_exp_cap_id); 51762306a36Sopenharmony_ci if (pos == 0) 51862306a36Sopenharmony_ci return; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci case HPX_CFG_PCIE_CAP_EXT: 52262306a36Sopenharmony_ci pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id); 52362306a36Sopenharmony_ci if (pos == 0) 52462306a36Sopenharmony_ci return; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci pci_read_config_dword(dev, pos, &header); 52762306a36Sopenharmony_ci if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header), 52862306a36Sopenharmony_ci reg->pci_exp_cap_ver)) 52962306a36Sopenharmony_ci return; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case HPX_CFG_VEND_CAP: 53362306a36Sopenharmony_ci case HPX_CFG_DVSEC: 53462306a36Sopenharmony_ci default: 53562306a36Sopenharmony_ci pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location"); 53662306a36Sopenharmony_ci return; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci pci_read_config_dword(dev, pos + reg->match_offset, &match_reg); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if ((match_reg & reg->match_mask_and) != reg->match_value) 54262306a36Sopenharmony_ci return; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg); 54562306a36Sopenharmony_ci orig_value = write_reg; 54662306a36Sopenharmony_ci write_reg &= reg->reg_mask_and; 54762306a36Sopenharmony_ci write_reg |= reg->reg_mask_or; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (orig_value == write_reg) 55062306a36Sopenharmony_ci return; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci pci_write_config_dword(dev, pos + reg->reg_offset, write_reg); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x", 55562306a36Sopenharmony_ci pos, orig_value, write_reg); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci if (!hpx) 56162306a36Sopenharmony_ci return; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (!pci_is_pcie(dev)) 56462306a36Sopenharmony_ci return; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci program_hpx_type3_register(dev, hpx); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic void parse_hpx3_register(struct hpx_type3 *hpx3_reg, 57062306a36Sopenharmony_ci union acpi_object *reg_fields) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci hpx3_reg->device_type = reg_fields[0].integer.value; 57362306a36Sopenharmony_ci hpx3_reg->function_type = reg_fields[1].integer.value; 57462306a36Sopenharmony_ci hpx3_reg->config_space_location = reg_fields[2].integer.value; 57562306a36Sopenharmony_ci hpx3_reg->pci_exp_cap_id = reg_fields[3].integer.value; 57662306a36Sopenharmony_ci hpx3_reg->pci_exp_cap_ver = reg_fields[4].integer.value; 57762306a36Sopenharmony_ci hpx3_reg->pci_exp_vendor_id = reg_fields[5].integer.value; 57862306a36Sopenharmony_ci hpx3_reg->dvsec_id = reg_fields[6].integer.value; 57962306a36Sopenharmony_ci hpx3_reg->dvsec_rev = reg_fields[7].integer.value; 58062306a36Sopenharmony_ci hpx3_reg->match_offset = reg_fields[8].integer.value; 58162306a36Sopenharmony_ci hpx3_reg->match_mask_and = reg_fields[9].integer.value; 58262306a36Sopenharmony_ci hpx3_reg->match_value = reg_fields[10].integer.value; 58362306a36Sopenharmony_ci hpx3_reg->reg_offset = reg_fields[11].integer.value; 58462306a36Sopenharmony_ci hpx3_reg->reg_mask_and = reg_fields[12].integer.value; 58562306a36Sopenharmony_ci hpx3_reg->reg_mask_or = reg_fields[13].integer.value; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic acpi_status program_type3_hpx_record(struct pci_dev *dev, 58962306a36Sopenharmony_ci union acpi_object *record) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci union acpi_object *fields = record->package.elements; 59262306a36Sopenharmony_ci u32 desc_count, expected_length, revision; 59362306a36Sopenharmony_ci union acpi_object *reg_fields; 59462306a36Sopenharmony_ci struct hpx_type3 hpx3; 59562306a36Sopenharmony_ci int i; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci revision = fields[1].integer.value; 59862306a36Sopenharmony_ci switch (revision) { 59962306a36Sopenharmony_ci case 1: 60062306a36Sopenharmony_ci desc_count = fields[2].integer.value; 60162306a36Sopenharmony_ci expected_length = 3 + desc_count * 14; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (record->package.count != expected_length) 60462306a36Sopenharmony_ci return AE_ERROR; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci for (i = 2; i < expected_length; i++) 60762306a36Sopenharmony_ci if (fields[i].type != ACPI_TYPE_INTEGER) 60862306a36Sopenharmony_ci return AE_ERROR; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci for (i = 0; i < desc_count; i++) { 61162306a36Sopenharmony_ci reg_fields = fields + 3 + i * 14; 61262306a36Sopenharmony_ci parse_hpx3_register(&hpx3, reg_fields); 61362306a36Sopenharmony_ci program_hpx_type3(dev, &hpx3); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci default: 61862306a36Sopenharmony_ci printk(KERN_WARNING 61962306a36Sopenharmony_ci "%s: Type 3 Revision %d record not supported\n", 62062306a36Sopenharmony_ci __func__, revision); 62162306a36Sopenharmony_ci return AE_ERROR; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci return AE_OK; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci acpi_status status; 62962306a36Sopenharmony_ci struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 63062306a36Sopenharmony_ci union acpi_object *package, *record, *fields; 63162306a36Sopenharmony_ci struct hpx_type0 hpx0; 63262306a36Sopenharmony_ci struct hpx_type1 hpx1; 63362306a36Sopenharmony_ci struct hpx_type2 hpx2; 63462306a36Sopenharmony_ci u32 type; 63562306a36Sopenharmony_ci int i; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); 63862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 63962306a36Sopenharmony_ci return status; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci package = (union acpi_object *)buffer.pointer; 64262306a36Sopenharmony_ci if (package->type != ACPI_TYPE_PACKAGE) { 64362306a36Sopenharmony_ci status = AE_ERROR; 64462306a36Sopenharmony_ci goto exit; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci for (i = 0; i < package->package.count; i++) { 64862306a36Sopenharmony_ci record = &package->package.elements[i]; 64962306a36Sopenharmony_ci if (record->type != ACPI_TYPE_PACKAGE) { 65062306a36Sopenharmony_ci status = AE_ERROR; 65162306a36Sopenharmony_ci goto exit; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci fields = record->package.elements; 65562306a36Sopenharmony_ci if (fields[0].type != ACPI_TYPE_INTEGER || 65662306a36Sopenharmony_ci fields[1].type != ACPI_TYPE_INTEGER) { 65762306a36Sopenharmony_ci status = AE_ERROR; 65862306a36Sopenharmony_ci goto exit; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci type = fields[0].integer.value; 66262306a36Sopenharmony_ci switch (type) { 66362306a36Sopenharmony_ci case 0: 66462306a36Sopenharmony_ci memset(&hpx0, 0, sizeof(hpx0)); 66562306a36Sopenharmony_ci status = decode_type0_hpx_record(record, &hpx0); 66662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 66762306a36Sopenharmony_ci goto exit; 66862306a36Sopenharmony_ci program_hpx_type0(dev, &hpx0); 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci case 1: 67162306a36Sopenharmony_ci memset(&hpx1, 0, sizeof(hpx1)); 67262306a36Sopenharmony_ci status = decode_type1_hpx_record(record, &hpx1); 67362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 67462306a36Sopenharmony_ci goto exit; 67562306a36Sopenharmony_ci program_hpx_type1(dev, &hpx1); 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci case 2: 67862306a36Sopenharmony_ci memset(&hpx2, 0, sizeof(hpx2)); 67962306a36Sopenharmony_ci status = decode_type2_hpx_record(record, &hpx2); 68062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 68162306a36Sopenharmony_ci goto exit; 68262306a36Sopenharmony_ci program_hpx_type2(dev, &hpx2); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case 3: 68562306a36Sopenharmony_ci status = program_type3_hpx_record(dev, record); 68662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 68762306a36Sopenharmony_ci goto exit; 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci default: 69062306a36Sopenharmony_ci pr_err("%s: Type %d record not supported\n", 69162306a36Sopenharmony_ci __func__, type); 69262306a36Sopenharmony_ci status = AE_ERROR; 69362306a36Sopenharmony_ci goto exit; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci exit: 69762306a36Sopenharmony_ci kfree(buffer.pointer); 69862306a36Sopenharmony_ci return status; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci acpi_status status; 70462306a36Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 70562306a36Sopenharmony_ci union acpi_object *package, *fields; 70662306a36Sopenharmony_ci struct hpx_type0 hpx0; 70762306a36Sopenharmony_ci int i; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci memset(&hpx0, 0, sizeof(hpx0)); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer); 71262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 71362306a36Sopenharmony_ci return status; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci package = (union acpi_object *) buffer.pointer; 71662306a36Sopenharmony_ci if (package->type != ACPI_TYPE_PACKAGE || 71762306a36Sopenharmony_ci package->package.count != 4) { 71862306a36Sopenharmony_ci status = AE_ERROR; 71962306a36Sopenharmony_ci goto exit; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci fields = package->package.elements; 72362306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 72462306a36Sopenharmony_ci if (fields[i].type != ACPI_TYPE_INTEGER) { 72562306a36Sopenharmony_ci status = AE_ERROR; 72662306a36Sopenharmony_ci goto exit; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci hpx0.revision = 1; 73162306a36Sopenharmony_ci hpx0.cache_line_size = fields[0].integer.value; 73262306a36Sopenharmony_ci hpx0.latency_timer = fields[1].integer.value; 73362306a36Sopenharmony_ci hpx0.enable_serr = fields[2].integer.value; 73462306a36Sopenharmony_ci hpx0.enable_perr = fields[3].integer.value; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci program_hpx_type0(dev, &hpx0); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ciexit: 73962306a36Sopenharmony_ci kfree(buffer.pointer); 74062306a36Sopenharmony_ci return status; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci/* pci_acpi_program_hp_params 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * @dev - the pci_dev for which we want parameters 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_ciint pci_acpi_program_hp_params(struct pci_dev *dev) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci acpi_status status; 75062306a36Sopenharmony_ci acpi_handle handle, phandle; 75162306a36Sopenharmony_ci struct pci_bus *pbus; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (acpi_pci_disabled) 75462306a36Sopenharmony_ci return -ENODEV; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci handle = NULL; 75762306a36Sopenharmony_ci for (pbus = dev->bus; pbus; pbus = pbus->parent) { 75862306a36Sopenharmony_ci handle = acpi_pci_get_bridge_handle(pbus); 75962306a36Sopenharmony_ci if (handle) 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* 76462306a36Sopenharmony_ci * _HPP settings apply to all child buses, until another _HPP is 76562306a36Sopenharmony_ci * encountered. If we don't find an _HPP for the input pci dev, 76662306a36Sopenharmony_ci * look for it in the parent device scope since that would apply to 76762306a36Sopenharmony_ci * this pci dev. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci while (handle) { 77062306a36Sopenharmony_ci status = acpi_run_hpx(dev, handle); 77162306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) 77262306a36Sopenharmony_ci return 0; 77362306a36Sopenharmony_ci status = acpi_run_hpp(dev, handle); 77462306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) 77562306a36Sopenharmony_ci return 0; 77662306a36Sopenharmony_ci if (acpi_is_root_bridge(handle)) 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci status = acpi_get_parent(handle, &phandle); 77962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci handle = phandle; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci return -ENODEV; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/** 78762306a36Sopenharmony_ci * pciehp_is_native - Check whether a hotplug port is handled by the OS 78862306a36Sopenharmony_ci * @bridge: Hotplug port to check 78962306a36Sopenharmony_ci * 79062306a36Sopenharmony_ci * Returns true if the given @bridge is handled by the native PCIe hotplug 79162306a36Sopenharmony_ci * driver. 79262306a36Sopenharmony_ci */ 79362306a36Sopenharmony_cibool pciehp_is_native(struct pci_dev *bridge) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci const struct pci_host_bridge *host; 79662306a36Sopenharmony_ci u32 slot_cap; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) 79962306a36Sopenharmony_ci return false; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap); 80262306a36Sopenharmony_ci if (!(slot_cap & PCI_EXP_SLTCAP_HPC)) 80362306a36Sopenharmony_ci return false; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (pcie_ports_native) 80662306a36Sopenharmony_ci return true; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci host = pci_find_host_bridge(bridge->bus); 80962306a36Sopenharmony_ci return host->native_pcie_hotplug; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci/** 81362306a36Sopenharmony_ci * shpchp_is_native - Check whether a hotplug port is handled by the OS 81462306a36Sopenharmony_ci * @bridge: Hotplug port to check 81562306a36Sopenharmony_ci * 81662306a36Sopenharmony_ci * Returns true if the given @bridge is handled by the native SHPC hotplug 81762306a36Sopenharmony_ci * driver. 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_cibool shpchp_is_native(struct pci_dev *bridge) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci return bridge->shpc_managed; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci/** 82562306a36Sopenharmony_ci * pci_acpi_wake_bus - Root bus wakeup notification fork function. 82662306a36Sopenharmony_ci * @context: Device wakeup context. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_cistatic void pci_acpi_wake_bus(struct acpi_device_wakeup_context *context) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct acpi_device *adev; 83162306a36Sopenharmony_ci struct acpi_pci_root *root; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci adev = container_of(context, struct acpi_device, wakeup.context); 83462306a36Sopenharmony_ci root = acpi_driver_data(adev); 83562306a36Sopenharmony_ci pci_pme_wakeup_bus(root->bus); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/** 83962306a36Sopenharmony_ci * pci_acpi_wake_dev - PCI device wakeup notification work function. 84062306a36Sopenharmony_ci * @context: Device wakeup context. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_cistatic void pci_acpi_wake_dev(struct acpi_device_wakeup_context *context) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct pci_dev *pci_dev; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci pci_dev = to_pci_dev(context->dev); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (pci_dev->pme_poll) 84962306a36Sopenharmony_ci pci_dev->pme_poll = false; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (pci_dev->current_state == PCI_D3cold) { 85262306a36Sopenharmony_ci pci_wakeup_event(pci_dev); 85362306a36Sopenharmony_ci pm_request_resume(&pci_dev->dev); 85462306a36Sopenharmony_ci return; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Clear PME Status if set. */ 85862306a36Sopenharmony_ci if (pci_dev->pme_support) 85962306a36Sopenharmony_ci pci_check_pme_status(pci_dev); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci pci_wakeup_event(pci_dev); 86262306a36Sopenharmony_ci pm_request_resume(&pci_dev->dev); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci pci_pme_wakeup_bus(pci_dev->subordinate); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci/** 86862306a36Sopenharmony_ci * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus. 86962306a36Sopenharmony_ci * @dev: PCI root bridge ACPI device. 87062306a36Sopenharmony_ci */ 87162306a36Sopenharmony_ciacpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/** 87762306a36Sopenharmony_ci * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device. 87862306a36Sopenharmony_ci * @dev: ACPI device to add the notifier for. 87962306a36Sopenharmony_ci * @pci_dev: PCI device to check for the PME status if an event is signaled. 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ciacpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, 88262306a36Sopenharmony_ci struct pci_dev *pci_dev) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev); 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/* 88862306a36Sopenharmony_ci * _SxD returns the D-state with the highest power 88962306a36Sopenharmony_ci * (lowest D-state number) supported in the S-state "x". 89062306a36Sopenharmony_ci * 89162306a36Sopenharmony_ci * If the devices does not have a _PRW 89262306a36Sopenharmony_ci * (Power Resources for Wake) supporting system wakeup from "x" 89362306a36Sopenharmony_ci * then the OS is free to choose a lower power (higher number 89462306a36Sopenharmony_ci * D-state) than the return value from _SxD. 89562306a36Sopenharmony_ci * 89662306a36Sopenharmony_ci * But if _PRW is enabled at S-state "x", the OS 89762306a36Sopenharmony_ci * must not choose a power lower than _SxD -- 89862306a36Sopenharmony_ci * unless the device has an _SxW method specifying 89962306a36Sopenharmony_ci * the lowest power (highest D-state number) the device 90062306a36Sopenharmony_ci * may enter while still able to wake the system. 90162306a36Sopenharmony_ci * 90262306a36Sopenharmony_ci * ie. depending on global OS policy: 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * if (_PRW at S-state x) 90562306a36Sopenharmony_ci * choose from highest power _SxD to lowest power _SxW 90662306a36Sopenharmony_ci * else // no _PRW at S-state x 90762306a36Sopenharmony_ci * choose highest power _SxD or any lower power 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cipci_power_t acpi_pci_choose_state(struct pci_dev *pdev) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci int acpi_state, d_max; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (pdev->no_d3cold || !pdev->d3cold_allowed) 91562306a36Sopenharmony_ci d_max = ACPI_STATE_D3_HOT; 91662306a36Sopenharmony_ci else 91762306a36Sopenharmony_ci d_max = ACPI_STATE_D3_COLD; 91862306a36Sopenharmony_ci acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL, d_max); 91962306a36Sopenharmony_ci if (acpi_state < 0) 92062306a36Sopenharmony_ci return PCI_POWER_ERROR; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci switch (acpi_state) { 92362306a36Sopenharmony_ci case ACPI_STATE_D0: 92462306a36Sopenharmony_ci return PCI_D0; 92562306a36Sopenharmony_ci case ACPI_STATE_D1: 92662306a36Sopenharmony_ci return PCI_D1; 92762306a36Sopenharmony_ci case ACPI_STATE_D2: 92862306a36Sopenharmony_ci return PCI_D2; 92962306a36Sopenharmony_ci case ACPI_STATE_D3_HOT: 93062306a36Sopenharmony_ci return PCI_D3hot; 93162306a36Sopenharmony_ci case ACPI_STATE_D3_COLD: 93262306a36Sopenharmony_ci return PCI_D3cold; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci return PCI_POWER_ERROR; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic struct acpi_device *acpi_pci_find_companion(struct device *dev); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_civoid pci_set_acpi_fwnode(struct pci_dev *dev) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci if (!dev_fwnode(&dev->dev) && !pci_dev_is_added(dev)) 94262306a36Sopenharmony_ci ACPI_COMPANION_SET(&dev->dev, 94362306a36Sopenharmony_ci acpi_pci_find_companion(&dev->dev)); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci/** 94762306a36Sopenharmony_ci * pci_dev_acpi_reset - do a function level reset using _RST method 94862306a36Sopenharmony_ci * @dev: device to reset 94962306a36Sopenharmony_ci * @probe: if true, return 0 if device supports _RST 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_ciint pci_dev_acpi_reset(struct pci_dev *dev, bool probe) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(&dev->dev); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci if (!handle || !acpi_has_method(handle, "_RST")) 95662306a36Sopenharmony_ci return -ENOTTY; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (probe) 95962306a36Sopenharmony_ci return 0; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (ACPI_FAILURE(acpi_evaluate_object(handle, "_RST", NULL, NULL))) { 96262306a36Sopenharmony_ci pci_warn(dev, "ACPI _RST failed\n"); 96362306a36Sopenharmony_ci return -ENOTTY; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci return 0; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cibool acpi_pci_power_manageable(struct pci_dev *dev) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(&dev->dev); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return adev && acpi_device_power_manageable(adev); 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cibool acpi_pci_bridge_d3(struct pci_dev *dev) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct pci_dev *rpdev; 97962306a36Sopenharmony_ci struct acpi_device *adev, *rpadev; 98062306a36Sopenharmony_ci const union acpi_object *obj; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (acpi_pci_disabled || !dev->is_hotplug_bridge) 98362306a36Sopenharmony_ci return false; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci adev = ACPI_COMPANION(&dev->dev); 98662306a36Sopenharmony_ci if (adev) { 98762306a36Sopenharmony_ci /* 98862306a36Sopenharmony_ci * If the bridge has _S0W, whether or not it can go into D3 98962306a36Sopenharmony_ci * depends on what is returned by that object. In particular, 99062306a36Sopenharmony_ci * if the power state returned by _S0W is D2 or shallower, 99162306a36Sopenharmony_ci * entering D3 should not be allowed. 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_ci if (acpi_dev_power_state_for_wake(adev) <= ACPI_STATE_D2) 99462306a36Sopenharmony_ci return false; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* 99762306a36Sopenharmony_ci * Otherwise, assume that the bridge can enter D3 so long as it 99862306a36Sopenharmony_ci * is power-manageable via ACPI. 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci if (acpi_device_power_manageable(adev)) 100162306a36Sopenharmony_ci return true; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci rpdev = pcie_find_root_port(dev); 100562306a36Sopenharmony_ci if (!rpdev) 100662306a36Sopenharmony_ci return false; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (rpdev == dev) 100962306a36Sopenharmony_ci rpadev = adev; 101062306a36Sopenharmony_ci else 101162306a36Sopenharmony_ci rpadev = ACPI_COMPANION(&rpdev->dev); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (!rpadev) 101462306a36Sopenharmony_ci return false; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* 101762306a36Sopenharmony_ci * If the Root Port cannot signal wakeup signals at all, i.e., it 101862306a36Sopenharmony_ci * doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug 101962306a36Sopenharmony_ci * events from low-power states including D3hot and D3cold. 102062306a36Sopenharmony_ci */ 102162306a36Sopenharmony_ci if (!rpadev->wakeup.flags.valid) 102262306a36Sopenharmony_ci return false; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* 102562306a36Sopenharmony_ci * In the bridge-below-a-Root-Port case, evaluate _S0W for the Root Port 102662306a36Sopenharmony_ci * to verify whether or not it can signal wakeup from D3. 102762306a36Sopenharmony_ci */ 102862306a36Sopenharmony_ci if (rpadev != adev && 102962306a36Sopenharmony_ci acpi_dev_power_state_for_wake(rpadev) <= ACPI_STATE_D2) 103062306a36Sopenharmony_ci return false; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* 103362306a36Sopenharmony_ci * The "HotPlugSupportInD3" property in a Root Port _DSD indicates 103462306a36Sopenharmony_ci * the Port can signal hotplug events while in D3. We assume any 103562306a36Sopenharmony_ci * bridges *below* that Root Port can also signal hotplug events 103662306a36Sopenharmony_ci * while in D3. 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_ci if (!acpi_dev_get_property(rpadev, "HotPlugSupportInD3", 103962306a36Sopenharmony_ci ACPI_TYPE_INTEGER, &obj) && 104062306a36Sopenharmony_ci obj->integer.value == 1) 104162306a36Sopenharmony_ci return true; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return false; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic void acpi_pci_config_space_access(struct pci_dev *dev, bool enable) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci int val = enable ? ACPI_REG_CONNECT : ACPI_REG_DISCONNECT; 104962306a36Sopenharmony_ci int ret = acpi_evaluate_reg(ACPI_HANDLE(&dev->dev), 105062306a36Sopenharmony_ci ACPI_ADR_SPACE_PCI_CONFIG, val); 105162306a36Sopenharmony_ci if (ret) 105262306a36Sopenharmony_ci pci_dbg(dev, "ACPI _REG %s evaluation failed (%d)\n", 105362306a36Sopenharmony_ci enable ? "connect" : "disconnect", ret); 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ciint acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(&dev->dev); 105962306a36Sopenharmony_ci static const u8 state_conv[] = { 106062306a36Sopenharmony_ci [PCI_D0] = ACPI_STATE_D0, 106162306a36Sopenharmony_ci [PCI_D1] = ACPI_STATE_D1, 106262306a36Sopenharmony_ci [PCI_D2] = ACPI_STATE_D2, 106362306a36Sopenharmony_ci [PCI_D3hot] = ACPI_STATE_D3_HOT, 106462306a36Sopenharmony_ci [PCI_D3cold] = ACPI_STATE_D3_COLD, 106562306a36Sopenharmony_ci }; 106662306a36Sopenharmony_ci int error; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* If the ACPI device has _EJ0, ignore the device */ 106962306a36Sopenharmony_ci if (!adev || acpi_has_method(adev->handle, "_EJ0")) 107062306a36Sopenharmony_ci return -ENODEV; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci switch (state) { 107362306a36Sopenharmony_ci case PCI_D0: 107462306a36Sopenharmony_ci case PCI_D1: 107562306a36Sopenharmony_ci case PCI_D2: 107662306a36Sopenharmony_ci case PCI_D3hot: 107762306a36Sopenharmony_ci case PCI_D3cold: 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci default: 108062306a36Sopenharmony_ci return -EINVAL; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (state == PCI_D3cold) { 108462306a36Sopenharmony_ci if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == 108562306a36Sopenharmony_ci PM_QOS_FLAGS_ALL) 108662306a36Sopenharmony_ci return -EBUSY; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Notify AML lack of PCI config space availability */ 108962306a36Sopenharmony_ci acpi_pci_config_space_access(dev, false); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci error = acpi_device_set_power(adev, state_conv[state]); 109362306a36Sopenharmony_ci if (error) 109462306a36Sopenharmony_ci return error; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci pci_dbg(dev, "power state changed by ACPI to %s\n", 109762306a36Sopenharmony_ci acpi_power_state_string(adev->power.state)); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci /* 110062306a36Sopenharmony_ci * Notify AML of PCI config space availability. Config space is 110162306a36Sopenharmony_ci * accessible in all states except D3cold; the only transitions 110262306a36Sopenharmony_ci * that change availability are transitions to D3cold and from 110362306a36Sopenharmony_ci * D3cold to D0. 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_ci if (state == PCI_D0) 110662306a36Sopenharmony_ci acpi_pci_config_space_access(dev, true); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci return 0; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cipci_power_t acpi_pci_get_power_state(struct pci_dev *dev) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(&dev->dev); 111462306a36Sopenharmony_ci static const pci_power_t state_conv[] = { 111562306a36Sopenharmony_ci [ACPI_STATE_D0] = PCI_D0, 111662306a36Sopenharmony_ci [ACPI_STATE_D1] = PCI_D1, 111762306a36Sopenharmony_ci [ACPI_STATE_D2] = PCI_D2, 111862306a36Sopenharmony_ci [ACPI_STATE_D3_HOT] = PCI_D3hot, 111962306a36Sopenharmony_ci [ACPI_STATE_D3_COLD] = PCI_D3cold, 112062306a36Sopenharmony_ci }; 112162306a36Sopenharmony_ci int state; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (!adev || !acpi_device_power_manageable(adev)) 112462306a36Sopenharmony_ci return PCI_UNKNOWN; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci state = adev->power.state; 112762306a36Sopenharmony_ci if (state == ACPI_STATE_UNKNOWN) 112862306a36Sopenharmony_ci return PCI_UNKNOWN; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return state_conv[state]; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_civoid acpi_pci_refresh_power_state(struct pci_dev *dev) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(&dev->dev); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (adev && acpi_device_power_manageable(adev)) 113862306a36Sopenharmony_ci acpi_device_update_power(adev, NULL); 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci while (bus->parent) { 114462306a36Sopenharmony_ci if (acpi_pm_device_can_wakeup(&bus->self->dev)) 114562306a36Sopenharmony_ci return acpi_pm_set_device_wakeup(&bus->self->dev, enable); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci bus = bus->parent; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* We have reached the root bus. */ 115162306a36Sopenharmony_ci if (bus->bridge) { 115262306a36Sopenharmony_ci if (acpi_pm_device_can_wakeup(bus->bridge)) 115362306a36Sopenharmony_ci return acpi_pm_set_device_wakeup(bus->bridge, enable); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci return 0; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ciint acpi_pci_wakeup(struct pci_dev *dev, bool enable) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci if (acpi_pci_disabled) 116162306a36Sopenharmony_ci return 0; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (acpi_pm_device_can_wakeup(&dev->dev)) 116462306a36Sopenharmony_ci return acpi_pm_set_device_wakeup(&dev->dev, enable); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return acpi_pci_propagate_wakeup(dev->bus, enable); 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cibool acpi_pci_need_resume(struct pci_dev *dev) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci struct acpi_device *adev; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (acpi_pci_disabled) 117462306a36Sopenharmony_ci return false; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* 117762306a36Sopenharmony_ci * In some cases (eg. Samsung 305V4A) leaving a bridge in suspend over 117862306a36Sopenharmony_ci * system-wide suspend/resume confuses the platform firmware, so avoid 117962306a36Sopenharmony_ci * doing that. According to Section 16.1.6 of ACPI 6.2, endpoint 118062306a36Sopenharmony_ci * devices are expected to be in D3 before invoking the S3 entry path 118162306a36Sopenharmony_ci * from the firmware, so they should not be affected by this issue. 118262306a36Sopenharmony_ci */ 118362306a36Sopenharmony_ci if (pci_is_bridge(dev) && acpi_target_system_state() != ACPI_STATE_S0) 118462306a36Sopenharmony_ci return true; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci adev = ACPI_COMPANION(&dev->dev); 118762306a36Sopenharmony_ci if (!adev || !acpi_device_power_manageable(adev)) 118862306a36Sopenharmony_ci return false; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (adev->wakeup.flags.valid && 119162306a36Sopenharmony_ci device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count) 119262306a36Sopenharmony_ci return true; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (acpi_target_system_state() == ACPI_STATE_S0) 119562306a36Sopenharmony_ci return false; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci return !!adev->power.flags.dsw_present; 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_civoid acpi_pci_add_bus(struct pci_bus *bus) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci union acpi_object *obj; 120362306a36Sopenharmony_ci struct pci_host_bridge *bridge; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge)) 120662306a36Sopenharmony_ci return; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci acpi_pci_slot_enumerate(bus); 120962306a36Sopenharmony_ci acpiphp_enumerate_slots(bus); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* 121262306a36Sopenharmony_ci * For a host bridge, check its _DSM for function 8 and if 121362306a36Sopenharmony_ci * that is available, mark it in pci_host_bridge. 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_ci if (!pci_is_root_bus(bus)) 121662306a36Sopenharmony_ci return; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3, 121962306a36Sopenharmony_ci DSM_PCI_POWER_ON_RESET_DELAY, NULL); 122062306a36Sopenharmony_ci if (!obj) 122162306a36Sopenharmony_ci return; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) { 122462306a36Sopenharmony_ci bridge = pci_find_host_bridge(bus); 122562306a36Sopenharmony_ci bridge->ignore_reset_delay = 1; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci ACPI_FREE(obj); 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_civoid acpi_pci_remove_bus(struct pci_bus *bus) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci if (acpi_pci_disabled || !bus->bridge) 123362306a36Sopenharmony_ci return; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci acpiphp_remove_slots(bus); 123662306a36Sopenharmony_ci acpi_pci_slot_remove(bus); 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci/* ACPI bus type */ 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic DECLARE_RWSEM(pci_acpi_companion_lookup_sem); 124362306a36Sopenharmony_cistatic struct acpi_device *(*pci_acpi_find_companion_hook)(struct pci_dev *); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci/** 124662306a36Sopenharmony_ci * pci_acpi_set_companion_lookup_hook - Set ACPI companion lookup callback. 124762306a36Sopenharmony_ci * @func: ACPI companion lookup callback pointer or NULL. 124862306a36Sopenharmony_ci * 124962306a36Sopenharmony_ci * Set a special ACPI companion lookup callback for PCI devices whose companion 125062306a36Sopenharmony_ci * objects in the ACPI namespace have _ADR with non-standard bus-device-function 125162306a36Sopenharmony_ci * encodings. 125262306a36Sopenharmony_ci * 125362306a36Sopenharmony_ci * Return 0 on success or a negative error code on failure (in which case no 125462306a36Sopenharmony_ci * changes are made). 125562306a36Sopenharmony_ci * 125662306a36Sopenharmony_ci * The caller is responsible for the appropriate ordering of the invocations of 125762306a36Sopenharmony_ci * this function with respect to the enumeration of the PCI devices needing the 125862306a36Sopenharmony_ci * callback installed by it. 125962306a36Sopenharmony_ci */ 126062306a36Sopenharmony_ciint pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *)) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci int ret; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (!func) 126562306a36Sopenharmony_ci return -EINVAL; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci down_write(&pci_acpi_companion_lookup_sem); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (pci_acpi_find_companion_hook) { 127062306a36Sopenharmony_ci ret = -EBUSY; 127162306a36Sopenharmony_ci } else { 127262306a36Sopenharmony_ci pci_acpi_find_companion_hook = func; 127362306a36Sopenharmony_ci ret = 0; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci up_write(&pci_acpi_companion_lookup_sem); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci return ret; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_acpi_set_companion_lookup_hook); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci/** 128362306a36Sopenharmony_ci * pci_acpi_clear_companion_lookup_hook - Clear ACPI companion lookup callback. 128462306a36Sopenharmony_ci * 128562306a36Sopenharmony_ci * Clear the special ACPI companion lookup callback previously set by 128662306a36Sopenharmony_ci * pci_acpi_set_companion_lookup_hook(). Block until the last running instance 128762306a36Sopenharmony_ci * of the callback returns before clearing it. 128862306a36Sopenharmony_ci * 128962306a36Sopenharmony_ci * The caller is responsible for the appropriate ordering of the invocations of 129062306a36Sopenharmony_ci * this function with respect to the enumeration of the PCI devices needing the 129162306a36Sopenharmony_ci * callback cleared by it. 129262306a36Sopenharmony_ci */ 129362306a36Sopenharmony_civoid pci_acpi_clear_companion_lookup_hook(void) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci down_write(&pci_acpi_companion_lookup_sem); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci pci_acpi_find_companion_hook = NULL; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci up_write(&pci_acpi_companion_lookup_sem); 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_acpi_clear_companion_lookup_hook); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cistatic struct acpi_device *acpi_pci_find_companion(struct device *dev) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 130662306a36Sopenharmony_ci struct acpi_device *adev; 130762306a36Sopenharmony_ci bool check_children; 130862306a36Sopenharmony_ci u64 addr; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (!dev->parent) 131162306a36Sopenharmony_ci return NULL; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci down_read(&pci_acpi_companion_lookup_sem); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci adev = pci_acpi_find_companion_hook ? 131662306a36Sopenharmony_ci pci_acpi_find_companion_hook(pci_dev) : NULL; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci up_read(&pci_acpi_companion_lookup_sem); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci if (adev) 132162306a36Sopenharmony_ci return adev; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci check_children = pci_is_bridge(pci_dev); 132462306a36Sopenharmony_ci /* Please ref to ACPI spec for the syntax of _ADR */ 132562306a36Sopenharmony_ci addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); 132662306a36Sopenharmony_ci adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, 132762306a36Sopenharmony_ci check_children); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* 133062306a36Sopenharmony_ci * There may be ACPI device objects in the ACPI namespace that are 133162306a36Sopenharmony_ci * children of the device object representing the host bridge, but don't 133262306a36Sopenharmony_ci * represent PCI devices. Both _HID and _ADR may be present for them, 133362306a36Sopenharmony_ci * even though that is against the specification (for example, see 133462306a36Sopenharmony_ci * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which 133562306a36Sopenharmony_ci * appears to indicate that they should not be taken into consideration 133662306a36Sopenharmony_ci * as potential companions of PCI devices on the root bus. 133762306a36Sopenharmony_ci * 133862306a36Sopenharmony_ci * To catch this special case, disregard the returned device object if 133962306a36Sopenharmony_ci * it has a valid _HID, addr is 0 and the PCI device at hand is on the 134062306a36Sopenharmony_ci * root bus. 134162306a36Sopenharmony_ci */ 134262306a36Sopenharmony_ci if (adev && adev->pnp.type.platform_id && !addr && 134362306a36Sopenharmony_ci pci_is_root_bus(pci_dev->bus)) 134462306a36Sopenharmony_ci return NULL; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return adev; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci/** 135062306a36Sopenharmony_ci * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI 135162306a36Sopenharmony_ci * @pdev: the PCI device whose delay is to be updated 135262306a36Sopenharmony_ci * @handle: ACPI handle of this device 135362306a36Sopenharmony_ci * 135462306a36Sopenharmony_ci * Update the d3hot_delay and d3cold_delay of a PCI device from the ACPI _DSM 135562306a36Sopenharmony_ci * control method of either the device itself or the PCI host bridge. 135662306a36Sopenharmony_ci * 135762306a36Sopenharmony_ci * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI 135862306a36Sopenharmony_ci * host bridge. If it returns one, the OS may assume that all devices in 135962306a36Sopenharmony_ci * the hierarchy have already completed power-on reset delays. 136062306a36Sopenharmony_ci * 136162306a36Sopenharmony_ci * Function 9, "Device Readiness Durations," applies only to the object 136262306a36Sopenharmony_ci * where it is located. It returns delay durations required after various 136362306a36Sopenharmony_ci * events if the device requires less time than the spec requires. Delays 136462306a36Sopenharmony_ci * from this function take precedence over the Reset Delay function. 136562306a36Sopenharmony_ci * 136662306a36Sopenharmony_ci * These _DSM functions are defined by the draft ECN of January 28, 2014, 136762306a36Sopenharmony_ci * titled "ACPI additions for FW latency optimizations." 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_cistatic void pci_acpi_optimize_delay(struct pci_dev *pdev, 137062306a36Sopenharmony_ci acpi_handle handle) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus); 137362306a36Sopenharmony_ci int value; 137462306a36Sopenharmony_ci union acpi_object *obj, *elements; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (bridge->ignore_reset_delay) 137762306a36Sopenharmony_ci pdev->d3cold_delay = 0; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3, 138062306a36Sopenharmony_ci DSM_PCI_DEVICE_READINESS_DURATIONS, NULL); 138162306a36Sopenharmony_ci if (!obj) 138262306a36Sopenharmony_ci return; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) { 138562306a36Sopenharmony_ci elements = obj->package.elements; 138662306a36Sopenharmony_ci if (elements[0].type == ACPI_TYPE_INTEGER) { 138762306a36Sopenharmony_ci value = (int)elements[0].integer.value / 1000; 138862306a36Sopenharmony_ci if (value < PCI_PM_D3COLD_WAIT) 138962306a36Sopenharmony_ci pdev->d3cold_delay = value; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci if (elements[3].type == ACPI_TYPE_INTEGER) { 139262306a36Sopenharmony_ci value = (int)elements[3].integer.value / 1000; 139362306a36Sopenharmony_ci if (value < PCI_PM_D3HOT_WAIT) 139462306a36Sopenharmony_ci pdev->d3hot_delay = value; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci ACPI_FREE(obj); 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic void pci_acpi_set_external_facing(struct pci_dev *dev) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci u8 val; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) 140562306a36Sopenharmony_ci return; 140662306a36Sopenharmony_ci if (device_property_read_u8(&dev->dev, "ExternalFacingPort", &val)) 140762306a36Sopenharmony_ci return; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci /* 141062306a36Sopenharmony_ci * These root ports expose PCIe (including DMA) outside of the 141162306a36Sopenharmony_ci * system. Everything downstream from them is external. 141262306a36Sopenharmony_ci */ 141362306a36Sopenharmony_ci if (val) 141462306a36Sopenharmony_ci dev->external_facing = 1; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_civoid pci_acpi_setup(struct device *dev, struct acpi_device *adev) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci pci_acpi_optimize_delay(pci_dev, adev->handle); 142262306a36Sopenharmony_ci pci_acpi_set_external_facing(pci_dev); 142362306a36Sopenharmony_ci pci_acpi_add_edr_notifier(pci_dev); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci pci_acpi_add_pm_notifier(adev, pci_dev); 142662306a36Sopenharmony_ci if (!adev->wakeup.flags.valid) 142762306a36Sopenharmony_ci return; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci device_set_wakeup_capable(dev, true); 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci * For bridges that can do D3 we enable wake automatically (as 143262306a36Sopenharmony_ci * we do for the power management itself in that case). The 143362306a36Sopenharmony_ci * reason is that the bridge may have additional methods such as 143462306a36Sopenharmony_ci * _DSW that need to be called. 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_ci if (pci_dev->bridge_d3) 143762306a36Sopenharmony_ci device_wakeup_enable(dev); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci acpi_pci_wakeup(pci_dev, false); 144062306a36Sopenharmony_ci acpi_device_power_add_dependent(adev, dev); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (pci_is_bridge(pci_dev)) 144362306a36Sopenharmony_ci acpi_dev_power_up_children_with_adr(adev); 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_civoid pci_acpi_cleanup(struct device *dev, struct acpi_device *adev) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci pci_acpi_remove_edr_notifier(pci_dev); 145162306a36Sopenharmony_ci pci_acpi_remove_pm_notifier(adev); 145262306a36Sopenharmony_ci if (adev->wakeup.flags.valid) { 145362306a36Sopenharmony_ci acpi_device_power_remove_dependent(adev, dev); 145462306a36Sopenharmony_ci if (pci_dev->bridge_d3) 145562306a36Sopenharmony_ci device_wakeup_disable(dev); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci device_set_wakeup_capable(dev, false); 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci/** 146462306a36Sopenharmony_ci * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode 146562306a36Sopenharmony_ci * @fn: Callback matching a device to a fwnode that identifies a PCI 146662306a36Sopenharmony_ci * MSI domain. 146762306a36Sopenharmony_ci * 146862306a36Sopenharmony_ci * This should be called by irqchip driver, which is the parent of 146962306a36Sopenharmony_ci * the MSI domain to provide callback interface to query fwnode. 147062306a36Sopenharmony_ci */ 147162306a36Sopenharmony_civoid 147262306a36Sopenharmony_cipci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *)) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci pci_msi_get_fwnode_cb = fn; 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci/** 147862306a36Sopenharmony_ci * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge 147962306a36Sopenharmony_ci * @bus: The PCI host bridge bus. 148062306a36Sopenharmony_ci * 148162306a36Sopenharmony_ci * This function uses the callback function registered by 148262306a36Sopenharmony_ci * pci_msi_register_fwnode_provider() to retrieve the irq_domain with 148362306a36Sopenharmony_ci * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus. 148462306a36Sopenharmony_ci * This returns NULL on error or when the domain is not found. 148562306a36Sopenharmony_ci */ 148662306a36Sopenharmony_cistruct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci struct fwnode_handle *fwnode; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if (!pci_msi_get_fwnode_cb) 149162306a36Sopenharmony_ci return NULL; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci fwnode = pci_msi_get_fwnode_cb(&bus->dev); 149462306a36Sopenharmony_ci if (!fwnode) 149562306a36Sopenharmony_ci return NULL; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI); 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic int __init acpi_pci_init(void) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) { 150362306a36Sopenharmony_ci pr_info("ACPI FADT declares the system doesn't support MSI, so disable it\n"); 150462306a36Sopenharmony_ci pci_no_msi(); 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { 150862306a36Sopenharmony_ci pr_info("ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); 150962306a36Sopenharmony_ci pcie_no_aspm(); 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci if (acpi_pci_disabled) 151362306a36Sopenharmony_ci return 0; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci acpi_pci_slot_init(); 151662306a36Sopenharmony_ci acpiphp_init(); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci return 0; 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ciarch_initcall(acpi_pci_init); 1521