18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCI support in ACPI
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005 David Shaohua Li <shaohua.li@intel.com>
68c2ecf20Sopenharmony_ci * Copyright (C) 2004 Tom Long Nguyen <tom.l.nguyen@intel.com>
78c2ecf20Sopenharmony_ci * Copyright (C) 2004 Intel Corp.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
138c2ecf20Sopenharmony_ci#include <linux/pci.h>
148c2ecf20Sopenharmony_ci#include <linux/msi.h>
158c2ecf20Sopenharmony_ci#include <linux/pci_hotplug.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/pci-acpi.h>
188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
198c2ecf20Sopenharmony_ci#include <linux/pm_qos.h>
208c2ecf20Sopenharmony_ci#include "pci.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * The GUID is defined in the PCI Firmware Specification available here:
248c2ecf20Sopenharmony_ci * https://www.pcisig.com/members/downloads/pcifw_r3_1_13Dec10.pdf
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ciconst guid_t pci_acpi_dsm_guid =
278c2ecf20Sopenharmony_ci	GUID_INIT(0xe5c937d0, 0x3553, 0x4d7a,
288c2ecf20Sopenharmony_ci		  0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
318c2ecf20Sopenharmony_cistatic int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct device *dev = &adev->dev;
348c2ecf20Sopenharmony_ci	struct resource_entry *entry;
358c2ecf20Sopenharmony_ci	struct list_head list;
368c2ecf20Sopenharmony_ci	unsigned long flags;
378c2ecf20Sopenharmony_ci	int ret;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list);
408c2ecf20Sopenharmony_ci	flags = IORESOURCE_MEM;
418c2ecf20Sopenharmony_ci	ret = acpi_dev_get_resources(adev, &list,
428c2ecf20Sopenharmony_ci				     acpi_dev_filter_resource_type_cb,
438c2ecf20Sopenharmony_ci				     (void *) flags);
448c2ecf20Sopenharmony_ci	if (ret < 0) {
458c2ecf20Sopenharmony_ci		dev_err(dev, "failed to parse _CRS method, error code %d\n",
468c2ecf20Sopenharmony_ci			ret);
478c2ecf20Sopenharmony_ci		return ret;
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (ret == 0) {
518c2ecf20Sopenharmony_ci		dev_err(dev, "no IO and memory resources present in _CRS\n");
528c2ecf20Sopenharmony_ci		return -EINVAL;
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	entry = list_first_entry(&list, struct resource_entry, node);
568c2ecf20Sopenharmony_ci	*res = *entry->res;
578c2ecf20Sopenharmony_ci	acpi_dev_free_resource_list(&list);
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic acpi_status acpi_match_rc(acpi_handle handle, u32 lvl, void *context,
628c2ecf20Sopenharmony_ci				 void **retval)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	u16 *segment = context;
658c2ecf20Sopenharmony_ci	unsigned long long uid;
668c2ecf20Sopenharmony_ci	acpi_status status;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	status = acpi_evaluate_integer(handle, "_UID", NULL, &uid);
698c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status) || uid != *segment)
708c2ecf20Sopenharmony_ci		return AE_CTRL_DEPTH;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	*(acpi_handle *)retval = handle;
738c2ecf20Sopenharmony_ci	return AE_CTRL_TERMINATE;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciint acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
778c2ecf20Sopenharmony_ci			  struct resource *res)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct acpi_device *adev;
808c2ecf20Sopenharmony_ci	acpi_status status;
818c2ecf20Sopenharmony_ci	acpi_handle handle;
828c2ecf20Sopenharmony_ci	int ret;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	status = acpi_get_devices(hid, acpi_match_rc, &segment, &handle);
858c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
868c2ecf20Sopenharmony_ci		dev_err(dev, "can't find _HID %s device to locate resources\n",
878c2ecf20Sopenharmony_ci			hid);
888c2ecf20Sopenharmony_ci		return -ENODEV;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	ret = acpi_bus_get_device(handle, &adev);
928c2ecf20Sopenharmony_ci	if (ret)
938c2ecf20Sopenharmony_ci		return ret;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = acpi_get_rc_addr(adev, res);
968c2ecf20Sopenharmony_ci	if (ret) {
978c2ecf20Sopenharmony_ci		dev_err(dev, "can't get resource from %s\n",
988c2ecf20Sopenharmony_ci			dev_name(&adev->dev));
998c2ecf20Sopenharmony_ci		return ret;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci#endif
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciphys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	acpi_status status = AE_NOT_EXIST;
1098c2ecf20Sopenharmony_ci	unsigned long long mcfg_addr;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (handle)
1128c2ecf20Sopenharmony_ci		status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
1138c2ecf20Sopenharmony_ci					       NULL, &mcfg_addr);
1148c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
1158c2ecf20Sopenharmony_ci		return 0;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return (phys_addr_t)mcfg_addr;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/* _HPX PCI Setting Record (Type 0); same as _HPP */
1218c2ecf20Sopenharmony_cistruct hpx_type0 {
1228c2ecf20Sopenharmony_ci	u32 revision;		/* Not present in _HPP */
1238c2ecf20Sopenharmony_ci	u8  cache_line_size;	/* Not applicable to PCIe */
1248c2ecf20Sopenharmony_ci	u8  latency_timer;	/* Not applicable to PCIe */
1258c2ecf20Sopenharmony_ci	u8  enable_serr;
1268c2ecf20Sopenharmony_ci	u8  enable_perr;
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic struct hpx_type0 pci_default_type0 = {
1308c2ecf20Sopenharmony_ci	.revision = 1,
1318c2ecf20Sopenharmony_ci	.cache_line_size = 8,
1328c2ecf20Sopenharmony_ci	.latency_timer = 0x40,
1338c2ecf20Sopenharmony_ci	.enable_serr = 0,
1348c2ecf20Sopenharmony_ci	.enable_perr = 0,
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void program_hpx_type0(struct pci_dev *dev, struct hpx_type0 *hpx)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	u16 pci_cmd, pci_bctl;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (!hpx)
1428c2ecf20Sopenharmony_ci		hpx = &pci_default_type0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (hpx->revision > 1) {
1458c2ecf20Sopenharmony_ci		pci_warn(dev, "PCI settings rev %d not supported; using defaults\n",
1468c2ecf20Sopenharmony_ci			 hpx->revision);
1478c2ecf20Sopenharmony_ci		hpx = &pci_default_type0;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpx->cache_line_size);
1518c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpx->latency_timer);
1528c2ecf20Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
1538c2ecf20Sopenharmony_ci	if (hpx->enable_serr)
1548c2ecf20Sopenharmony_ci		pci_cmd |= PCI_COMMAND_SERR;
1558c2ecf20Sopenharmony_ci	if (hpx->enable_perr)
1568c2ecf20Sopenharmony_ci		pci_cmd |= PCI_COMMAND_PARITY;
1578c2ecf20Sopenharmony_ci	pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Program bridge control value */
1608c2ecf20Sopenharmony_ci	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
1618c2ecf20Sopenharmony_ci		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
1628c2ecf20Sopenharmony_ci				      hpx->latency_timer);
1638c2ecf20Sopenharmony_ci		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
1648c2ecf20Sopenharmony_ci		if (hpx->enable_perr)
1658c2ecf20Sopenharmony_ci			pci_bctl |= PCI_BRIDGE_CTL_PARITY;
1668c2ecf20Sopenharmony_ci		pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic acpi_status decode_type0_hpx_record(union acpi_object *record,
1718c2ecf20Sopenharmony_ci					   struct hpx_type0 *hpx0)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	int i;
1748c2ecf20Sopenharmony_ci	union acpi_object *fields = record->package.elements;
1758c2ecf20Sopenharmony_ci	u32 revision = fields[1].integer.value;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	switch (revision) {
1788c2ecf20Sopenharmony_ci	case 1:
1798c2ecf20Sopenharmony_ci		if (record->package.count != 6)
1808c2ecf20Sopenharmony_ci			return AE_ERROR;
1818c2ecf20Sopenharmony_ci		for (i = 2; i < 6; i++)
1828c2ecf20Sopenharmony_ci			if (fields[i].type != ACPI_TYPE_INTEGER)
1838c2ecf20Sopenharmony_ci				return AE_ERROR;
1848c2ecf20Sopenharmony_ci		hpx0->revision        = revision;
1858c2ecf20Sopenharmony_ci		hpx0->cache_line_size = fields[2].integer.value;
1868c2ecf20Sopenharmony_ci		hpx0->latency_timer   = fields[3].integer.value;
1878c2ecf20Sopenharmony_ci		hpx0->enable_serr     = fields[4].integer.value;
1888c2ecf20Sopenharmony_ci		hpx0->enable_perr     = fields[5].integer.value;
1898c2ecf20Sopenharmony_ci		break;
1908c2ecf20Sopenharmony_ci	default:
1918c2ecf20Sopenharmony_ci		pr_warn("%s: Type 0 Revision %d record not supported\n",
1928c2ecf20Sopenharmony_ci		       __func__, revision);
1938c2ecf20Sopenharmony_ci		return AE_ERROR;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci	return AE_OK;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci/* _HPX PCI-X Setting Record (Type 1) */
1998c2ecf20Sopenharmony_cistruct hpx_type1 {
2008c2ecf20Sopenharmony_ci	u32 revision;
2018c2ecf20Sopenharmony_ci	u8  max_mem_read;
2028c2ecf20Sopenharmony_ci	u8  avg_max_split;
2038c2ecf20Sopenharmony_ci	u16 tot_max_split;
2048c2ecf20Sopenharmony_ci};
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void program_hpx_type1(struct pci_dev *dev, struct hpx_type1 *hpx)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	int pos;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!hpx)
2118c2ecf20Sopenharmony_ci		return;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
2148c2ecf20Sopenharmony_ci	if (!pos)
2158c2ecf20Sopenharmony_ci		return;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	pci_warn(dev, "PCI-X settings not supported\n");
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic acpi_status decode_type1_hpx_record(union acpi_object *record,
2218c2ecf20Sopenharmony_ci					   struct hpx_type1 *hpx1)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	int i;
2248c2ecf20Sopenharmony_ci	union acpi_object *fields = record->package.elements;
2258c2ecf20Sopenharmony_ci	u32 revision = fields[1].integer.value;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	switch (revision) {
2288c2ecf20Sopenharmony_ci	case 1:
2298c2ecf20Sopenharmony_ci		if (record->package.count != 5)
2308c2ecf20Sopenharmony_ci			return AE_ERROR;
2318c2ecf20Sopenharmony_ci		for (i = 2; i < 5; i++)
2328c2ecf20Sopenharmony_ci			if (fields[i].type != ACPI_TYPE_INTEGER)
2338c2ecf20Sopenharmony_ci				return AE_ERROR;
2348c2ecf20Sopenharmony_ci		hpx1->revision      = revision;
2358c2ecf20Sopenharmony_ci		hpx1->max_mem_read  = fields[2].integer.value;
2368c2ecf20Sopenharmony_ci		hpx1->avg_max_split = fields[3].integer.value;
2378c2ecf20Sopenharmony_ci		hpx1->tot_max_split = fields[4].integer.value;
2388c2ecf20Sopenharmony_ci		break;
2398c2ecf20Sopenharmony_ci	default:
2408c2ecf20Sopenharmony_ci		pr_warn("%s: Type 1 Revision %d record not supported\n",
2418c2ecf20Sopenharmony_ci		       __func__, revision);
2428c2ecf20Sopenharmony_ci		return AE_ERROR;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	return AE_OK;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic bool pcie_root_rcb_set(struct pci_dev *dev)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct pci_dev *rp = pcie_find_root_port(dev);
2508c2ecf20Sopenharmony_ci	u16 lnkctl;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (!rp)
2538c2ecf20Sopenharmony_ci		return false;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
2568c2ecf20Sopenharmony_ci	if (lnkctl & PCI_EXP_LNKCTL_RCB)
2578c2ecf20Sopenharmony_ci		return true;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return false;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/* _HPX PCI Express Setting Record (Type 2) */
2638c2ecf20Sopenharmony_cistruct hpx_type2 {
2648c2ecf20Sopenharmony_ci	u32 revision;
2658c2ecf20Sopenharmony_ci	u32 unc_err_mask_and;
2668c2ecf20Sopenharmony_ci	u32 unc_err_mask_or;
2678c2ecf20Sopenharmony_ci	u32 unc_err_sever_and;
2688c2ecf20Sopenharmony_ci	u32 unc_err_sever_or;
2698c2ecf20Sopenharmony_ci	u32 cor_err_mask_and;
2708c2ecf20Sopenharmony_ci	u32 cor_err_mask_or;
2718c2ecf20Sopenharmony_ci	u32 adv_err_cap_and;
2728c2ecf20Sopenharmony_ci	u32 adv_err_cap_or;
2738c2ecf20Sopenharmony_ci	u16 pci_exp_devctl_and;
2748c2ecf20Sopenharmony_ci	u16 pci_exp_devctl_or;
2758c2ecf20Sopenharmony_ci	u16 pci_exp_lnkctl_and;
2768c2ecf20Sopenharmony_ci	u16 pci_exp_lnkctl_or;
2778c2ecf20Sopenharmony_ci	u32 sec_unc_err_sever_and;
2788c2ecf20Sopenharmony_ci	u32 sec_unc_err_sever_or;
2798c2ecf20Sopenharmony_ci	u32 sec_unc_err_mask_and;
2808c2ecf20Sopenharmony_ci	u32 sec_unc_err_mask_or;
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	int pos;
2868c2ecf20Sopenharmony_ci	u32 reg32;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!hpx)
2898c2ecf20Sopenharmony_ci		return;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
2928c2ecf20Sopenharmony_ci		return;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (hpx->revision > 1) {
2958c2ecf20Sopenharmony_ci		pci_warn(dev, "PCIe settings rev %d not supported\n",
2968c2ecf20Sopenharmony_ci			 hpx->revision);
2978c2ecf20Sopenharmony_ci		return;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/*
3018c2ecf20Sopenharmony_ci	 * Don't allow _HPX to change MPS or MRRS settings.  We manage
3028c2ecf20Sopenharmony_ci	 * those to make sure they're consistent with the rest of the
3038c2ecf20Sopenharmony_ci	 * platform.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD |
3068c2ecf20Sopenharmony_ci				    PCI_EXP_DEVCTL_READRQ;
3078c2ecf20Sopenharmony_ci	hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD |
3088c2ecf20Sopenharmony_ci				    PCI_EXP_DEVCTL_READRQ);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/* Initialize Device Control Register */
3118c2ecf20Sopenharmony_ci	pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
3128c2ecf20Sopenharmony_ci			~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Initialize Link Control Register */
3158c2ecf20Sopenharmony_ci	if (pcie_cap_has_lnkctl(dev)) {
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		/*
3188c2ecf20Sopenharmony_ci		 * If the Root Port supports Read Completion Boundary of
3198c2ecf20Sopenharmony_ci		 * 128, set RCB to 128.  Otherwise, clear it.
3208c2ecf20Sopenharmony_ci		 */
3218c2ecf20Sopenharmony_ci		hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
3228c2ecf20Sopenharmony_ci		hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
3238c2ecf20Sopenharmony_ci		if (pcie_root_rcb_set(dev))
3248c2ecf20Sopenharmony_ci			hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
3278c2ecf20Sopenharmony_ci			~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or);
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* Find Advanced Error Reporting Enhanced Capability */
3318c2ecf20Sopenharmony_ci	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
3328c2ecf20Sopenharmony_ci	if (!pos)
3338c2ecf20Sopenharmony_ci		return;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* Initialize Uncorrectable Error Mask Register */
3368c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &reg32);
3378c2ecf20Sopenharmony_ci	reg32 = (reg32 & hpx->unc_err_mask_and) | hpx->unc_err_mask_or;
3388c2ecf20Sopenharmony_ci	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* Initialize Uncorrectable Error Severity Register */
3418c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &reg32);
3428c2ecf20Sopenharmony_ci	reg32 = (reg32 & hpx->unc_err_sever_and) | hpx->unc_err_sever_or;
3438c2ecf20Sopenharmony_ci	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Initialize Correctable Error Mask Register */
3468c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg32);
3478c2ecf20Sopenharmony_ci	reg32 = (reg32 & hpx->cor_err_mask_and) | hpx->cor_err_mask_or;
3488c2ecf20Sopenharmony_ci	pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* Initialize Advanced Error Capabilities and Control Register */
3518c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
3528c2ecf20Sopenharmony_ci	reg32 = (reg32 & hpx->adv_err_cap_and) | hpx->adv_err_cap_or;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Don't enable ECRC generation or checking if unsupported */
3558c2ecf20Sopenharmony_ci	if (!(reg32 & PCI_ERR_CAP_ECRC_GENC))
3568c2ecf20Sopenharmony_ci		reg32 &= ~PCI_ERR_CAP_ECRC_GENE;
3578c2ecf20Sopenharmony_ci	if (!(reg32 & PCI_ERR_CAP_ECRC_CHKC))
3588c2ecf20Sopenharmony_ci		reg32 &= ~PCI_ERR_CAP_ECRC_CHKE;
3598c2ecf20Sopenharmony_ci	pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/*
3628c2ecf20Sopenharmony_ci	 * FIXME: The following two registers are not supported yet.
3638c2ecf20Sopenharmony_ci	 *
3648c2ecf20Sopenharmony_ci	 *   o Secondary Uncorrectable Error Severity Register
3658c2ecf20Sopenharmony_ci	 *   o Secondary Uncorrectable Error Mask Register
3668c2ecf20Sopenharmony_ci	 */
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic acpi_status decode_type2_hpx_record(union acpi_object *record,
3708c2ecf20Sopenharmony_ci					   struct hpx_type2 *hpx2)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	int i;
3738c2ecf20Sopenharmony_ci	union acpi_object *fields = record->package.elements;
3748c2ecf20Sopenharmony_ci	u32 revision = fields[1].integer.value;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	switch (revision) {
3778c2ecf20Sopenharmony_ci	case 1:
3788c2ecf20Sopenharmony_ci		if (record->package.count != 18)
3798c2ecf20Sopenharmony_ci			return AE_ERROR;
3808c2ecf20Sopenharmony_ci		for (i = 2; i < 18; i++)
3818c2ecf20Sopenharmony_ci			if (fields[i].type != ACPI_TYPE_INTEGER)
3828c2ecf20Sopenharmony_ci				return AE_ERROR;
3838c2ecf20Sopenharmony_ci		hpx2->revision      = revision;
3848c2ecf20Sopenharmony_ci		hpx2->unc_err_mask_and      = fields[2].integer.value;
3858c2ecf20Sopenharmony_ci		hpx2->unc_err_mask_or       = fields[3].integer.value;
3868c2ecf20Sopenharmony_ci		hpx2->unc_err_sever_and     = fields[4].integer.value;
3878c2ecf20Sopenharmony_ci		hpx2->unc_err_sever_or      = fields[5].integer.value;
3888c2ecf20Sopenharmony_ci		hpx2->cor_err_mask_and      = fields[6].integer.value;
3898c2ecf20Sopenharmony_ci		hpx2->cor_err_mask_or       = fields[7].integer.value;
3908c2ecf20Sopenharmony_ci		hpx2->adv_err_cap_and       = fields[8].integer.value;
3918c2ecf20Sopenharmony_ci		hpx2->adv_err_cap_or        = fields[9].integer.value;
3928c2ecf20Sopenharmony_ci		hpx2->pci_exp_devctl_and    = fields[10].integer.value;
3938c2ecf20Sopenharmony_ci		hpx2->pci_exp_devctl_or     = fields[11].integer.value;
3948c2ecf20Sopenharmony_ci		hpx2->pci_exp_lnkctl_and    = fields[12].integer.value;
3958c2ecf20Sopenharmony_ci		hpx2->pci_exp_lnkctl_or     = fields[13].integer.value;
3968c2ecf20Sopenharmony_ci		hpx2->sec_unc_err_sever_and = fields[14].integer.value;
3978c2ecf20Sopenharmony_ci		hpx2->sec_unc_err_sever_or  = fields[15].integer.value;
3988c2ecf20Sopenharmony_ci		hpx2->sec_unc_err_mask_and  = fields[16].integer.value;
3998c2ecf20Sopenharmony_ci		hpx2->sec_unc_err_mask_or   = fields[17].integer.value;
4008c2ecf20Sopenharmony_ci		break;
4018c2ecf20Sopenharmony_ci	default:
4028c2ecf20Sopenharmony_ci		pr_warn("%s: Type 2 Revision %d record not supported\n",
4038c2ecf20Sopenharmony_ci		       __func__, revision);
4048c2ecf20Sopenharmony_ci		return AE_ERROR;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci	return AE_OK;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci/* _HPX PCI Express Setting Record (Type 3) */
4108c2ecf20Sopenharmony_cistruct hpx_type3 {
4118c2ecf20Sopenharmony_ci	u16 device_type;
4128c2ecf20Sopenharmony_ci	u16 function_type;
4138c2ecf20Sopenharmony_ci	u16 config_space_location;
4148c2ecf20Sopenharmony_ci	u16 pci_exp_cap_id;
4158c2ecf20Sopenharmony_ci	u16 pci_exp_cap_ver;
4168c2ecf20Sopenharmony_ci	u16 pci_exp_vendor_id;
4178c2ecf20Sopenharmony_ci	u16 dvsec_id;
4188c2ecf20Sopenharmony_ci	u16 dvsec_rev;
4198c2ecf20Sopenharmony_ci	u16 match_offset;
4208c2ecf20Sopenharmony_ci	u32 match_mask_and;
4218c2ecf20Sopenharmony_ci	u32 match_value;
4228c2ecf20Sopenharmony_ci	u16 reg_offset;
4238c2ecf20Sopenharmony_ci	u32 reg_mask_and;
4248c2ecf20Sopenharmony_ci	u32 reg_mask_or;
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cienum hpx_type3_dev_type {
4288c2ecf20Sopenharmony_ci	HPX_TYPE_ENDPOINT	= BIT(0),
4298c2ecf20Sopenharmony_ci	HPX_TYPE_LEG_END	= BIT(1),
4308c2ecf20Sopenharmony_ci	HPX_TYPE_RC_END		= BIT(2),
4318c2ecf20Sopenharmony_ci	HPX_TYPE_RC_EC		= BIT(3),
4328c2ecf20Sopenharmony_ci	HPX_TYPE_ROOT_PORT	= BIT(4),
4338c2ecf20Sopenharmony_ci	HPX_TYPE_UPSTREAM	= BIT(5),
4348c2ecf20Sopenharmony_ci	HPX_TYPE_DOWNSTREAM	= BIT(6),
4358c2ecf20Sopenharmony_ci	HPX_TYPE_PCI_BRIDGE	= BIT(7),
4368c2ecf20Sopenharmony_ci	HPX_TYPE_PCIE_BRIDGE	= BIT(8),
4378c2ecf20Sopenharmony_ci};
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic u16 hpx3_device_type(struct pci_dev *dev)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	u16 pcie_type = pci_pcie_type(dev);
4428c2ecf20Sopenharmony_ci	static const int pcie_to_hpx3_type[] = {
4438c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_ENDPOINT]    = HPX_TYPE_ENDPOINT,
4448c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_LEG_END]     = HPX_TYPE_LEG_END,
4458c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_RC_END]      = HPX_TYPE_RC_END,
4468c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_RC_EC]       = HPX_TYPE_RC_EC,
4478c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_ROOT_PORT]   = HPX_TYPE_ROOT_PORT,
4488c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_UPSTREAM]    = HPX_TYPE_UPSTREAM,
4498c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_DOWNSTREAM]  = HPX_TYPE_DOWNSTREAM,
4508c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_PCI_BRIDGE]  = HPX_TYPE_PCI_BRIDGE,
4518c2ecf20Sopenharmony_ci		[PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE,
4528c2ecf20Sopenharmony_ci	};
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type))
4558c2ecf20Sopenharmony_ci		return 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return pcie_to_hpx3_type[pcie_type];
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cienum hpx_type3_fn_type {
4618c2ecf20Sopenharmony_ci	HPX_FN_NORMAL		= BIT(0),
4628c2ecf20Sopenharmony_ci	HPX_FN_SRIOV_PHYS	= BIT(1),
4638c2ecf20Sopenharmony_ci	HPX_FN_SRIOV_VIRT	= BIT(2),
4648c2ecf20Sopenharmony_ci};
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic u8 hpx3_function_type(struct pci_dev *dev)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	if (dev->is_virtfn)
4698c2ecf20Sopenharmony_ci		return HPX_FN_SRIOV_VIRT;
4708c2ecf20Sopenharmony_ci	else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0)
4718c2ecf20Sopenharmony_ci		return HPX_FN_SRIOV_PHYS;
4728c2ecf20Sopenharmony_ci	else
4738c2ecf20Sopenharmony_ci		return HPX_FN_NORMAL;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	u8 cap_ver = hpx3_cap_id & 0xf;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id)
4818c2ecf20Sopenharmony_ci		return true;
4828c2ecf20Sopenharmony_ci	else if (cap_ver == pcie_cap_id)
4838c2ecf20Sopenharmony_ci		return true;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return false;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cienum hpx_type3_cfg_loc {
4898c2ecf20Sopenharmony_ci	HPX_CFG_PCICFG		= 0,
4908c2ecf20Sopenharmony_ci	HPX_CFG_PCIE_CAP	= 1,
4918c2ecf20Sopenharmony_ci	HPX_CFG_PCIE_CAP_EXT	= 2,
4928c2ecf20Sopenharmony_ci	HPX_CFG_VEND_CAP	= 3,
4938c2ecf20Sopenharmony_ci	HPX_CFG_DVSEC		= 4,
4948c2ecf20Sopenharmony_ci	HPX_CFG_MAX,
4958c2ecf20Sopenharmony_ci};
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic void program_hpx_type3_register(struct pci_dev *dev,
4988c2ecf20Sopenharmony_ci				       const struct hpx_type3 *reg)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	u32 match_reg, write_reg, header, orig_value;
5018c2ecf20Sopenharmony_ci	u16 pos;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (!(hpx3_device_type(dev) & reg->device_type))
5048c2ecf20Sopenharmony_ci		return;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (!(hpx3_function_type(dev) & reg->function_type))
5078c2ecf20Sopenharmony_ci		return;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	switch (reg->config_space_location) {
5108c2ecf20Sopenharmony_ci	case HPX_CFG_PCICFG:
5118c2ecf20Sopenharmony_ci		pos = 0;
5128c2ecf20Sopenharmony_ci		break;
5138c2ecf20Sopenharmony_ci	case HPX_CFG_PCIE_CAP:
5148c2ecf20Sopenharmony_ci		pos = pci_find_capability(dev, reg->pci_exp_cap_id);
5158c2ecf20Sopenharmony_ci		if (pos == 0)
5168c2ecf20Sopenharmony_ci			return;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		break;
5198c2ecf20Sopenharmony_ci	case HPX_CFG_PCIE_CAP_EXT:
5208c2ecf20Sopenharmony_ci		pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id);
5218c2ecf20Sopenharmony_ci		if (pos == 0)
5228c2ecf20Sopenharmony_ci			return;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, pos, &header);
5258c2ecf20Sopenharmony_ci		if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header),
5268c2ecf20Sopenharmony_ci					  reg->pci_exp_cap_ver))
5278c2ecf20Sopenharmony_ci			return;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		break;
5308c2ecf20Sopenharmony_ci	case HPX_CFG_VEND_CAP:
5318c2ecf20Sopenharmony_ci	case HPX_CFG_DVSEC:
5328c2ecf20Sopenharmony_ci	default:
5338c2ecf20Sopenharmony_ci		pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location");
5348c2ecf20Sopenharmony_ci		return;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + reg->match_offset, &match_reg);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if ((match_reg & reg->match_mask_and) != reg->match_value)
5408c2ecf20Sopenharmony_ci		return;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg);
5438c2ecf20Sopenharmony_ci	orig_value = write_reg;
5448c2ecf20Sopenharmony_ci	write_reg &= reg->reg_mask_and;
5458c2ecf20Sopenharmony_ci	write_reg |= reg->reg_mask_or;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (orig_value == write_reg)
5488c2ecf20Sopenharmony_ci		return;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	pci_write_config_dword(dev, pos + reg->reg_offset, write_reg);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x",
5538c2ecf20Sopenharmony_ci		pos, orig_value, write_reg);
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	if (!hpx)
5598c2ecf20Sopenharmony_ci		return;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
5628c2ecf20Sopenharmony_ci		return;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	program_hpx_type3_register(dev, hpx);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
5688c2ecf20Sopenharmony_ci				union acpi_object *reg_fields)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	hpx3_reg->device_type            = reg_fields[0].integer.value;
5718c2ecf20Sopenharmony_ci	hpx3_reg->function_type          = reg_fields[1].integer.value;
5728c2ecf20Sopenharmony_ci	hpx3_reg->config_space_location  = reg_fields[2].integer.value;
5738c2ecf20Sopenharmony_ci	hpx3_reg->pci_exp_cap_id         = reg_fields[3].integer.value;
5748c2ecf20Sopenharmony_ci	hpx3_reg->pci_exp_cap_ver        = reg_fields[4].integer.value;
5758c2ecf20Sopenharmony_ci	hpx3_reg->pci_exp_vendor_id      = reg_fields[5].integer.value;
5768c2ecf20Sopenharmony_ci	hpx3_reg->dvsec_id               = reg_fields[6].integer.value;
5778c2ecf20Sopenharmony_ci	hpx3_reg->dvsec_rev              = reg_fields[7].integer.value;
5788c2ecf20Sopenharmony_ci	hpx3_reg->match_offset           = reg_fields[8].integer.value;
5798c2ecf20Sopenharmony_ci	hpx3_reg->match_mask_and         = reg_fields[9].integer.value;
5808c2ecf20Sopenharmony_ci	hpx3_reg->match_value            = reg_fields[10].integer.value;
5818c2ecf20Sopenharmony_ci	hpx3_reg->reg_offset             = reg_fields[11].integer.value;
5828c2ecf20Sopenharmony_ci	hpx3_reg->reg_mask_and           = reg_fields[12].integer.value;
5838c2ecf20Sopenharmony_ci	hpx3_reg->reg_mask_or            = reg_fields[13].integer.value;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic acpi_status program_type3_hpx_record(struct pci_dev *dev,
5878c2ecf20Sopenharmony_ci					   union acpi_object *record)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	union acpi_object *fields = record->package.elements;
5908c2ecf20Sopenharmony_ci	u32 desc_count, expected_length, revision;
5918c2ecf20Sopenharmony_ci	union acpi_object *reg_fields;
5928c2ecf20Sopenharmony_ci	struct hpx_type3 hpx3;
5938c2ecf20Sopenharmony_ci	int i;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	revision = fields[1].integer.value;
5968c2ecf20Sopenharmony_ci	switch (revision) {
5978c2ecf20Sopenharmony_ci	case 1:
5988c2ecf20Sopenharmony_ci		desc_count = fields[2].integer.value;
5998c2ecf20Sopenharmony_ci		expected_length = 3 + desc_count * 14;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		if (record->package.count != expected_length)
6028c2ecf20Sopenharmony_ci			return AE_ERROR;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci		for (i = 2; i < expected_length; i++)
6058c2ecf20Sopenharmony_ci			if (fields[i].type != ACPI_TYPE_INTEGER)
6068c2ecf20Sopenharmony_ci				return AE_ERROR;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		for (i = 0; i < desc_count; i++) {
6098c2ecf20Sopenharmony_ci			reg_fields = fields + 3 + i * 14;
6108c2ecf20Sopenharmony_ci			parse_hpx3_register(&hpx3, reg_fields);
6118c2ecf20Sopenharmony_ci			program_hpx_type3(dev, &hpx3);
6128c2ecf20Sopenharmony_ci		}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		break;
6158c2ecf20Sopenharmony_ci	default:
6168c2ecf20Sopenharmony_ci		printk(KERN_WARNING
6178c2ecf20Sopenharmony_ci			"%s: Type 3 Revision %d record not supported\n",
6188c2ecf20Sopenharmony_ci			__func__, revision);
6198c2ecf20Sopenharmony_ci		return AE_ERROR;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci	return AE_OK;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	acpi_status status;
6278c2ecf20Sopenharmony_ci	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
6288c2ecf20Sopenharmony_ci	union acpi_object *package, *record, *fields;
6298c2ecf20Sopenharmony_ci	struct hpx_type0 hpx0;
6308c2ecf20Sopenharmony_ci	struct hpx_type1 hpx1;
6318c2ecf20Sopenharmony_ci	struct hpx_type2 hpx2;
6328c2ecf20Sopenharmony_ci	u32 type;
6338c2ecf20Sopenharmony_ci	int i;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
6368c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
6378c2ecf20Sopenharmony_ci		return status;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	package = (union acpi_object *)buffer.pointer;
6408c2ecf20Sopenharmony_ci	if (package->type != ACPI_TYPE_PACKAGE) {
6418c2ecf20Sopenharmony_ci		status = AE_ERROR;
6428c2ecf20Sopenharmony_ci		goto exit;
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	for (i = 0; i < package->package.count; i++) {
6468c2ecf20Sopenharmony_ci		record = &package->package.elements[i];
6478c2ecf20Sopenharmony_ci		if (record->type != ACPI_TYPE_PACKAGE) {
6488c2ecf20Sopenharmony_ci			status = AE_ERROR;
6498c2ecf20Sopenharmony_ci			goto exit;
6508c2ecf20Sopenharmony_ci		}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		fields = record->package.elements;
6538c2ecf20Sopenharmony_ci		if (fields[0].type != ACPI_TYPE_INTEGER ||
6548c2ecf20Sopenharmony_ci		    fields[1].type != ACPI_TYPE_INTEGER) {
6558c2ecf20Sopenharmony_ci			status = AE_ERROR;
6568c2ecf20Sopenharmony_ci			goto exit;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		type = fields[0].integer.value;
6608c2ecf20Sopenharmony_ci		switch (type) {
6618c2ecf20Sopenharmony_ci		case 0:
6628c2ecf20Sopenharmony_ci			memset(&hpx0, 0, sizeof(hpx0));
6638c2ecf20Sopenharmony_ci			status = decode_type0_hpx_record(record, &hpx0);
6648c2ecf20Sopenharmony_ci			if (ACPI_FAILURE(status))
6658c2ecf20Sopenharmony_ci				goto exit;
6668c2ecf20Sopenharmony_ci			program_hpx_type0(dev, &hpx0);
6678c2ecf20Sopenharmony_ci			break;
6688c2ecf20Sopenharmony_ci		case 1:
6698c2ecf20Sopenharmony_ci			memset(&hpx1, 0, sizeof(hpx1));
6708c2ecf20Sopenharmony_ci			status = decode_type1_hpx_record(record, &hpx1);
6718c2ecf20Sopenharmony_ci			if (ACPI_FAILURE(status))
6728c2ecf20Sopenharmony_ci				goto exit;
6738c2ecf20Sopenharmony_ci			program_hpx_type1(dev, &hpx1);
6748c2ecf20Sopenharmony_ci			break;
6758c2ecf20Sopenharmony_ci		case 2:
6768c2ecf20Sopenharmony_ci			memset(&hpx2, 0, sizeof(hpx2));
6778c2ecf20Sopenharmony_ci			status = decode_type2_hpx_record(record, &hpx2);
6788c2ecf20Sopenharmony_ci			if (ACPI_FAILURE(status))
6798c2ecf20Sopenharmony_ci				goto exit;
6808c2ecf20Sopenharmony_ci			program_hpx_type2(dev, &hpx2);
6818c2ecf20Sopenharmony_ci			break;
6828c2ecf20Sopenharmony_ci		case 3:
6838c2ecf20Sopenharmony_ci			status = program_type3_hpx_record(dev, record);
6848c2ecf20Sopenharmony_ci			if (ACPI_FAILURE(status))
6858c2ecf20Sopenharmony_ci				goto exit;
6868c2ecf20Sopenharmony_ci			break;
6878c2ecf20Sopenharmony_ci		default:
6888c2ecf20Sopenharmony_ci			pr_err("%s: Type %d record not supported\n",
6898c2ecf20Sopenharmony_ci			       __func__, type);
6908c2ecf20Sopenharmony_ci			status = AE_ERROR;
6918c2ecf20Sopenharmony_ci			goto exit;
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci exit:
6958c2ecf20Sopenharmony_ci	kfree(buffer.pointer);
6968c2ecf20Sopenharmony_ci	return status;
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle)
7008c2ecf20Sopenharmony_ci{
7018c2ecf20Sopenharmony_ci	acpi_status status;
7028c2ecf20Sopenharmony_ci	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
7038c2ecf20Sopenharmony_ci	union acpi_object *package, *fields;
7048c2ecf20Sopenharmony_ci	struct hpx_type0 hpx0;
7058c2ecf20Sopenharmony_ci	int i;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	memset(&hpx0, 0, sizeof(hpx0));
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
7108c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
7118c2ecf20Sopenharmony_ci		return status;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	package = (union acpi_object *) buffer.pointer;
7148c2ecf20Sopenharmony_ci	if (package->type != ACPI_TYPE_PACKAGE ||
7158c2ecf20Sopenharmony_ci	    package->package.count != 4) {
7168c2ecf20Sopenharmony_ci		status = AE_ERROR;
7178c2ecf20Sopenharmony_ci		goto exit;
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	fields = package->package.elements;
7218c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
7228c2ecf20Sopenharmony_ci		if (fields[i].type != ACPI_TYPE_INTEGER) {
7238c2ecf20Sopenharmony_ci			status = AE_ERROR;
7248c2ecf20Sopenharmony_ci			goto exit;
7258c2ecf20Sopenharmony_ci		}
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	hpx0.revision        = 1;
7298c2ecf20Sopenharmony_ci	hpx0.cache_line_size = fields[0].integer.value;
7308c2ecf20Sopenharmony_ci	hpx0.latency_timer   = fields[1].integer.value;
7318c2ecf20Sopenharmony_ci	hpx0.enable_serr     = fields[2].integer.value;
7328c2ecf20Sopenharmony_ci	hpx0.enable_perr     = fields[3].integer.value;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	program_hpx_type0(dev, &hpx0);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ciexit:
7378c2ecf20Sopenharmony_ci	kfree(buffer.pointer);
7388c2ecf20Sopenharmony_ci	return status;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci/* pci_acpi_program_hp_params
7428c2ecf20Sopenharmony_ci *
7438c2ecf20Sopenharmony_ci * @dev - the pci_dev for which we want parameters
7448c2ecf20Sopenharmony_ci */
7458c2ecf20Sopenharmony_ciint pci_acpi_program_hp_params(struct pci_dev *dev)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	acpi_status status;
7488c2ecf20Sopenharmony_ci	acpi_handle handle, phandle;
7498c2ecf20Sopenharmony_ci	struct pci_bus *pbus;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	if (acpi_pci_disabled)
7528c2ecf20Sopenharmony_ci		return -ENODEV;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	handle = NULL;
7558c2ecf20Sopenharmony_ci	for (pbus = dev->bus; pbus; pbus = pbus->parent) {
7568c2ecf20Sopenharmony_ci		handle = acpi_pci_get_bridge_handle(pbus);
7578c2ecf20Sopenharmony_ci		if (handle)
7588c2ecf20Sopenharmony_ci			break;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	/*
7628c2ecf20Sopenharmony_ci	 * _HPP settings apply to all child buses, until another _HPP is
7638c2ecf20Sopenharmony_ci	 * encountered. If we don't find an _HPP for the input pci dev,
7648c2ecf20Sopenharmony_ci	 * look for it in the parent device scope since that would apply to
7658c2ecf20Sopenharmony_ci	 * this pci dev.
7668c2ecf20Sopenharmony_ci	 */
7678c2ecf20Sopenharmony_ci	while (handle) {
7688c2ecf20Sopenharmony_ci		status = acpi_run_hpx(dev, handle);
7698c2ecf20Sopenharmony_ci		if (ACPI_SUCCESS(status))
7708c2ecf20Sopenharmony_ci			return 0;
7718c2ecf20Sopenharmony_ci		status = acpi_run_hpp(dev, handle);
7728c2ecf20Sopenharmony_ci		if (ACPI_SUCCESS(status))
7738c2ecf20Sopenharmony_ci			return 0;
7748c2ecf20Sopenharmony_ci		if (acpi_is_root_bridge(handle))
7758c2ecf20Sopenharmony_ci			break;
7768c2ecf20Sopenharmony_ci		status = acpi_get_parent(handle, &phandle);
7778c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(status))
7788c2ecf20Sopenharmony_ci			break;
7798c2ecf20Sopenharmony_ci		handle = phandle;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci	return -ENODEV;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci/**
7858c2ecf20Sopenharmony_ci * pciehp_is_native - Check whether a hotplug port is handled by the OS
7868c2ecf20Sopenharmony_ci * @bridge: Hotplug port to check
7878c2ecf20Sopenharmony_ci *
7888c2ecf20Sopenharmony_ci * Returns true if the given @bridge is handled by the native PCIe hotplug
7898c2ecf20Sopenharmony_ci * driver.
7908c2ecf20Sopenharmony_ci */
7918c2ecf20Sopenharmony_cibool pciehp_is_native(struct pci_dev *bridge)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	const struct pci_host_bridge *host;
7948c2ecf20Sopenharmony_ci	u32 slot_cap;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
7978c2ecf20Sopenharmony_ci		return false;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
8008c2ecf20Sopenharmony_ci	if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
8018c2ecf20Sopenharmony_ci		return false;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (pcie_ports_native)
8048c2ecf20Sopenharmony_ci		return true;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	host = pci_find_host_bridge(bridge->bus);
8078c2ecf20Sopenharmony_ci	return host->native_pcie_hotplug;
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci/**
8118c2ecf20Sopenharmony_ci * shpchp_is_native - Check whether a hotplug port is handled by the OS
8128c2ecf20Sopenharmony_ci * @bridge: Hotplug port to check
8138c2ecf20Sopenharmony_ci *
8148c2ecf20Sopenharmony_ci * Returns true if the given @bridge is handled by the native SHPC hotplug
8158c2ecf20Sopenharmony_ci * driver.
8168c2ecf20Sopenharmony_ci */
8178c2ecf20Sopenharmony_cibool shpchp_is_native(struct pci_dev *bridge)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	return bridge->shpc_managed;
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci/**
8238c2ecf20Sopenharmony_ci * pci_acpi_wake_bus - Root bus wakeup notification fork function.
8248c2ecf20Sopenharmony_ci * @context: Device wakeup context.
8258c2ecf20Sopenharmony_ci */
8268c2ecf20Sopenharmony_cistatic void pci_acpi_wake_bus(struct acpi_device_wakeup_context *context)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	struct acpi_device *adev;
8298c2ecf20Sopenharmony_ci	struct acpi_pci_root *root;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	adev = container_of(context, struct acpi_device, wakeup.context);
8328c2ecf20Sopenharmony_ci	root = acpi_driver_data(adev);
8338c2ecf20Sopenharmony_ci	pci_pme_wakeup_bus(root->bus);
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci/**
8378c2ecf20Sopenharmony_ci * pci_acpi_wake_dev - PCI device wakeup notification work function.
8388c2ecf20Sopenharmony_ci * @context: Device wakeup context.
8398c2ecf20Sopenharmony_ci */
8408c2ecf20Sopenharmony_cistatic void pci_acpi_wake_dev(struct acpi_device_wakeup_context *context)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	struct pci_dev *pci_dev;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	pci_dev = to_pci_dev(context->dev);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	if (pci_dev->pme_poll)
8478c2ecf20Sopenharmony_ci		pci_dev->pme_poll = false;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (pci_dev->current_state == PCI_D3cold) {
8508c2ecf20Sopenharmony_ci		pci_wakeup_event(pci_dev);
8518c2ecf20Sopenharmony_ci		pm_request_resume(&pci_dev->dev);
8528c2ecf20Sopenharmony_ci		return;
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	/* Clear PME Status if set. */
8568c2ecf20Sopenharmony_ci	if (pci_dev->pme_support)
8578c2ecf20Sopenharmony_ci		pci_check_pme_status(pci_dev);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	pci_wakeup_event(pci_dev);
8608c2ecf20Sopenharmony_ci	pm_request_resume(&pci_dev->dev);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	pci_pme_wakeup_bus(pci_dev->subordinate);
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/**
8668c2ecf20Sopenharmony_ci * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
8678c2ecf20Sopenharmony_ci * @dev: PCI root bridge ACPI device.
8688c2ecf20Sopenharmony_ci */
8698c2ecf20Sopenharmony_ciacpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus);
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci/**
8758c2ecf20Sopenharmony_ci * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device.
8768c2ecf20Sopenharmony_ci * @dev: ACPI device to add the notifier for.
8778c2ecf20Sopenharmony_ci * @pci_dev: PCI device to check for the PME status if an event is signaled.
8788c2ecf20Sopenharmony_ci */
8798c2ecf20Sopenharmony_ciacpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
8808c2ecf20Sopenharmony_ci				     struct pci_dev *pci_dev)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci/*
8868c2ecf20Sopenharmony_ci * _SxD returns the D-state with the highest power
8878c2ecf20Sopenharmony_ci * (lowest D-state number) supported in the S-state "x".
8888c2ecf20Sopenharmony_ci *
8898c2ecf20Sopenharmony_ci * If the devices does not have a _PRW
8908c2ecf20Sopenharmony_ci * (Power Resources for Wake) supporting system wakeup from "x"
8918c2ecf20Sopenharmony_ci * then the OS is free to choose a lower power (higher number
8928c2ecf20Sopenharmony_ci * D-state) than the return value from _SxD.
8938c2ecf20Sopenharmony_ci *
8948c2ecf20Sopenharmony_ci * But if _PRW is enabled at S-state "x", the OS
8958c2ecf20Sopenharmony_ci * must not choose a power lower than _SxD --
8968c2ecf20Sopenharmony_ci * unless the device has an _SxW method specifying
8978c2ecf20Sopenharmony_ci * the lowest power (highest D-state number) the device
8988c2ecf20Sopenharmony_ci * may enter while still able to wake the system.
8998c2ecf20Sopenharmony_ci *
9008c2ecf20Sopenharmony_ci * ie. depending on global OS policy:
9018c2ecf20Sopenharmony_ci *
9028c2ecf20Sopenharmony_ci * if (_PRW at S-state x)
9038c2ecf20Sopenharmony_ci *	choose from highest power _SxD to lowest power _SxW
9048c2ecf20Sopenharmony_ci * else // no _PRW at S-state x
9058c2ecf20Sopenharmony_ci *	choose highest power _SxD or any lower power
9068c2ecf20Sopenharmony_ci */
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	int acpi_state, d_max;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (pdev->no_d3cold || !pdev->d3cold_allowed)
9138c2ecf20Sopenharmony_ci		d_max = ACPI_STATE_D3_HOT;
9148c2ecf20Sopenharmony_ci	else
9158c2ecf20Sopenharmony_ci		d_max = ACPI_STATE_D3_COLD;
9168c2ecf20Sopenharmony_ci	acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL, d_max);
9178c2ecf20Sopenharmony_ci	if (acpi_state < 0)
9188c2ecf20Sopenharmony_ci		return PCI_POWER_ERROR;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	switch (acpi_state) {
9218c2ecf20Sopenharmony_ci	case ACPI_STATE_D0:
9228c2ecf20Sopenharmony_ci		return PCI_D0;
9238c2ecf20Sopenharmony_ci	case ACPI_STATE_D1:
9248c2ecf20Sopenharmony_ci		return PCI_D1;
9258c2ecf20Sopenharmony_ci	case ACPI_STATE_D2:
9268c2ecf20Sopenharmony_ci		return PCI_D2;
9278c2ecf20Sopenharmony_ci	case ACPI_STATE_D3_HOT:
9288c2ecf20Sopenharmony_ci		return PCI_D3hot;
9298c2ecf20Sopenharmony_ci	case ACPI_STATE_D3_COLD:
9308c2ecf20Sopenharmony_ci		return PCI_D3cold;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci	return PCI_POWER_ERROR;
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic struct acpi_device *acpi_pci_find_companion(struct device *dev);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic bool acpi_pci_bridge_d3(struct pci_dev *dev)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	const struct fwnode_handle *fwnode;
9408c2ecf20Sopenharmony_ci	struct acpi_device *adev;
9418c2ecf20Sopenharmony_ci	struct pci_dev *root;
9428c2ecf20Sopenharmony_ci	u8 val;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	if (!dev->is_hotplug_bridge)
9458c2ecf20Sopenharmony_ci		return false;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* Assume D3 support if the bridge is power-manageable by ACPI. */
9488c2ecf20Sopenharmony_ci	adev = ACPI_COMPANION(&dev->dev);
9498c2ecf20Sopenharmony_ci	if (!adev && !pci_dev_is_added(dev)) {
9508c2ecf20Sopenharmony_ci		adev = acpi_pci_find_companion(&dev->dev);
9518c2ecf20Sopenharmony_ci		ACPI_COMPANION_SET(&dev->dev, adev);
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	if (adev && acpi_device_power_manageable(adev))
9558c2ecf20Sopenharmony_ci		return true;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	/*
9588c2ecf20Sopenharmony_ci	 * Look for a special _DSD property for the root port and if it
9598c2ecf20Sopenharmony_ci	 * is set we know the hierarchy behind it supports D3 just fine.
9608c2ecf20Sopenharmony_ci	 */
9618c2ecf20Sopenharmony_ci	root = pcie_find_root_port(dev);
9628c2ecf20Sopenharmony_ci	if (!root)
9638c2ecf20Sopenharmony_ci		return false;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	adev = ACPI_COMPANION(&root->dev);
9668c2ecf20Sopenharmony_ci	if (root == dev) {
9678c2ecf20Sopenharmony_ci		/*
9688c2ecf20Sopenharmony_ci		 * It is possible that the ACPI companion is not yet bound
9698c2ecf20Sopenharmony_ci		 * for the root port so look it up manually here.
9708c2ecf20Sopenharmony_ci		 */
9718c2ecf20Sopenharmony_ci		if (!adev && !pci_dev_is_added(root))
9728c2ecf20Sopenharmony_ci			adev = acpi_pci_find_companion(&root->dev);
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (!adev)
9768c2ecf20Sopenharmony_ci		return false;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	fwnode = acpi_fwnode_handle(adev);
9798c2ecf20Sopenharmony_ci	if (fwnode_property_read_u8(fwnode, "HotPlugSupportInD3", &val))
9808c2ecf20Sopenharmony_ci		return false;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	return val == 1;
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic bool acpi_pci_power_manageable(struct pci_dev *dev)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
9888c2ecf20Sopenharmony_ci	return adev ? acpi_device_power_manageable(adev) : false;
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cistatic int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
9948c2ecf20Sopenharmony_ci	static const u8 state_conv[] = {
9958c2ecf20Sopenharmony_ci		[PCI_D0] = ACPI_STATE_D0,
9968c2ecf20Sopenharmony_ci		[PCI_D1] = ACPI_STATE_D1,
9978c2ecf20Sopenharmony_ci		[PCI_D2] = ACPI_STATE_D2,
9988c2ecf20Sopenharmony_ci		[PCI_D3hot] = ACPI_STATE_D3_HOT,
9998c2ecf20Sopenharmony_ci		[PCI_D3cold] = ACPI_STATE_D3_COLD,
10008c2ecf20Sopenharmony_ci	};
10018c2ecf20Sopenharmony_ci	int error = -EINVAL;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* If the ACPI device has _EJ0, ignore the device */
10048c2ecf20Sopenharmony_ci	if (!adev || acpi_has_method(adev->handle, "_EJ0"))
10058c2ecf20Sopenharmony_ci		return -ENODEV;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	switch (state) {
10088c2ecf20Sopenharmony_ci	case PCI_D3cold:
10098c2ecf20Sopenharmony_ci		if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
10108c2ecf20Sopenharmony_ci				PM_QOS_FLAGS_ALL) {
10118c2ecf20Sopenharmony_ci			error = -EBUSY;
10128c2ecf20Sopenharmony_ci			break;
10138c2ecf20Sopenharmony_ci		}
10148c2ecf20Sopenharmony_ci		fallthrough;
10158c2ecf20Sopenharmony_ci	case PCI_D0:
10168c2ecf20Sopenharmony_ci	case PCI_D1:
10178c2ecf20Sopenharmony_ci	case PCI_D2:
10188c2ecf20Sopenharmony_ci	case PCI_D3hot:
10198c2ecf20Sopenharmony_ci		error = acpi_device_set_power(adev, state_conv[state]);
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (!error)
10238c2ecf20Sopenharmony_ci		pci_dbg(dev, "power state changed by ACPI to %s\n",
10248c2ecf20Sopenharmony_ci			 acpi_power_state_string(state_conv[state]));
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	return error;
10278c2ecf20Sopenharmony_ci}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_cistatic pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
10328c2ecf20Sopenharmony_ci	static const pci_power_t state_conv[] = {
10338c2ecf20Sopenharmony_ci		[ACPI_STATE_D0]      = PCI_D0,
10348c2ecf20Sopenharmony_ci		[ACPI_STATE_D1]      = PCI_D1,
10358c2ecf20Sopenharmony_ci		[ACPI_STATE_D2]      = PCI_D2,
10368c2ecf20Sopenharmony_ci		[ACPI_STATE_D3_HOT]  = PCI_D3hot,
10378c2ecf20Sopenharmony_ci		[ACPI_STATE_D3_COLD] = PCI_D3cold,
10388c2ecf20Sopenharmony_ci	};
10398c2ecf20Sopenharmony_ci	int state;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	if (!adev || !acpi_device_power_manageable(adev))
10428c2ecf20Sopenharmony_ci		return PCI_UNKNOWN;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	state = adev->power.state;
10458c2ecf20Sopenharmony_ci	if (state == ACPI_STATE_UNKNOWN)
10468c2ecf20Sopenharmony_ci		return PCI_UNKNOWN;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	return state_conv[state];
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic void acpi_pci_refresh_power_state(struct pci_dev *dev)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (adev && acpi_device_power_manageable(adev))
10568c2ecf20Sopenharmony_ci		acpi_device_update_power(adev, NULL);
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	while (bus->parent) {
10628c2ecf20Sopenharmony_ci		if (acpi_pm_device_can_wakeup(&bus->self->dev))
10638c2ecf20Sopenharmony_ci			return acpi_pm_set_device_wakeup(&bus->self->dev, enable);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci		bus = bus->parent;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	/* We have reached the root bus. */
10698c2ecf20Sopenharmony_ci	if (bus->bridge) {
10708c2ecf20Sopenharmony_ci		if (acpi_pm_device_can_wakeup(bus->bridge))
10718c2ecf20Sopenharmony_ci			return acpi_pm_set_device_wakeup(bus->bridge, enable);
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci	return 0;
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_cistatic int acpi_pci_wakeup(struct pci_dev *dev, bool enable)
10778c2ecf20Sopenharmony_ci{
10788c2ecf20Sopenharmony_ci	if (acpi_pm_device_can_wakeup(&dev->dev))
10798c2ecf20Sopenharmony_ci		return acpi_pm_set_device_wakeup(&dev->dev, enable);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	return acpi_pci_propagate_wakeup(dev->bus, enable);
10828c2ecf20Sopenharmony_ci}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_cistatic bool acpi_pci_need_resume(struct pci_dev *dev)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	/*
10898c2ecf20Sopenharmony_ci	 * In some cases (eg. Samsung 305V4A) leaving a bridge in suspend over
10908c2ecf20Sopenharmony_ci	 * system-wide suspend/resume confuses the platform firmware, so avoid
10918c2ecf20Sopenharmony_ci	 * doing that.  According to Section 16.1.6 of ACPI 6.2, endpoint
10928c2ecf20Sopenharmony_ci	 * devices are expected to be in D3 before invoking the S3 entry path
10938c2ecf20Sopenharmony_ci	 * from the firmware, so they should not be affected by this issue.
10948c2ecf20Sopenharmony_ci	 */
10958c2ecf20Sopenharmony_ci	if (pci_is_bridge(dev) && acpi_target_system_state() != ACPI_STATE_S0)
10968c2ecf20Sopenharmony_ci		return true;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (!adev || !acpi_device_power_manageable(adev))
10998c2ecf20Sopenharmony_ci		return false;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	if (adev->wakeup.flags.valid &&
11028c2ecf20Sopenharmony_ci	    device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count)
11038c2ecf20Sopenharmony_ci		return true;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (acpi_target_system_state() == ACPI_STATE_S0)
11068c2ecf20Sopenharmony_ci		return false;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	return !!adev->power.flags.dsw_present;
11098c2ecf20Sopenharmony_ci}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_cistatic const struct pci_platform_pm_ops acpi_pci_platform_pm = {
11128c2ecf20Sopenharmony_ci	.bridge_d3 = acpi_pci_bridge_d3,
11138c2ecf20Sopenharmony_ci	.is_manageable = acpi_pci_power_manageable,
11148c2ecf20Sopenharmony_ci	.set_state = acpi_pci_set_power_state,
11158c2ecf20Sopenharmony_ci	.get_state = acpi_pci_get_power_state,
11168c2ecf20Sopenharmony_ci	.refresh_state = acpi_pci_refresh_power_state,
11178c2ecf20Sopenharmony_ci	.choose_state = acpi_pci_choose_state,
11188c2ecf20Sopenharmony_ci	.set_wakeup = acpi_pci_wakeup,
11198c2ecf20Sopenharmony_ci	.need_resume = acpi_pci_need_resume,
11208c2ecf20Sopenharmony_ci};
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_civoid acpi_pci_add_bus(struct pci_bus *bus)
11238c2ecf20Sopenharmony_ci{
11248c2ecf20Sopenharmony_ci	union acpi_object *obj;
11258c2ecf20Sopenharmony_ci	struct pci_host_bridge *bridge;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge))
11288c2ecf20Sopenharmony_ci		return;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	acpi_pci_slot_enumerate(bus);
11318c2ecf20Sopenharmony_ci	acpiphp_enumerate_slots(bus);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	/*
11348c2ecf20Sopenharmony_ci	 * For a host bridge, check its _DSM for function 8 and if
11358c2ecf20Sopenharmony_ci	 * that is available, mark it in pci_host_bridge.
11368c2ecf20Sopenharmony_ci	 */
11378c2ecf20Sopenharmony_ci	if (!pci_is_root_bus(bus))
11388c2ecf20Sopenharmony_ci		return;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3,
11418c2ecf20Sopenharmony_ci				DSM_PCI_POWER_ON_RESET_DELAY, NULL);
11428c2ecf20Sopenharmony_ci	if (!obj)
11438c2ecf20Sopenharmony_ci		return;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
11468c2ecf20Sopenharmony_ci		bridge = pci_find_host_bridge(bus);
11478c2ecf20Sopenharmony_ci		bridge->ignore_reset_delay = 1;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci	ACPI_FREE(obj);
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_civoid acpi_pci_remove_bus(struct pci_bus *bus)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	if (acpi_pci_disabled || !bus->bridge)
11558c2ecf20Sopenharmony_ci		return;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	acpiphp_remove_slots(bus);
11588c2ecf20Sopenharmony_ci	acpi_pci_slot_remove(bus);
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci/* ACPI bus type */
11628c2ecf20Sopenharmony_cistatic struct acpi_device *acpi_pci_find_companion(struct device *dev)
11638c2ecf20Sopenharmony_ci{
11648c2ecf20Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
11658c2ecf20Sopenharmony_ci	bool check_children;
11668c2ecf20Sopenharmony_ci	u64 addr;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	check_children = pci_is_bridge(pci_dev);
11698c2ecf20Sopenharmony_ci	/* Please ref to ACPI spec for the syntax of _ADR */
11708c2ecf20Sopenharmony_ci	addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
11718c2ecf20Sopenharmony_ci	return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
11728c2ecf20Sopenharmony_ci				      check_children);
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci/**
11768c2ecf20Sopenharmony_ci * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
11778c2ecf20Sopenharmony_ci * @pdev: the PCI device whose delay is to be updated
11788c2ecf20Sopenharmony_ci * @handle: ACPI handle of this device
11798c2ecf20Sopenharmony_ci *
11808c2ecf20Sopenharmony_ci * Update the d3hot_delay and d3cold_delay of a PCI device from the ACPI _DSM
11818c2ecf20Sopenharmony_ci * control method of either the device itself or the PCI host bridge.
11828c2ecf20Sopenharmony_ci *
11838c2ecf20Sopenharmony_ci * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
11848c2ecf20Sopenharmony_ci * host bridge.  If it returns one, the OS may assume that all devices in
11858c2ecf20Sopenharmony_ci * the hierarchy have already completed power-on reset delays.
11868c2ecf20Sopenharmony_ci *
11878c2ecf20Sopenharmony_ci * Function 9, "Device Readiness Durations," applies only to the object
11888c2ecf20Sopenharmony_ci * where it is located.  It returns delay durations required after various
11898c2ecf20Sopenharmony_ci * events if the device requires less time than the spec requires.  Delays
11908c2ecf20Sopenharmony_ci * from this function take precedence over the Reset Delay function.
11918c2ecf20Sopenharmony_ci *
11928c2ecf20Sopenharmony_ci * These _DSM functions are defined by the draft ECN of January 28, 2014,
11938c2ecf20Sopenharmony_ci * titled "ACPI additions for FW latency optimizations."
11948c2ecf20Sopenharmony_ci */
11958c2ecf20Sopenharmony_cistatic void pci_acpi_optimize_delay(struct pci_dev *pdev,
11968c2ecf20Sopenharmony_ci				    acpi_handle handle)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
11998c2ecf20Sopenharmony_ci	int value;
12008c2ecf20Sopenharmony_ci	union acpi_object *obj, *elements;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	if (bridge->ignore_reset_delay)
12038c2ecf20Sopenharmony_ci		pdev->d3cold_delay = 0;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3,
12068c2ecf20Sopenharmony_ci				DSM_PCI_DEVICE_READINESS_DURATIONS, NULL);
12078c2ecf20Sopenharmony_ci	if (!obj)
12088c2ecf20Sopenharmony_ci		return;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
12118c2ecf20Sopenharmony_ci		elements = obj->package.elements;
12128c2ecf20Sopenharmony_ci		if (elements[0].type == ACPI_TYPE_INTEGER) {
12138c2ecf20Sopenharmony_ci			value = (int)elements[0].integer.value / 1000;
12148c2ecf20Sopenharmony_ci			if (value < PCI_PM_D3COLD_WAIT)
12158c2ecf20Sopenharmony_ci				pdev->d3cold_delay = value;
12168c2ecf20Sopenharmony_ci		}
12178c2ecf20Sopenharmony_ci		if (elements[3].type == ACPI_TYPE_INTEGER) {
12188c2ecf20Sopenharmony_ci			value = (int)elements[3].integer.value / 1000;
12198c2ecf20Sopenharmony_ci			if (value < PCI_PM_D3HOT_WAIT)
12208c2ecf20Sopenharmony_ci				pdev->d3hot_delay = value;
12218c2ecf20Sopenharmony_ci		}
12228c2ecf20Sopenharmony_ci	}
12238c2ecf20Sopenharmony_ci	ACPI_FREE(obj);
12248c2ecf20Sopenharmony_ci}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_cistatic void pci_acpi_set_external_facing(struct pci_dev *dev)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	u8 val;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
12318c2ecf20Sopenharmony_ci		return;
12328c2ecf20Sopenharmony_ci	if (device_property_read_u8(&dev->dev, "ExternalFacingPort", &val))
12338c2ecf20Sopenharmony_ci		return;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	/*
12368c2ecf20Sopenharmony_ci	 * These root ports expose PCIe (including DMA) outside of the
12378c2ecf20Sopenharmony_ci	 * system.  Everything downstream from them is external.
12388c2ecf20Sopenharmony_ci	 */
12398c2ecf20Sopenharmony_ci	if (val)
12408c2ecf20Sopenharmony_ci		dev->external_facing = 1;
12418c2ecf20Sopenharmony_ci}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_cistatic void pci_acpi_setup(struct device *dev)
12448c2ecf20Sopenharmony_ci{
12458c2ecf20Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
12468c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	if (!adev)
12498c2ecf20Sopenharmony_ci		return;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	pci_acpi_optimize_delay(pci_dev, adev->handle);
12528c2ecf20Sopenharmony_ci	pci_acpi_set_external_facing(pci_dev);
12538c2ecf20Sopenharmony_ci	pci_acpi_add_edr_notifier(pci_dev);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	pci_acpi_add_pm_notifier(adev, pci_dev);
12568c2ecf20Sopenharmony_ci	if (!adev->wakeup.flags.valid)
12578c2ecf20Sopenharmony_ci		return;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	device_set_wakeup_capable(dev, true);
12608c2ecf20Sopenharmony_ci	/*
12618c2ecf20Sopenharmony_ci	 * For bridges that can do D3 we enable wake automatically (as
12628c2ecf20Sopenharmony_ci	 * we do for the power management itself in that case). The
12638c2ecf20Sopenharmony_ci	 * reason is that the bridge may have additional methods such as
12648c2ecf20Sopenharmony_ci	 * _DSW that need to be called.
12658c2ecf20Sopenharmony_ci	 */
12668c2ecf20Sopenharmony_ci	if (pci_dev->bridge_d3)
12678c2ecf20Sopenharmony_ci		device_wakeup_enable(dev);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	acpi_pci_wakeup(pci_dev, false);
12708c2ecf20Sopenharmony_ci	acpi_device_power_add_dependent(adev, dev);
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic void pci_acpi_cleanup(struct device *dev)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
12768c2ecf20Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (!adev)
12798c2ecf20Sopenharmony_ci		return;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	pci_acpi_remove_edr_notifier(pci_dev);
12828c2ecf20Sopenharmony_ci	pci_acpi_remove_pm_notifier(adev);
12838c2ecf20Sopenharmony_ci	if (adev->wakeup.flags.valid) {
12848c2ecf20Sopenharmony_ci		acpi_device_power_remove_dependent(adev, dev);
12858c2ecf20Sopenharmony_ci		if (pci_dev->bridge_d3)
12868c2ecf20Sopenharmony_ci			device_wakeup_disable(dev);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci		device_set_wakeup_capable(dev, false);
12898c2ecf20Sopenharmony_ci	}
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic bool pci_acpi_bus_match(struct device *dev)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	return dev_is_pci(dev);
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistatic struct acpi_bus_type acpi_pci_bus = {
12988c2ecf20Sopenharmony_ci	.name = "PCI",
12998c2ecf20Sopenharmony_ci	.match = pci_acpi_bus_match,
13008c2ecf20Sopenharmony_ci	.find_companion = acpi_pci_find_companion,
13018c2ecf20Sopenharmony_ci	.setup = pci_acpi_setup,
13028c2ecf20Sopenharmony_ci	.cleanup = pci_acpi_cleanup,
13038c2ecf20Sopenharmony_ci};
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_cistatic struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev);
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci/**
13098c2ecf20Sopenharmony_ci * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode
13108c2ecf20Sopenharmony_ci * @fn:       Callback matching a device to a fwnode that identifies a PCI
13118c2ecf20Sopenharmony_ci *            MSI domain.
13128c2ecf20Sopenharmony_ci *
13138c2ecf20Sopenharmony_ci * This should be called by irqchip driver, which is the parent of
13148c2ecf20Sopenharmony_ci * the MSI domain to provide callback interface to query fwnode.
13158c2ecf20Sopenharmony_ci */
13168c2ecf20Sopenharmony_civoid
13178c2ecf20Sopenharmony_cipci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *))
13188c2ecf20Sopenharmony_ci{
13198c2ecf20Sopenharmony_ci	pci_msi_get_fwnode_cb = fn;
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci/**
13238c2ecf20Sopenharmony_ci * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge
13248c2ecf20Sopenharmony_ci * @bus:      The PCI host bridge bus.
13258c2ecf20Sopenharmony_ci *
13268c2ecf20Sopenharmony_ci * This function uses the callback function registered by
13278c2ecf20Sopenharmony_ci * pci_msi_register_fwnode_provider() to retrieve the irq_domain with
13288c2ecf20Sopenharmony_ci * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus.
13298c2ecf20Sopenharmony_ci * This returns NULL on error or when the domain is not found.
13308c2ecf20Sopenharmony_ci */
13318c2ecf20Sopenharmony_cistruct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	struct fwnode_handle *fwnode;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	if (!pci_msi_get_fwnode_cb)
13368c2ecf20Sopenharmony_ci		return NULL;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	fwnode = pci_msi_get_fwnode_cb(&bus->dev);
13398c2ecf20Sopenharmony_ci	if (!fwnode)
13408c2ecf20Sopenharmony_ci		return NULL;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_cistatic int __init acpi_pci_init(void)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	int ret;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) {
13508c2ecf20Sopenharmony_ci		pr_info("ACPI FADT declares the system doesn't support MSI, so disable it\n");
13518c2ecf20Sopenharmony_ci		pci_no_msi();
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
13558c2ecf20Sopenharmony_ci		pr_info("ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
13568c2ecf20Sopenharmony_ci		pcie_no_aspm();
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	ret = register_acpi_bus_type(&acpi_pci_bus);
13608c2ecf20Sopenharmony_ci	if (ret)
13618c2ecf20Sopenharmony_ci		return 0;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	pci_set_platform_pm(&acpi_pci_platform_pm);
13648c2ecf20Sopenharmony_ci	acpi_pci_slot_init();
13658c2ecf20Sopenharmony_ci	acpiphp_init();
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	return 0;
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ciarch_initcall(acpi_pci_init);
1370