xref: /openbmc/linux/drivers/pci/pci-acpi.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3df62ab5eSBjorn Helgaas  * PCI support in ACPI
41da177e4SLinus Torvalds  *
584df749fSDavid Shaohua Li  * Copyright (C) 2005 David Shaohua Li <shaohua.li@intel.com>
684df749fSDavid Shaohua Li  * Copyright (C) 2004 Tom Long Nguyen <tom.l.nguyen@intel.com>
784df749fSDavid Shaohua Li  * Copyright (C) 2004 Intel Corp.
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/delay.h>
111da177e4SLinus Torvalds #include <linux/init.h>
12471036b2SSuravee Suthikulpanit #include <linux/irqdomain.h>
131da177e4SLinus Torvalds #include <linux/pci.h>
14471036b2SSuravee Suthikulpanit #include <linux/msi.h>
159ce90ea5SBjorn Helgaas #include <linux/pci_hotplug.h>
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/pci-acpi.h>
18b67ea761SRafael J. Wysocki #include <linux/pm_runtime.h>
198b713a88SRafael J. Wysocki #include <linux/pm_qos.h>
2059dc3325SRafael J. Wysocki #include <linux/rwsem.h>
210f64474bSDavid Shaohua Li #include "pci.h"
221da177e4SLinus Torvalds 
2318e94a33SAaron Lu /*
246943f3e3SMario Limonciello  * The GUID is defined in the PCI Firmware Specification available
256943f3e3SMario Limonciello  * here to PCI-SIG members:
266943f3e3SMario Limonciello  * https://members.pcisig.com/wg/PCI-SIG/document/15350
2718e94a33SAaron Lu  */
2894116f81SAndy Shevchenko const guid_t pci_acpi_dsm_guid =
2994116f81SAndy Shevchenko 	GUID_INIT(0xe5c937d0, 0x3553, 0x4d7a,
3094116f81SAndy Shevchenko 		  0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d);
3118e94a33SAaron Lu 
32169de969SDongdong Liu #if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
acpi_get_rc_addr(struct acpi_device * adev,struct resource * res)33169de969SDongdong Liu static int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res)
34169de969SDongdong Liu {
35169de969SDongdong Liu 	struct device *dev = &adev->dev;
36169de969SDongdong Liu 	struct resource_entry *entry;
37169de969SDongdong Liu 	struct list_head list;
38169de969SDongdong Liu 	unsigned long flags;
39169de969SDongdong Liu 	int ret;
40169de969SDongdong Liu 
41169de969SDongdong Liu 	INIT_LIST_HEAD(&list);
42169de969SDongdong Liu 	flags = IORESOURCE_MEM;
43169de969SDongdong Liu 	ret = acpi_dev_get_resources(adev, &list,
44169de969SDongdong Liu 				     acpi_dev_filter_resource_type_cb,
45169de969SDongdong Liu 				     (void *) flags);
46169de969SDongdong Liu 	if (ret < 0) {
47169de969SDongdong Liu 		dev_err(dev, "failed to parse _CRS method, error code %d\n",
48169de969SDongdong Liu 			ret);
49169de969SDongdong Liu 		return ret;
50169de969SDongdong Liu 	}
51169de969SDongdong Liu 
52169de969SDongdong Liu 	if (ret == 0) {
53169de969SDongdong Liu 		dev_err(dev, "no IO and memory resources present in _CRS\n");
54169de969SDongdong Liu 		return -EINVAL;
55169de969SDongdong Liu 	}
56169de969SDongdong Liu 
57169de969SDongdong Liu 	entry = list_first_entry(&list, struct resource_entry, node);
58169de969SDongdong Liu 	*res = *entry->res;
59169de969SDongdong Liu 	acpi_dev_free_resource_list(&list);
60169de969SDongdong Liu 	return 0;
61169de969SDongdong Liu }
62169de969SDongdong Liu 
acpi_match_rc(acpi_handle handle,u32 lvl,void * context,void ** retval)63169de969SDongdong Liu static acpi_status acpi_match_rc(acpi_handle handle, u32 lvl, void *context,
64169de969SDongdong Liu 				 void **retval)
65169de969SDongdong Liu {
66169de969SDongdong Liu 	u16 *segment = context;
67169de969SDongdong Liu 	unsigned long long uid;
68169de969SDongdong Liu 	acpi_status status;
69169de969SDongdong Liu 
709f0b4cc1SYipeng Zou 	status = acpi_evaluate_integer(handle, METHOD_NAME__UID, NULL, &uid);
71169de969SDongdong Liu 	if (ACPI_FAILURE(status) || uid != *segment)
72169de969SDongdong Liu 		return AE_CTRL_DEPTH;
73169de969SDongdong Liu 
74169de969SDongdong Liu 	*(acpi_handle *)retval = handle;
75169de969SDongdong Liu 	return AE_CTRL_TERMINATE;
76169de969SDongdong Liu }
77169de969SDongdong Liu 
acpi_get_rc_resources(struct device * dev,const char * hid,u16 segment,struct resource * res)78169de969SDongdong Liu int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
79169de969SDongdong Liu 			  struct resource *res)
80169de969SDongdong Liu {
81169de969SDongdong Liu 	struct acpi_device *adev;
82169de969SDongdong Liu 	acpi_status status;
83169de969SDongdong Liu 	acpi_handle handle;
84169de969SDongdong Liu 	int ret;
85169de969SDongdong Liu 
86169de969SDongdong Liu 	status = acpi_get_devices(hid, acpi_match_rc, &segment, &handle);
87169de969SDongdong Liu 	if (ACPI_FAILURE(status)) {
88169de969SDongdong Liu 		dev_err(dev, "can't find _HID %s device to locate resources\n",
89169de969SDongdong Liu 			hid);
90169de969SDongdong Liu 		return -ENODEV;
91169de969SDongdong Liu 	}
92169de969SDongdong Liu 
939a607a54SRafael J. Wysocki 	adev = acpi_fetch_acpi_dev(handle);
949a607a54SRafael J. Wysocki 	if (!adev)
959a607a54SRafael J. Wysocki 		return -ENODEV;
96169de969SDongdong Liu 
97169de969SDongdong Liu 	ret = acpi_get_rc_addr(adev, res);
98169de969SDongdong Liu 	if (ret) {
99169de969SDongdong Liu 		dev_err(dev, "can't get resource from %s\n",
100169de969SDongdong Liu 			dev_name(&adev->dev));
101169de969SDongdong Liu 		return ret;
102169de969SDongdong Liu 	}
103169de969SDongdong Liu 
104169de969SDongdong Liu 	return 0;
105169de969SDongdong Liu }
106169de969SDongdong Liu #endif
107169de969SDongdong Liu 
acpi_pci_root_get_mcfg_addr(acpi_handle handle)108f4b57a3bSJiang Liu phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
109f4b57a3bSJiang Liu {
110f4b57a3bSJiang Liu 	acpi_status status = AE_NOT_EXIST;
111f4b57a3bSJiang Liu 	unsigned long long mcfg_addr;
112f4b57a3bSJiang Liu 
113f4b57a3bSJiang Liu 	if (handle)
114f4b57a3bSJiang Liu 		status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
115f4b57a3bSJiang Liu 					       NULL, &mcfg_addr);
116f4b57a3bSJiang Liu 	if (ACPI_FAILURE(status))
117f4b57a3bSJiang Liu 		return 0;
118f4b57a3bSJiang Liu 
119f4b57a3bSJiang Liu 	return (phys_addr_t)mcfg_addr;
120f4b57a3bSJiang Liu }
121f4b57a3bSJiang Liu 
1224a2dbeddSKrzysztof Wilczynski /* _HPX PCI Setting Record (Type 0); same as _HPP */
1234a2dbeddSKrzysztof Wilczynski struct hpx_type0 {
1244a2dbeddSKrzysztof Wilczynski 	u32 revision;		/* Not present in _HPP */
1254a2dbeddSKrzysztof Wilczynski 	u8  cache_line_size;	/* Not applicable to PCIe */
1264a2dbeddSKrzysztof Wilczynski 	u8  latency_timer;	/* Not applicable to PCIe */
1274a2dbeddSKrzysztof Wilczynski 	u8  enable_serr;
1284a2dbeddSKrzysztof Wilczynski 	u8  enable_perr;
1294a2dbeddSKrzysztof Wilczynski };
1304a2dbeddSKrzysztof Wilczynski 
1318c3aac6eSKrzysztof Wilczynski static struct hpx_type0 pci_default_type0 = {
1328c3aac6eSKrzysztof Wilczynski 	.revision = 1,
1338c3aac6eSKrzysztof Wilczynski 	.cache_line_size = 8,
1348c3aac6eSKrzysztof Wilczynski 	.latency_timer = 0x40,
1358c3aac6eSKrzysztof Wilczynski 	.enable_serr = 0,
1368c3aac6eSKrzysztof Wilczynski 	.enable_perr = 0,
1378c3aac6eSKrzysztof Wilczynski };
1388c3aac6eSKrzysztof Wilczynski 
program_hpx_type0(struct pci_dev * dev,struct hpx_type0 * hpx)1394a2dbeddSKrzysztof Wilczynski static void program_hpx_type0(struct pci_dev *dev, struct hpx_type0 *hpx)
1408c3aac6eSKrzysztof Wilczynski {
1418c3aac6eSKrzysztof Wilczynski 	u16 pci_cmd, pci_bctl;
1428c3aac6eSKrzysztof Wilczynski 
1438c3aac6eSKrzysztof Wilczynski 	if (!hpx)
1448c3aac6eSKrzysztof Wilczynski 		hpx = &pci_default_type0;
1458c3aac6eSKrzysztof Wilczynski 
1468c3aac6eSKrzysztof Wilczynski 	if (hpx->revision > 1) {
1478c3aac6eSKrzysztof Wilczynski 		pci_warn(dev, "PCI settings rev %d not supported; using defaults\n",
1488c3aac6eSKrzysztof Wilczynski 			 hpx->revision);
1498c3aac6eSKrzysztof Wilczynski 		hpx = &pci_default_type0;
1508c3aac6eSKrzysztof Wilczynski 	}
1518c3aac6eSKrzysztof Wilczynski 
1528c3aac6eSKrzysztof Wilczynski 	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpx->cache_line_size);
1538c3aac6eSKrzysztof Wilczynski 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpx->latency_timer);
1548c3aac6eSKrzysztof Wilczynski 	pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
1558c3aac6eSKrzysztof Wilczynski 	if (hpx->enable_serr)
1568c3aac6eSKrzysztof Wilczynski 		pci_cmd |= PCI_COMMAND_SERR;
1578c3aac6eSKrzysztof Wilczynski 	if (hpx->enable_perr)
1588c3aac6eSKrzysztof Wilczynski 		pci_cmd |= PCI_COMMAND_PARITY;
1598c3aac6eSKrzysztof Wilczynski 	pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
1608c3aac6eSKrzysztof Wilczynski 
1618c3aac6eSKrzysztof Wilczynski 	/* Program bridge control value */
1628c3aac6eSKrzysztof Wilczynski 	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
1638c3aac6eSKrzysztof Wilczynski 		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
1648c3aac6eSKrzysztof Wilczynski 				      hpx->latency_timer);
1658c3aac6eSKrzysztof Wilczynski 		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
1668c3aac6eSKrzysztof Wilczynski 		if (hpx->enable_perr)
1678c3aac6eSKrzysztof Wilczynski 			pci_bctl |= PCI_BRIDGE_CTL_PARITY;
1688c3aac6eSKrzysztof Wilczynski 		pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
1698c3aac6eSKrzysztof Wilczynski 	}
1708c3aac6eSKrzysztof Wilczynski }
1718c3aac6eSKrzysztof Wilczynski 
decode_type0_hpx_record(union acpi_object * record,struct hpx_type0 * hpx0)172abbfec34SBjorn Helgaas static acpi_status decode_type0_hpx_record(union acpi_object *record,
173e2797ad3SKrzysztof Wilczynski 					   struct hpx_type0 *hpx0)
1749ce90ea5SBjorn Helgaas {
1759ce90ea5SBjorn Helgaas 	int i;
1769ce90ea5SBjorn Helgaas 	union acpi_object *fields = record->package.elements;
1779ce90ea5SBjorn Helgaas 	u32 revision = fields[1].integer.value;
1789ce90ea5SBjorn Helgaas 
1799ce90ea5SBjorn Helgaas 	switch (revision) {
1809ce90ea5SBjorn Helgaas 	case 1:
1819ce90ea5SBjorn Helgaas 		if (record->package.count != 6)
1829ce90ea5SBjorn Helgaas 			return AE_ERROR;
1839ce90ea5SBjorn Helgaas 		for (i = 2; i < 6; i++)
1849ce90ea5SBjorn Helgaas 			if (fields[i].type != ACPI_TYPE_INTEGER)
1859ce90ea5SBjorn Helgaas 				return AE_ERROR;
18687fcf12eSAlexandru Gagniuc 		hpx0->revision        = revision;
18787fcf12eSAlexandru Gagniuc 		hpx0->cache_line_size = fields[2].integer.value;
18887fcf12eSAlexandru Gagniuc 		hpx0->latency_timer   = fields[3].integer.value;
18987fcf12eSAlexandru Gagniuc 		hpx0->enable_serr     = fields[4].integer.value;
19087fcf12eSAlexandru Gagniuc 		hpx0->enable_perr     = fields[5].integer.value;
1919ce90ea5SBjorn Helgaas 		break;
1929ce90ea5SBjorn Helgaas 	default:
19325da8dbaSMohan Kumar 		pr_warn("%s: Type 0 Revision %d record not supported\n",
1949ce90ea5SBjorn Helgaas 		       __func__, revision);
1959ce90ea5SBjorn Helgaas 		return AE_ERROR;
1969ce90ea5SBjorn Helgaas 	}
1979ce90ea5SBjorn Helgaas 	return AE_OK;
1989ce90ea5SBjorn Helgaas }
1999ce90ea5SBjorn Helgaas 
2004a2dbeddSKrzysztof Wilczynski /* _HPX PCI-X Setting Record (Type 1) */
2014a2dbeddSKrzysztof Wilczynski struct hpx_type1 {
2024a2dbeddSKrzysztof Wilczynski 	u32 revision;
2034a2dbeddSKrzysztof Wilczynski 	u8  max_mem_read;
2044a2dbeddSKrzysztof Wilczynski 	u8  avg_max_split;
2054a2dbeddSKrzysztof Wilczynski 	u16 tot_max_split;
2064a2dbeddSKrzysztof Wilczynski };
2074a2dbeddSKrzysztof Wilczynski 
program_hpx_type1(struct pci_dev * dev,struct hpx_type1 * hpx)2084a2dbeddSKrzysztof Wilczynski static void program_hpx_type1(struct pci_dev *dev, struct hpx_type1 *hpx)
2098c3aac6eSKrzysztof Wilczynski {
2108c3aac6eSKrzysztof Wilczynski 	int pos;
2118c3aac6eSKrzysztof Wilczynski 
2128c3aac6eSKrzysztof Wilczynski 	if (!hpx)
2138c3aac6eSKrzysztof Wilczynski 		return;
2148c3aac6eSKrzysztof Wilczynski 
2158c3aac6eSKrzysztof Wilczynski 	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
2168c3aac6eSKrzysztof Wilczynski 	if (!pos)
2178c3aac6eSKrzysztof Wilczynski 		return;
2188c3aac6eSKrzysztof Wilczynski 
2198c3aac6eSKrzysztof Wilczynski 	pci_warn(dev, "PCI-X settings not supported\n");
2208c3aac6eSKrzysztof Wilczynski }
2218c3aac6eSKrzysztof Wilczynski 
decode_type1_hpx_record(union acpi_object * record,struct hpx_type1 * hpx1)222abbfec34SBjorn Helgaas static acpi_status decode_type1_hpx_record(union acpi_object *record,
223e2797ad3SKrzysztof Wilczynski 					   struct hpx_type1 *hpx1)
2249ce90ea5SBjorn Helgaas {
2259ce90ea5SBjorn Helgaas 	int i;
2269ce90ea5SBjorn Helgaas 	union acpi_object *fields = record->package.elements;
2279ce90ea5SBjorn Helgaas 	u32 revision = fields[1].integer.value;
2289ce90ea5SBjorn Helgaas 
2299ce90ea5SBjorn Helgaas 	switch (revision) {
2309ce90ea5SBjorn Helgaas 	case 1:
2319ce90ea5SBjorn Helgaas 		if (record->package.count != 5)
2329ce90ea5SBjorn Helgaas 			return AE_ERROR;
2339ce90ea5SBjorn Helgaas 		for (i = 2; i < 5; i++)
2349ce90ea5SBjorn Helgaas 			if (fields[i].type != ACPI_TYPE_INTEGER)
2359ce90ea5SBjorn Helgaas 				return AE_ERROR;
23687fcf12eSAlexandru Gagniuc 		hpx1->revision      = revision;
23787fcf12eSAlexandru Gagniuc 		hpx1->max_mem_read  = fields[2].integer.value;
23887fcf12eSAlexandru Gagniuc 		hpx1->avg_max_split = fields[3].integer.value;
23987fcf12eSAlexandru Gagniuc 		hpx1->tot_max_split = fields[4].integer.value;
2409ce90ea5SBjorn Helgaas 		break;
2419ce90ea5SBjorn Helgaas 	default:
24225da8dbaSMohan Kumar 		pr_warn("%s: Type 1 Revision %d record not supported\n",
2439ce90ea5SBjorn Helgaas 		       __func__, revision);
2449ce90ea5SBjorn Helgaas 		return AE_ERROR;
2459ce90ea5SBjorn Helgaas 	}
2469ce90ea5SBjorn Helgaas 	return AE_OK;
2479ce90ea5SBjorn Helgaas }
2489ce90ea5SBjorn Helgaas 
pcie_root_rcb_set(struct pci_dev * dev)2498c3aac6eSKrzysztof Wilczynski static bool pcie_root_rcb_set(struct pci_dev *dev)
2508c3aac6eSKrzysztof Wilczynski {
2518c3aac6eSKrzysztof Wilczynski 	struct pci_dev *rp = pcie_find_root_port(dev);
2528c3aac6eSKrzysztof Wilczynski 	u16 lnkctl;
2538c3aac6eSKrzysztof Wilczynski 
2548c3aac6eSKrzysztof Wilczynski 	if (!rp)
2558c3aac6eSKrzysztof Wilczynski 		return false;
2568c3aac6eSKrzysztof Wilczynski 
2578c3aac6eSKrzysztof Wilczynski 	pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
2588c3aac6eSKrzysztof Wilczynski 	if (lnkctl & PCI_EXP_LNKCTL_RCB)
2598c3aac6eSKrzysztof Wilczynski 		return true;
2608c3aac6eSKrzysztof Wilczynski 
2618c3aac6eSKrzysztof Wilczynski 	return false;
2628c3aac6eSKrzysztof Wilczynski }
2638c3aac6eSKrzysztof Wilczynski 
2644a2dbeddSKrzysztof Wilczynski /* _HPX PCI Express Setting Record (Type 2) */
2654a2dbeddSKrzysztof Wilczynski struct hpx_type2 {
2664a2dbeddSKrzysztof Wilczynski 	u32 revision;
2674a2dbeddSKrzysztof Wilczynski 	u32 unc_err_mask_and;
2684a2dbeddSKrzysztof Wilczynski 	u32 unc_err_mask_or;
2694a2dbeddSKrzysztof Wilczynski 	u32 unc_err_sever_and;
2704a2dbeddSKrzysztof Wilczynski 	u32 unc_err_sever_or;
2714a2dbeddSKrzysztof Wilczynski 	u32 cor_err_mask_and;
2724a2dbeddSKrzysztof Wilczynski 	u32 cor_err_mask_or;
2734a2dbeddSKrzysztof Wilczynski 	u32 adv_err_cap_and;
2744a2dbeddSKrzysztof Wilczynski 	u32 adv_err_cap_or;
2754a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_devctl_and;
2764a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_devctl_or;
2774a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_lnkctl_and;
2784a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_lnkctl_or;
2794a2dbeddSKrzysztof Wilczynski 	u32 sec_unc_err_sever_and;
2804a2dbeddSKrzysztof Wilczynski 	u32 sec_unc_err_sever_or;
2814a2dbeddSKrzysztof Wilczynski 	u32 sec_unc_err_mask_and;
2824a2dbeddSKrzysztof Wilczynski 	u32 sec_unc_err_mask_or;
2834a2dbeddSKrzysztof Wilczynski };
2844a2dbeddSKrzysztof Wilczynski 
program_hpx_type2(struct pci_dev * dev,struct hpx_type2 * hpx)2854a2dbeddSKrzysztof Wilczynski static void program_hpx_type2(struct pci_dev *dev, struct hpx_type2 *hpx)
2868c3aac6eSKrzysztof Wilczynski {
2878c3aac6eSKrzysztof Wilczynski 	int pos;
2888c3aac6eSKrzysztof Wilczynski 	u32 reg32;
2898c3aac6eSKrzysztof Wilczynski 
2908c3aac6eSKrzysztof Wilczynski 	if (!hpx)
2918c3aac6eSKrzysztof Wilczynski 		return;
2928c3aac6eSKrzysztof Wilczynski 
2938c3aac6eSKrzysztof Wilczynski 	if (!pci_is_pcie(dev))
2948c3aac6eSKrzysztof Wilczynski 		return;
2958c3aac6eSKrzysztof Wilczynski 
2968c3aac6eSKrzysztof Wilczynski 	if (hpx->revision > 1) {
2978c3aac6eSKrzysztof Wilczynski 		pci_warn(dev, "PCIe settings rev %d not supported\n",
2988c3aac6eSKrzysztof Wilczynski 			 hpx->revision);
2998c3aac6eSKrzysztof Wilczynski 		return;
3008c3aac6eSKrzysztof Wilczynski 	}
3018c3aac6eSKrzysztof Wilczynski 
3028c3aac6eSKrzysztof Wilczynski 	/*
3038c3aac6eSKrzysztof Wilczynski 	 * Don't allow _HPX to change MPS or MRRS settings.  We manage
3048c3aac6eSKrzysztof Wilczynski 	 * those to make sure they're consistent with the rest of the
3058c3aac6eSKrzysztof Wilczynski 	 * platform.
3068c3aac6eSKrzysztof Wilczynski 	 */
3078c3aac6eSKrzysztof Wilczynski 	hpx->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD |
3088c3aac6eSKrzysztof Wilczynski 				    PCI_EXP_DEVCTL_READRQ;
3098c3aac6eSKrzysztof Wilczynski 	hpx->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD |
3108c3aac6eSKrzysztof Wilczynski 				    PCI_EXP_DEVCTL_READRQ);
3118c3aac6eSKrzysztof Wilczynski 
3128c3aac6eSKrzysztof Wilczynski 	/* Initialize Device Control Register */
3138c3aac6eSKrzysztof Wilczynski 	pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
3148c3aac6eSKrzysztof Wilczynski 			~hpx->pci_exp_devctl_and, hpx->pci_exp_devctl_or);
3158c3aac6eSKrzysztof Wilczynski 
3168c3aac6eSKrzysztof Wilczynski 	/* Initialize Link Control Register */
3178c3aac6eSKrzysztof Wilczynski 	if (pcie_cap_has_lnkctl(dev)) {
3188c3aac6eSKrzysztof Wilczynski 
3198c3aac6eSKrzysztof Wilczynski 		/*
3208c3aac6eSKrzysztof Wilczynski 		 * If the Root Port supports Read Completion Boundary of
3218c3aac6eSKrzysztof Wilczynski 		 * 128, set RCB to 128.  Otherwise, clear it.
3228c3aac6eSKrzysztof Wilczynski 		 */
3238c3aac6eSKrzysztof Wilczynski 		hpx->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
3248c3aac6eSKrzysztof Wilczynski 		hpx->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
3258c3aac6eSKrzysztof Wilczynski 		if (pcie_root_rcb_set(dev))
3268c3aac6eSKrzysztof Wilczynski 			hpx->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
3278c3aac6eSKrzysztof Wilczynski 
3288c3aac6eSKrzysztof Wilczynski 		pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
3298c3aac6eSKrzysztof Wilczynski 			~hpx->pci_exp_lnkctl_and, hpx->pci_exp_lnkctl_or);
3308c3aac6eSKrzysztof Wilczynski 	}
3318c3aac6eSKrzysztof Wilczynski 
3328c3aac6eSKrzysztof Wilczynski 	/* Find Advanced Error Reporting Enhanced Capability */
3338c3aac6eSKrzysztof Wilczynski 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
3348c3aac6eSKrzysztof Wilczynski 	if (!pos)
3358c3aac6eSKrzysztof Wilczynski 		return;
3368c3aac6eSKrzysztof Wilczynski 
3378c3aac6eSKrzysztof Wilczynski 	/* Initialize Uncorrectable Error Mask Register */
3388c3aac6eSKrzysztof Wilczynski 	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &reg32);
3398c3aac6eSKrzysztof Wilczynski 	reg32 = (reg32 & hpx->unc_err_mask_and) | hpx->unc_err_mask_or;
3408c3aac6eSKrzysztof Wilczynski 	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32);
3418c3aac6eSKrzysztof Wilczynski 
3428c3aac6eSKrzysztof Wilczynski 	/* Initialize Uncorrectable Error Severity Register */
3438c3aac6eSKrzysztof Wilczynski 	pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &reg32);
3448c3aac6eSKrzysztof Wilczynski 	reg32 = (reg32 & hpx->unc_err_sever_and) | hpx->unc_err_sever_or;
3458c3aac6eSKrzysztof Wilczynski 	pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32);
3468c3aac6eSKrzysztof Wilczynski 
3478c3aac6eSKrzysztof Wilczynski 	/* Initialize Correctable Error Mask Register */
3488c3aac6eSKrzysztof Wilczynski 	pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg32);
3498c3aac6eSKrzysztof Wilczynski 	reg32 = (reg32 & hpx->cor_err_mask_and) | hpx->cor_err_mask_or;
3508c3aac6eSKrzysztof Wilczynski 	pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32);
3518c3aac6eSKrzysztof Wilczynski 
3528c3aac6eSKrzysztof Wilczynski 	/* Initialize Advanced Error Capabilities and Control Register */
3538c3aac6eSKrzysztof Wilczynski 	pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
3548c3aac6eSKrzysztof Wilczynski 	reg32 = (reg32 & hpx->adv_err_cap_and) | hpx->adv_err_cap_or;
3558c3aac6eSKrzysztof Wilczynski 
3568c3aac6eSKrzysztof Wilczynski 	/* Don't enable ECRC generation or checking if unsupported */
3578c3aac6eSKrzysztof Wilczynski 	if (!(reg32 & PCI_ERR_CAP_ECRC_GENC))
3588c3aac6eSKrzysztof Wilczynski 		reg32 &= ~PCI_ERR_CAP_ECRC_GENE;
3598c3aac6eSKrzysztof Wilczynski 	if (!(reg32 & PCI_ERR_CAP_ECRC_CHKC))
3608c3aac6eSKrzysztof Wilczynski 		reg32 &= ~PCI_ERR_CAP_ECRC_CHKE;
3618c3aac6eSKrzysztof Wilczynski 	pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
3628c3aac6eSKrzysztof Wilczynski 
3638c3aac6eSKrzysztof Wilczynski 	/*
3648c3aac6eSKrzysztof Wilczynski 	 * FIXME: The following two registers are not supported yet.
3658c3aac6eSKrzysztof Wilczynski 	 *
3668c3aac6eSKrzysztof Wilczynski 	 *   o Secondary Uncorrectable Error Severity Register
3678c3aac6eSKrzysztof Wilczynski 	 *   o Secondary Uncorrectable Error Mask Register
3688c3aac6eSKrzysztof Wilczynski 	 */
3698c3aac6eSKrzysztof Wilczynski }
3708c3aac6eSKrzysztof Wilczynski 
decode_type2_hpx_record(union acpi_object * record,struct hpx_type2 * hpx2)371abbfec34SBjorn Helgaas static acpi_status decode_type2_hpx_record(union acpi_object *record,
372e2797ad3SKrzysztof Wilczynski 					   struct hpx_type2 *hpx2)
3739ce90ea5SBjorn Helgaas {
3749ce90ea5SBjorn Helgaas 	int i;
3759ce90ea5SBjorn Helgaas 	union acpi_object *fields = record->package.elements;
3769ce90ea5SBjorn Helgaas 	u32 revision = fields[1].integer.value;
3779ce90ea5SBjorn Helgaas 
3789ce90ea5SBjorn Helgaas 	switch (revision) {
3799ce90ea5SBjorn Helgaas 	case 1:
3809ce90ea5SBjorn Helgaas 		if (record->package.count != 18)
3819ce90ea5SBjorn Helgaas 			return AE_ERROR;
3829ce90ea5SBjorn Helgaas 		for (i = 2; i < 18; i++)
3839ce90ea5SBjorn Helgaas 			if (fields[i].type != ACPI_TYPE_INTEGER)
3849ce90ea5SBjorn Helgaas 				return AE_ERROR;
38587fcf12eSAlexandru Gagniuc 		hpx2->revision      = revision;
38687fcf12eSAlexandru Gagniuc 		hpx2->unc_err_mask_and      = fields[2].integer.value;
38787fcf12eSAlexandru Gagniuc 		hpx2->unc_err_mask_or       = fields[3].integer.value;
38887fcf12eSAlexandru Gagniuc 		hpx2->unc_err_sever_and     = fields[4].integer.value;
38987fcf12eSAlexandru Gagniuc 		hpx2->unc_err_sever_or      = fields[5].integer.value;
39087fcf12eSAlexandru Gagniuc 		hpx2->cor_err_mask_and      = fields[6].integer.value;
39187fcf12eSAlexandru Gagniuc 		hpx2->cor_err_mask_or       = fields[7].integer.value;
39287fcf12eSAlexandru Gagniuc 		hpx2->adv_err_cap_and       = fields[8].integer.value;
39387fcf12eSAlexandru Gagniuc 		hpx2->adv_err_cap_or        = fields[9].integer.value;
39487fcf12eSAlexandru Gagniuc 		hpx2->pci_exp_devctl_and    = fields[10].integer.value;
39587fcf12eSAlexandru Gagniuc 		hpx2->pci_exp_devctl_or     = fields[11].integer.value;
39687fcf12eSAlexandru Gagniuc 		hpx2->pci_exp_lnkctl_and    = fields[12].integer.value;
39787fcf12eSAlexandru Gagniuc 		hpx2->pci_exp_lnkctl_or     = fields[13].integer.value;
39887fcf12eSAlexandru Gagniuc 		hpx2->sec_unc_err_sever_and = fields[14].integer.value;
39987fcf12eSAlexandru Gagniuc 		hpx2->sec_unc_err_sever_or  = fields[15].integer.value;
40087fcf12eSAlexandru Gagniuc 		hpx2->sec_unc_err_mask_and  = fields[16].integer.value;
40187fcf12eSAlexandru Gagniuc 		hpx2->sec_unc_err_mask_or   = fields[17].integer.value;
4029ce90ea5SBjorn Helgaas 		break;
4039ce90ea5SBjorn Helgaas 	default:
40425da8dbaSMohan Kumar 		pr_warn("%s: Type 2 Revision %d record not supported\n",
4059ce90ea5SBjorn Helgaas 		       __func__, revision);
4069ce90ea5SBjorn Helgaas 		return AE_ERROR;
4079ce90ea5SBjorn Helgaas 	}
4089ce90ea5SBjorn Helgaas 	return AE_OK;
4099ce90ea5SBjorn Helgaas }
4109ce90ea5SBjorn Helgaas 
4114a2dbeddSKrzysztof Wilczynski /* _HPX PCI Express Setting Record (Type 3) */
4124a2dbeddSKrzysztof Wilczynski struct hpx_type3 {
4134a2dbeddSKrzysztof Wilczynski 	u16 device_type;
4144a2dbeddSKrzysztof Wilczynski 	u16 function_type;
4154a2dbeddSKrzysztof Wilczynski 	u16 config_space_location;
4164a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_cap_id;
4174a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_cap_ver;
4184a2dbeddSKrzysztof Wilczynski 	u16 pci_exp_vendor_id;
4194a2dbeddSKrzysztof Wilczynski 	u16 dvsec_id;
4204a2dbeddSKrzysztof Wilczynski 	u16 dvsec_rev;
4214a2dbeddSKrzysztof Wilczynski 	u16 match_offset;
4224a2dbeddSKrzysztof Wilczynski 	u32 match_mask_and;
4234a2dbeddSKrzysztof Wilczynski 	u32 match_value;
4244a2dbeddSKrzysztof Wilczynski 	u16 reg_offset;
4254a2dbeddSKrzysztof Wilczynski 	u32 reg_mask_and;
4264a2dbeddSKrzysztof Wilczynski 	u32 reg_mask_or;
4274a2dbeddSKrzysztof Wilczynski };
4284a2dbeddSKrzysztof Wilczynski 
4298c3aac6eSKrzysztof Wilczynski enum hpx_type3_dev_type {
4308c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_ENDPOINT	= BIT(0),
4318c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_LEG_END	= BIT(1),
4328c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_RC_END		= BIT(2),
4338c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_RC_EC		= BIT(3),
4348c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_ROOT_PORT	= BIT(4),
4358c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_UPSTREAM	= BIT(5),
4368c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_DOWNSTREAM	= BIT(6),
4378c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_PCI_BRIDGE	= BIT(7),
4388c3aac6eSKrzysztof Wilczynski 	HPX_TYPE_PCIE_BRIDGE	= BIT(8),
4398c3aac6eSKrzysztof Wilczynski };
4408c3aac6eSKrzysztof Wilczynski 
hpx3_device_type(struct pci_dev * dev)4418c3aac6eSKrzysztof Wilczynski static u16 hpx3_device_type(struct pci_dev *dev)
4428c3aac6eSKrzysztof Wilczynski {
4438c3aac6eSKrzysztof Wilczynski 	u16 pcie_type = pci_pcie_type(dev);
444e3cdcfceSColin Ian King 	static const int pcie_to_hpx3_type[] = {
4458c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_ENDPOINT]    = HPX_TYPE_ENDPOINT,
4468c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_LEG_END]     = HPX_TYPE_LEG_END,
4478c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_RC_END]      = HPX_TYPE_RC_END,
4488c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_RC_EC]       = HPX_TYPE_RC_EC,
4498c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_ROOT_PORT]   = HPX_TYPE_ROOT_PORT,
4508c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_UPSTREAM]    = HPX_TYPE_UPSTREAM,
4518c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_DOWNSTREAM]  = HPX_TYPE_DOWNSTREAM,
4528c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_PCI_BRIDGE]  = HPX_TYPE_PCI_BRIDGE,
4538c3aac6eSKrzysztof Wilczynski 		[PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE,
4548c3aac6eSKrzysztof Wilczynski 	};
4558c3aac6eSKrzysztof Wilczynski 
4568c3aac6eSKrzysztof Wilczynski 	if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type))
4578c3aac6eSKrzysztof Wilczynski 		return 0;
4588c3aac6eSKrzysztof Wilczynski 
4598c3aac6eSKrzysztof Wilczynski 	return pcie_to_hpx3_type[pcie_type];
4608c3aac6eSKrzysztof Wilczynski }
4618c3aac6eSKrzysztof Wilczynski 
4628c3aac6eSKrzysztof Wilczynski enum hpx_type3_fn_type {
4638c3aac6eSKrzysztof Wilczynski 	HPX_FN_NORMAL		= BIT(0),
4648c3aac6eSKrzysztof Wilczynski 	HPX_FN_SRIOV_PHYS	= BIT(1),
4658c3aac6eSKrzysztof Wilczynski 	HPX_FN_SRIOV_VIRT	= BIT(2),
4668c3aac6eSKrzysztof Wilczynski };
4678c3aac6eSKrzysztof Wilczynski 
hpx3_function_type(struct pci_dev * dev)4688c3aac6eSKrzysztof Wilczynski static u8 hpx3_function_type(struct pci_dev *dev)
4698c3aac6eSKrzysztof Wilczynski {
4708c3aac6eSKrzysztof Wilczynski 	if (dev->is_virtfn)
4718c3aac6eSKrzysztof Wilczynski 		return HPX_FN_SRIOV_VIRT;
4728c3aac6eSKrzysztof Wilczynski 	else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0)
4738c3aac6eSKrzysztof Wilczynski 		return HPX_FN_SRIOV_PHYS;
4748c3aac6eSKrzysztof Wilczynski 	else
4758c3aac6eSKrzysztof Wilczynski 		return HPX_FN_NORMAL;
4768c3aac6eSKrzysztof Wilczynski }
4778c3aac6eSKrzysztof Wilczynski 
hpx3_cap_ver_matches(u8 pcie_cap_id,u8 hpx3_cap_id)4788c3aac6eSKrzysztof Wilczynski static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
4798c3aac6eSKrzysztof Wilczynski {
4808c3aac6eSKrzysztof Wilczynski 	u8 cap_ver = hpx3_cap_id & 0xf;
4818c3aac6eSKrzysztof Wilczynski 
4828c3aac6eSKrzysztof Wilczynski 	if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id)
4838c3aac6eSKrzysztof Wilczynski 		return true;
4848c3aac6eSKrzysztof Wilczynski 	else if (cap_ver == pcie_cap_id)
4858c3aac6eSKrzysztof Wilczynski 		return true;
4868c3aac6eSKrzysztof Wilczynski 
4878c3aac6eSKrzysztof Wilczynski 	return false;
4888c3aac6eSKrzysztof Wilczynski }
4898c3aac6eSKrzysztof Wilczynski 
4908c3aac6eSKrzysztof Wilczynski enum hpx_type3_cfg_loc {
4918c3aac6eSKrzysztof Wilczynski 	HPX_CFG_PCICFG		= 0,
4928c3aac6eSKrzysztof Wilczynski 	HPX_CFG_PCIE_CAP	= 1,
4938c3aac6eSKrzysztof Wilczynski 	HPX_CFG_PCIE_CAP_EXT	= 2,
4948c3aac6eSKrzysztof Wilczynski 	HPX_CFG_VEND_CAP	= 3,
4958c3aac6eSKrzysztof Wilczynski 	HPX_CFG_DVSEC		= 4,
4968c3aac6eSKrzysztof Wilczynski 	HPX_CFG_MAX,
4978c3aac6eSKrzysztof Wilczynski };
4988c3aac6eSKrzysztof Wilczynski 
program_hpx_type3_register(struct pci_dev * dev,const struct hpx_type3 * reg)4998c3aac6eSKrzysztof Wilczynski static void program_hpx_type3_register(struct pci_dev *dev,
5008c3aac6eSKrzysztof Wilczynski 				       const struct hpx_type3 *reg)
5018c3aac6eSKrzysztof Wilczynski {
5028c3aac6eSKrzysztof Wilczynski 	u32 match_reg, write_reg, header, orig_value;
5038c3aac6eSKrzysztof Wilczynski 	u16 pos;
5048c3aac6eSKrzysztof Wilczynski 
5058c3aac6eSKrzysztof Wilczynski 	if (!(hpx3_device_type(dev) & reg->device_type))
5068c3aac6eSKrzysztof Wilczynski 		return;
5078c3aac6eSKrzysztof Wilczynski 
5088c3aac6eSKrzysztof Wilczynski 	if (!(hpx3_function_type(dev) & reg->function_type))
5098c3aac6eSKrzysztof Wilczynski 		return;
5108c3aac6eSKrzysztof Wilczynski 
5118c3aac6eSKrzysztof Wilczynski 	switch (reg->config_space_location) {
5128c3aac6eSKrzysztof Wilczynski 	case HPX_CFG_PCICFG:
5138c3aac6eSKrzysztof Wilczynski 		pos = 0;
5148c3aac6eSKrzysztof Wilczynski 		break;
5158c3aac6eSKrzysztof Wilczynski 	case HPX_CFG_PCIE_CAP:
5168c3aac6eSKrzysztof Wilczynski 		pos = pci_find_capability(dev, reg->pci_exp_cap_id);
5178c3aac6eSKrzysztof Wilczynski 		if (pos == 0)
5188c3aac6eSKrzysztof Wilczynski 			return;
5198c3aac6eSKrzysztof Wilczynski 
5208c3aac6eSKrzysztof Wilczynski 		break;
5218c3aac6eSKrzysztof Wilczynski 	case HPX_CFG_PCIE_CAP_EXT:
5228c3aac6eSKrzysztof Wilczynski 		pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id);
5238c3aac6eSKrzysztof Wilczynski 		if (pos == 0)
5248c3aac6eSKrzysztof Wilczynski 			return;
5258c3aac6eSKrzysztof Wilczynski 
5268c3aac6eSKrzysztof Wilczynski 		pci_read_config_dword(dev, pos, &header);
5278c3aac6eSKrzysztof Wilczynski 		if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header),
5288c3aac6eSKrzysztof Wilczynski 					  reg->pci_exp_cap_ver))
5298c3aac6eSKrzysztof Wilczynski 			return;
5308c3aac6eSKrzysztof Wilczynski 
5318c3aac6eSKrzysztof Wilczynski 		break;
53257d2dd4bSGustavo A. R. Silva 	case HPX_CFG_VEND_CAP:
53357d2dd4bSGustavo A. R. Silva 	case HPX_CFG_DVSEC:
5348c3aac6eSKrzysztof Wilczynski 	default:
5358c3aac6eSKrzysztof Wilczynski 		pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location");
5368c3aac6eSKrzysztof Wilczynski 		return;
5378c3aac6eSKrzysztof Wilczynski 	}
5388c3aac6eSKrzysztof Wilczynski 
5398c3aac6eSKrzysztof Wilczynski 	pci_read_config_dword(dev, pos + reg->match_offset, &match_reg);
5408c3aac6eSKrzysztof Wilczynski 
5418c3aac6eSKrzysztof Wilczynski 	if ((match_reg & reg->match_mask_and) != reg->match_value)
5428c3aac6eSKrzysztof Wilczynski 		return;
5438c3aac6eSKrzysztof Wilczynski 
5448c3aac6eSKrzysztof Wilczynski 	pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg);
5458c3aac6eSKrzysztof Wilczynski 	orig_value = write_reg;
5468c3aac6eSKrzysztof Wilczynski 	write_reg &= reg->reg_mask_and;
5478c3aac6eSKrzysztof Wilczynski 	write_reg |= reg->reg_mask_or;
5488c3aac6eSKrzysztof Wilczynski 
5498c3aac6eSKrzysztof Wilczynski 	if (orig_value == write_reg)
5508c3aac6eSKrzysztof Wilczynski 		return;
5518c3aac6eSKrzysztof Wilczynski 
5528c3aac6eSKrzysztof Wilczynski 	pci_write_config_dword(dev, pos + reg->reg_offset, write_reg);
5538c3aac6eSKrzysztof Wilczynski 
5548c3aac6eSKrzysztof Wilczynski 	pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x",
5558c3aac6eSKrzysztof Wilczynski 		pos, orig_value, write_reg);
5568c3aac6eSKrzysztof Wilczynski }
5578c3aac6eSKrzysztof Wilczynski 
program_hpx_type3(struct pci_dev * dev,struct hpx_type3 * hpx)5584a2dbeddSKrzysztof Wilczynski static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx)
5598c3aac6eSKrzysztof Wilczynski {
5608c3aac6eSKrzysztof Wilczynski 	if (!hpx)
5618c3aac6eSKrzysztof Wilczynski 		return;
5628c3aac6eSKrzysztof Wilczynski 
5638c3aac6eSKrzysztof Wilczynski 	if (!pci_is_pcie(dev))
5648c3aac6eSKrzysztof Wilczynski 		return;
5658c3aac6eSKrzysztof Wilczynski 
5668c3aac6eSKrzysztof Wilczynski 	program_hpx_type3_register(dev, hpx);
5678c3aac6eSKrzysztof Wilczynski }
5688c3aac6eSKrzysztof Wilczynski 
parse_hpx3_register(struct hpx_type3 * hpx3_reg,union acpi_object * reg_fields)569f873c51aSAlexandru Gagniuc static void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
570f873c51aSAlexandru Gagniuc 				union acpi_object *reg_fields)
571f873c51aSAlexandru Gagniuc {
572f873c51aSAlexandru Gagniuc 	hpx3_reg->device_type            = reg_fields[0].integer.value;
573f873c51aSAlexandru Gagniuc 	hpx3_reg->function_type          = reg_fields[1].integer.value;
574f873c51aSAlexandru Gagniuc 	hpx3_reg->config_space_location  = reg_fields[2].integer.value;
575f873c51aSAlexandru Gagniuc 	hpx3_reg->pci_exp_cap_id         = reg_fields[3].integer.value;
576f873c51aSAlexandru Gagniuc 	hpx3_reg->pci_exp_cap_ver        = reg_fields[4].integer.value;
577f873c51aSAlexandru Gagniuc 	hpx3_reg->pci_exp_vendor_id      = reg_fields[5].integer.value;
578f873c51aSAlexandru Gagniuc 	hpx3_reg->dvsec_id               = reg_fields[6].integer.value;
579f873c51aSAlexandru Gagniuc 	hpx3_reg->dvsec_rev              = reg_fields[7].integer.value;
580f873c51aSAlexandru Gagniuc 	hpx3_reg->match_offset           = reg_fields[8].integer.value;
581f873c51aSAlexandru Gagniuc 	hpx3_reg->match_mask_and         = reg_fields[9].integer.value;
582f873c51aSAlexandru Gagniuc 	hpx3_reg->match_value            = reg_fields[10].integer.value;
583f873c51aSAlexandru Gagniuc 	hpx3_reg->reg_offset             = reg_fields[11].integer.value;
584f873c51aSAlexandru Gagniuc 	hpx3_reg->reg_mask_and           = reg_fields[12].integer.value;
585f873c51aSAlexandru Gagniuc 	hpx3_reg->reg_mask_or            = reg_fields[13].integer.value;
586f873c51aSAlexandru Gagniuc }
587f873c51aSAlexandru Gagniuc 
program_type3_hpx_record(struct pci_dev * dev,union acpi_object * record)588f873c51aSAlexandru Gagniuc static acpi_status program_type3_hpx_record(struct pci_dev *dev,
5894a2dbeddSKrzysztof Wilczynski 					   union acpi_object *record)
590f873c51aSAlexandru Gagniuc {
591f873c51aSAlexandru Gagniuc 	union acpi_object *fields = record->package.elements;
592f873c51aSAlexandru Gagniuc 	u32 desc_count, expected_length, revision;
593f873c51aSAlexandru Gagniuc 	union acpi_object *reg_fields;
594f873c51aSAlexandru Gagniuc 	struct hpx_type3 hpx3;
595f873c51aSAlexandru Gagniuc 	int i;
596f873c51aSAlexandru Gagniuc 
597f873c51aSAlexandru Gagniuc 	revision = fields[1].integer.value;
598f873c51aSAlexandru Gagniuc 	switch (revision) {
599f873c51aSAlexandru Gagniuc 	case 1:
600f873c51aSAlexandru Gagniuc 		desc_count = fields[2].integer.value;
601f873c51aSAlexandru Gagniuc 		expected_length = 3 + desc_count * 14;
602f873c51aSAlexandru Gagniuc 
603f873c51aSAlexandru Gagniuc 		if (record->package.count != expected_length)
604f873c51aSAlexandru Gagniuc 			return AE_ERROR;
605f873c51aSAlexandru Gagniuc 
606f873c51aSAlexandru Gagniuc 		for (i = 2; i < expected_length; i++)
607f873c51aSAlexandru Gagniuc 			if (fields[i].type != ACPI_TYPE_INTEGER)
608f873c51aSAlexandru Gagniuc 				return AE_ERROR;
609f873c51aSAlexandru Gagniuc 
610f873c51aSAlexandru Gagniuc 		for (i = 0; i < desc_count; i++) {
611f873c51aSAlexandru Gagniuc 			reg_fields = fields + 3 + i * 14;
612f873c51aSAlexandru Gagniuc 			parse_hpx3_register(&hpx3, reg_fields);
6134a2dbeddSKrzysztof Wilczynski 			program_hpx_type3(dev, &hpx3);
614f873c51aSAlexandru Gagniuc 		}
615f873c51aSAlexandru Gagniuc 
616f873c51aSAlexandru Gagniuc 		break;
617f873c51aSAlexandru Gagniuc 	default:
618f873c51aSAlexandru Gagniuc 		printk(KERN_WARNING
619f873c51aSAlexandru Gagniuc 			"%s: Type 3 Revision %d record not supported\n",
620f873c51aSAlexandru Gagniuc 			__func__, revision);
621f873c51aSAlexandru Gagniuc 		return AE_ERROR;
622f873c51aSAlexandru Gagniuc 	}
623f873c51aSAlexandru Gagniuc 	return AE_OK;
624f873c51aSAlexandru Gagniuc }
625f873c51aSAlexandru Gagniuc 
acpi_run_hpx(struct pci_dev * dev,acpi_handle handle)6264a2dbeddSKrzysztof Wilczynski static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle)
6279ce90ea5SBjorn Helgaas {
6289ce90ea5SBjorn Helgaas 	acpi_status status;
6299ce90ea5SBjorn Helgaas 	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
6309ce90ea5SBjorn Helgaas 	union acpi_object *package, *record, *fields;
631e2797ad3SKrzysztof Wilczynski 	struct hpx_type0 hpx0;
632e2797ad3SKrzysztof Wilczynski 	struct hpx_type1 hpx1;
633e2797ad3SKrzysztof Wilczynski 	struct hpx_type2 hpx2;
6349ce90ea5SBjorn Helgaas 	u32 type;
6359ce90ea5SBjorn Helgaas 	int i;
6369ce90ea5SBjorn Helgaas 
6379ce90ea5SBjorn Helgaas 	status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
6389ce90ea5SBjorn Helgaas 	if (ACPI_FAILURE(status))
6399ce90ea5SBjorn Helgaas 		return status;
6409ce90ea5SBjorn Helgaas 
6419ce90ea5SBjorn Helgaas 	package = (union acpi_object *)buffer.pointer;
6429ce90ea5SBjorn Helgaas 	if (package->type != ACPI_TYPE_PACKAGE) {
6439ce90ea5SBjorn Helgaas 		status = AE_ERROR;
6449ce90ea5SBjorn Helgaas 		goto exit;
6459ce90ea5SBjorn Helgaas 	}
6469ce90ea5SBjorn Helgaas 
6479ce90ea5SBjorn Helgaas 	for (i = 0; i < package->package.count; i++) {
6489ce90ea5SBjorn Helgaas 		record = &package->package.elements[i];
6499ce90ea5SBjorn Helgaas 		if (record->type != ACPI_TYPE_PACKAGE) {
6509ce90ea5SBjorn Helgaas 			status = AE_ERROR;
6519ce90ea5SBjorn Helgaas 			goto exit;
6529ce90ea5SBjorn Helgaas 		}
6539ce90ea5SBjorn Helgaas 
6549ce90ea5SBjorn Helgaas 		fields = record->package.elements;
6559ce90ea5SBjorn Helgaas 		if (fields[0].type != ACPI_TYPE_INTEGER ||
6569ce90ea5SBjorn Helgaas 		    fields[1].type != ACPI_TYPE_INTEGER) {
6579ce90ea5SBjorn Helgaas 			status = AE_ERROR;
6589ce90ea5SBjorn Helgaas 			goto exit;
6599ce90ea5SBjorn Helgaas 		}
6609ce90ea5SBjorn Helgaas 
6619ce90ea5SBjorn Helgaas 		type = fields[0].integer.value;
6629ce90ea5SBjorn Helgaas 		switch (type) {
6639ce90ea5SBjorn Helgaas 		case 0:
66487fcf12eSAlexandru Gagniuc 			memset(&hpx0, 0, sizeof(hpx0));
66587fcf12eSAlexandru Gagniuc 			status = decode_type0_hpx_record(record, &hpx0);
6669ce90ea5SBjorn Helgaas 			if (ACPI_FAILURE(status))
6679ce90ea5SBjorn Helgaas 				goto exit;
6684a2dbeddSKrzysztof Wilczynski 			program_hpx_type0(dev, &hpx0);
6699ce90ea5SBjorn Helgaas 			break;
6709ce90ea5SBjorn Helgaas 		case 1:
67187fcf12eSAlexandru Gagniuc 			memset(&hpx1, 0, sizeof(hpx1));
67287fcf12eSAlexandru Gagniuc 			status = decode_type1_hpx_record(record, &hpx1);
6739ce90ea5SBjorn Helgaas 			if (ACPI_FAILURE(status))
6749ce90ea5SBjorn Helgaas 				goto exit;
6754a2dbeddSKrzysztof Wilczynski 			program_hpx_type1(dev, &hpx1);
6769ce90ea5SBjorn Helgaas 			break;
6779ce90ea5SBjorn Helgaas 		case 2:
67887fcf12eSAlexandru Gagniuc 			memset(&hpx2, 0, sizeof(hpx2));
67987fcf12eSAlexandru Gagniuc 			status = decode_type2_hpx_record(record, &hpx2);
6809ce90ea5SBjorn Helgaas 			if (ACPI_FAILURE(status))
6819ce90ea5SBjorn Helgaas 				goto exit;
6824a2dbeddSKrzysztof Wilczynski 			program_hpx_type2(dev, &hpx2);
6839ce90ea5SBjorn Helgaas 			break;
684f873c51aSAlexandru Gagniuc 		case 3:
6854a2dbeddSKrzysztof Wilczynski 			status = program_type3_hpx_record(dev, record);
686f873c51aSAlexandru Gagniuc 			if (ACPI_FAILURE(status))
687f873c51aSAlexandru Gagniuc 				goto exit;
688f873c51aSAlexandru Gagniuc 			break;
6899ce90ea5SBjorn Helgaas 		default:
69025da8dbaSMohan Kumar 			pr_err("%s: Type %d record not supported\n",
6919ce90ea5SBjorn Helgaas 			       __func__, type);
6929ce90ea5SBjorn Helgaas 			status = AE_ERROR;
6939ce90ea5SBjorn Helgaas 			goto exit;
6949ce90ea5SBjorn Helgaas 		}
6959ce90ea5SBjorn Helgaas 	}
6969ce90ea5SBjorn Helgaas  exit:
6979ce90ea5SBjorn Helgaas 	kfree(buffer.pointer);
6989ce90ea5SBjorn Helgaas 	return status;
6999ce90ea5SBjorn Helgaas }
7009ce90ea5SBjorn Helgaas 
acpi_run_hpp(struct pci_dev * dev,acpi_handle handle)7014a2dbeddSKrzysztof Wilczynski static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle)
7029ce90ea5SBjorn Helgaas {
7039ce90ea5SBjorn Helgaas 	acpi_status status;
7049ce90ea5SBjorn Helgaas 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
7059ce90ea5SBjorn Helgaas 	union acpi_object *package, *fields;
706e2797ad3SKrzysztof Wilczynski 	struct hpx_type0 hpx0;
7079ce90ea5SBjorn Helgaas 	int i;
7089ce90ea5SBjorn Helgaas 
709e2797ad3SKrzysztof Wilczynski 	memset(&hpx0, 0, sizeof(hpx0));
7109ce90ea5SBjorn Helgaas 
7119ce90ea5SBjorn Helgaas 	status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
7129ce90ea5SBjorn Helgaas 	if (ACPI_FAILURE(status))
7139ce90ea5SBjorn Helgaas 		return status;
7149ce90ea5SBjorn Helgaas 
7159ce90ea5SBjorn Helgaas 	package = (union acpi_object *) buffer.pointer;
7169ce90ea5SBjorn Helgaas 	if (package->type != ACPI_TYPE_PACKAGE ||
7179ce90ea5SBjorn Helgaas 	    package->package.count != 4) {
7189ce90ea5SBjorn Helgaas 		status = AE_ERROR;
7199ce90ea5SBjorn Helgaas 		goto exit;
7209ce90ea5SBjorn Helgaas 	}
7219ce90ea5SBjorn Helgaas 
7229ce90ea5SBjorn Helgaas 	fields = package->package.elements;
7239ce90ea5SBjorn Helgaas 	for (i = 0; i < 4; i++) {
7249ce90ea5SBjorn Helgaas 		if (fields[i].type != ACPI_TYPE_INTEGER) {
7259ce90ea5SBjorn Helgaas 			status = AE_ERROR;
7269ce90ea5SBjorn Helgaas 			goto exit;
7279ce90ea5SBjorn Helgaas 		}
7289ce90ea5SBjorn Helgaas 	}
7299ce90ea5SBjorn Helgaas 
730e2797ad3SKrzysztof Wilczynski 	hpx0.revision        = 1;
731e2797ad3SKrzysztof Wilczynski 	hpx0.cache_line_size = fields[0].integer.value;
732e2797ad3SKrzysztof Wilczynski 	hpx0.latency_timer   = fields[1].integer.value;
733e2797ad3SKrzysztof Wilczynski 	hpx0.enable_serr     = fields[2].integer.value;
734e2797ad3SKrzysztof Wilczynski 	hpx0.enable_perr     = fields[3].integer.value;
73587fcf12eSAlexandru Gagniuc 
7364a2dbeddSKrzysztof Wilczynski 	program_hpx_type0(dev, &hpx0);
7379ce90ea5SBjorn Helgaas 
7389ce90ea5SBjorn Helgaas exit:
7399ce90ea5SBjorn Helgaas 	kfree(buffer.pointer);
7409ce90ea5SBjorn Helgaas 	return status;
7419ce90ea5SBjorn Helgaas }
7429ce90ea5SBjorn Helgaas 
7434a2dbeddSKrzysztof Wilczynski /* pci_acpi_program_hp_params
7449ce90ea5SBjorn Helgaas  *
7459ce90ea5SBjorn Helgaas  * @dev - the pci_dev for which we want parameters
7469ce90ea5SBjorn Helgaas  */
pci_acpi_program_hp_params(struct pci_dev * dev)7474a2dbeddSKrzysztof Wilczynski int pci_acpi_program_hp_params(struct pci_dev *dev)
7489ce90ea5SBjorn Helgaas {
7499ce90ea5SBjorn Helgaas 	acpi_status status;
7509ce90ea5SBjorn Helgaas 	acpi_handle handle, phandle;
7519ce90ea5SBjorn Helgaas 	struct pci_bus *pbus;
7529ce90ea5SBjorn Helgaas 
7538647ca9aSBjorn Helgaas 	if (acpi_pci_disabled)
7548647ca9aSBjorn Helgaas 		return -ENODEV;
7558647ca9aSBjorn Helgaas 
7569ce90ea5SBjorn Helgaas 	handle = NULL;
7579ce90ea5SBjorn Helgaas 	for (pbus = dev->bus; pbus; pbus = pbus->parent) {
7589ce90ea5SBjorn Helgaas 		handle = acpi_pci_get_bridge_handle(pbus);
7599ce90ea5SBjorn Helgaas 		if (handle)
7609ce90ea5SBjorn Helgaas 			break;
7619ce90ea5SBjorn Helgaas 	}
7629ce90ea5SBjorn Helgaas 
7639ce90ea5SBjorn Helgaas 	/*
7649ce90ea5SBjorn Helgaas 	 * _HPP settings apply to all child buses, until another _HPP is
7659ce90ea5SBjorn Helgaas 	 * encountered. If we don't find an _HPP for the input pci dev,
7669ce90ea5SBjorn Helgaas 	 * look for it in the parent device scope since that would apply to
7679ce90ea5SBjorn Helgaas 	 * this pci dev.
7689ce90ea5SBjorn Helgaas 	 */
7699ce90ea5SBjorn Helgaas 	while (handle) {
7704a2dbeddSKrzysztof Wilczynski 		status = acpi_run_hpx(dev, handle);
7719ce90ea5SBjorn Helgaas 		if (ACPI_SUCCESS(status))
7729ce90ea5SBjorn Helgaas 			return 0;
7734a2dbeddSKrzysztof Wilczynski 		status = acpi_run_hpp(dev, handle);
7749ce90ea5SBjorn Helgaas 		if (ACPI_SUCCESS(status))
7759ce90ea5SBjorn Helgaas 			return 0;
7769ce90ea5SBjorn Helgaas 		if (acpi_is_root_bridge(handle))
7779ce90ea5SBjorn Helgaas 			break;
7789ce90ea5SBjorn Helgaas 		status = acpi_get_parent(handle, &phandle);
7799ce90ea5SBjorn Helgaas 		if (ACPI_FAILURE(status))
7809ce90ea5SBjorn Helgaas 			break;
7819ce90ea5SBjorn Helgaas 		handle = phandle;
7829ce90ea5SBjorn Helgaas 	}
7839ce90ea5SBjorn Helgaas 	return -ENODEV;
7849ce90ea5SBjorn Helgaas }
7859ce90ea5SBjorn Helgaas 
7865e3d2344SBjorn Helgaas /**
787437eb7bfSLukas Wunner  * pciehp_is_native - Check whether a hotplug port is handled by the OS
7885352a44aSMika Westerberg  * @bridge: Hotplug port to check
789437eb7bfSLukas Wunner  *
7905352a44aSMika Westerberg  * Returns true if the given @bridge is handled by the native PCIe hotplug
7915352a44aSMika Westerberg  * driver.
792437eb7bfSLukas Wunner  */
pciehp_is_native(struct pci_dev * bridge)7935352a44aSMika Westerberg bool pciehp_is_native(struct pci_dev *bridge)
794437eb7bfSLukas Wunner {
7955352a44aSMika Westerberg 	const struct pci_host_bridge *host;
7965352a44aSMika Westerberg 	u32 slot_cap;
797437eb7bfSLukas Wunner 
7985352a44aSMika Westerberg 	if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
799437eb7bfSLukas Wunner 		return false;
800437eb7bfSLukas Wunner 
8015352a44aSMika Westerberg 	pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
8025352a44aSMika Westerberg 	if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
803437eb7bfSLukas Wunner 		return false;
804437eb7bfSLukas Wunner 
8055352a44aSMika Westerberg 	if (pcie_ports_native)
8065352a44aSMika Westerberg 		return true;
8075352a44aSMika Westerberg 
8085352a44aSMika Westerberg 	host = pci_find_host_bridge(bridge->bus);
8095352a44aSMika Westerberg 	return host->native_pcie_hotplug;
810437eb7bfSLukas Wunner }
811437eb7bfSLukas Wunner 
812437eb7bfSLukas Wunner /**
81390cc0c3cSMika Westerberg  * shpchp_is_native - Check whether a hotplug port is handled by the OS
81490cc0c3cSMika Westerberg  * @bridge: Hotplug port to check
81590cc0c3cSMika Westerberg  *
81690cc0c3cSMika Westerberg  * Returns true if the given @bridge is handled by the native SHPC hotplug
81790cc0c3cSMika Westerberg  * driver.
81890cc0c3cSMika Westerberg  */
shpchp_is_native(struct pci_dev * bridge)81990cc0c3cSMika Westerberg bool shpchp_is_native(struct pci_dev *bridge)
82090cc0c3cSMika Westerberg {
821b03799b0SBjorn Helgaas 	return bridge->shpc_managed;
82290cc0c3cSMika Westerberg }
82390cc0c3cSMika Westerberg 
82490cc0c3cSMika Westerberg /**
8255e3d2344SBjorn Helgaas  * pci_acpi_wake_bus - Root bus wakeup notification fork function.
82664fd1c70SRafael J. Wysocki  * @context: Device wakeup context.
8275e3d2344SBjorn Helgaas  */
pci_acpi_wake_bus(struct acpi_device_wakeup_context * context)82864fd1c70SRafael J. Wysocki static void pci_acpi_wake_bus(struct acpi_device_wakeup_context *context)
8295e3d2344SBjorn Helgaas {
8305e3d2344SBjorn Helgaas 	struct acpi_device *adev;
8315e3d2344SBjorn Helgaas 	struct acpi_pci_root *root;
8325e3d2344SBjorn Helgaas 
83364fd1c70SRafael J. Wysocki 	adev = container_of(context, struct acpi_device, wakeup.context);
8345e3d2344SBjorn Helgaas 	root = acpi_driver_data(adev);
8355e3d2344SBjorn Helgaas 	pci_pme_wakeup_bus(root->bus);
8365e3d2344SBjorn Helgaas }
8375e3d2344SBjorn Helgaas 
8385e3d2344SBjorn Helgaas /**
8395e3d2344SBjorn Helgaas  * pci_acpi_wake_dev - PCI device wakeup notification work function.
84064fd1c70SRafael J. Wysocki  * @context: Device wakeup context.
8415e3d2344SBjorn Helgaas  */
pci_acpi_wake_dev(struct acpi_device_wakeup_context * context)84264fd1c70SRafael J. Wysocki static void pci_acpi_wake_dev(struct acpi_device_wakeup_context *context)
8435e3d2344SBjorn Helgaas {
8445e3d2344SBjorn Helgaas 	struct pci_dev *pci_dev;
8455e3d2344SBjorn Helgaas 
8465e3d2344SBjorn Helgaas 	pci_dev = to_pci_dev(context->dev);
8475e3d2344SBjorn Helgaas 
8485e3d2344SBjorn Helgaas 	if (pci_dev->pme_poll)
8495e3d2344SBjorn Helgaas 		pci_dev->pme_poll = false;
8505e3d2344SBjorn Helgaas 
8515e3d2344SBjorn Helgaas 	if (pci_dev->current_state == PCI_D3cold) {
8525e3d2344SBjorn Helgaas 		pci_wakeup_event(pci_dev);
85364fd1c70SRafael J. Wysocki 		pm_request_resume(&pci_dev->dev);
8545e3d2344SBjorn Helgaas 		return;
8555e3d2344SBjorn Helgaas 	}
8565e3d2344SBjorn Helgaas 
8575e3d2344SBjorn Helgaas 	/* Clear PME Status if set. */
8585e3d2344SBjorn Helgaas 	if (pci_dev->pme_support)
8595e3d2344SBjorn Helgaas 		pci_check_pme_status(pci_dev);
8605e3d2344SBjorn Helgaas 
8615e3d2344SBjorn Helgaas 	pci_wakeup_event(pci_dev);
86264fd1c70SRafael J. Wysocki 	pm_request_resume(&pci_dev->dev);
8635e3d2344SBjorn Helgaas 
8645e3d2344SBjorn Helgaas 	pci_pme_wakeup_bus(pci_dev->subordinate);
8655e3d2344SBjorn Helgaas }
8665e3d2344SBjorn Helgaas 
8675e3d2344SBjorn Helgaas /**
8685e3d2344SBjorn Helgaas  * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
8695e3d2344SBjorn Helgaas  * @dev: PCI root bridge ACPI device.
8705e3d2344SBjorn Helgaas  */
pci_acpi_add_bus_pm_notifier(struct acpi_device * dev)8715e3d2344SBjorn Helgaas acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
8725e3d2344SBjorn Helgaas {
8735e3d2344SBjorn Helgaas 	return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus);
8745e3d2344SBjorn Helgaas }
8755e3d2344SBjorn Helgaas 
8765e3d2344SBjorn Helgaas /**
8775e3d2344SBjorn Helgaas  * pci_acpi_add_pm_notifier - Register PM notifier for given PCI device.
8785e3d2344SBjorn Helgaas  * @dev: ACPI device to add the notifier for.
8795e3d2344SBjorn Helgaas  * @pci_dev: PCI device to check for the PME status if an event is signaled.
8805e3d2344SBjorn Helgaas  */
pci_acpi_add_pm_notifier(struct acpi_device * dev,struct pci_dev * pci_dev)8815e3d2344SBjorn Helgaas acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
8825e3d2344SBjorn Helgaas 				     struct pci_dev *pci_dev)
8835e3d2344SBjorn Helgaas {
8845e3d2344SBjorn Helgaas 	return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
8855e3d2344SBjorn Helgaas }
8865e3d2344SBjorn Helgaas 
8870f64474bSDavid Shaohua Li /*
8880f64474bSDavid Shaohua Li  * _SxD returns the D-state with the highest power
8890f64474bSDavid Shaohua Li  * (lowest D-state number) supported in the S-state "x".
8900f64474bSDavid Shaohua Li  *
8910f64474bSDavid Shaohua Li  * If the devices does not have a _PRW
8920f64474bSDavid Shaohua Li  * (Power Resources for Wake) supporting system wakeup from "x"
8930f64474bSDavid Shaohua Li  * then the OS is free to choose a lower power (higher number
8940f64474bSDavid Shaohua Li  * D-state) than the return value from _SxD.
8950f64474bSDavid Shaohua Li  *
8960f64474bSDavid Shaohua Li  * But if _PRW is enabled at S-state "x", the OS
8970f64474bSDavid Shaohua Li  * must not choose a power lower than _SxD --
8980f64474bSDavid Shaohua Li  * unless the device has an _SxW method specifying
8990f64474bSDavid Shaohua Li  * the lowest power (highest D-state number) the device
9000f64474bSDavid Shaohua Li  * may enter while still able to wake the system.
9010f64474bSDavid Shaohua Li  *
9020f64474bSDavid Shaohua Li  * ie. depending on global OS policy:
9030f64474bSDavid Shaohua Li  *
9040f64474bSDavid Shaohua Li  * if (_PRW at S-state x)
9050f64474bSDavid Shaohua Li  *	choose from highest power _SxD to lowest power _SxW
9060f64474bSDavid Shaohua Li  * else // no _PRW at S-state x
9070f64474bSDavid Shaohua Li  *	choose highest power _SxD or any lower power
9080f64474bSDavid Shaohua Li  */
9090f64474bSDavid Shaohua Li 
acpi_pci_choose_state(struct pci_dev * pdev)910d97c5d4cSRafael J. Wysocki pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
9110f64474bSDavid Shaohua Li {
912448bd857SHuang Ying 	int acpi_state, d_max;
9130f64474bSDavid Shaohua Li 
914*0763bcefSLukas Wunner 	if (pdev->no_d3cold || !pdev->d3cold_allowed)
915448bd857SHuang Ying 		d_max = ACPI_STATE_D3_HOT;
916448bd857SHuang Ying 	else
917448bd857SHuang Ying 		d_max = ACPI_STATE_D3_COLD;
918448bd857SHuang Ying 	acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL, d_max);
919ab826ca4SShaohua Li 	if (acpi_state < 0)
920ab826ca4SShaohua Li 		return PCI_POWER_ERROR;
921ab826ca4SShaohua Li 
922ab826ca4SShaohua Li 	switch (acpi_state) {
923ab826ca4SShaohua Li 	case ACPI_STATE_D0:
924ab826ca4SShaohua Li 		return PCI_D0;
925ab826ca4SShaohua Li 	case ACPI_STATE_D1:
926ab826ca4SShaohua Li 		return PCI_D1;
927ab826ca4SShaohua Li 	case ACPI_STATE_D2:
928ab826ca4SShaohua Li 		return PCI_D2;
9291cc0c998SLin Ming 	case ACPI_STATE_D3_HOT:
930ab826ca4SShaohua Li 		return PCI_D3hot;
93128c2103dSLin Ming 	case ACPI_STATE_D3_COLD:
93228c2103dSLin Ming 		return PCI_D3cold;
933ab826ca4SShaohua Li 	}
934ab826ca4SShaohua Li 	return PCI_POWER_ERROR;
9350f64474bSDavid Shaohua Li }
936961d9120SRafael J. Wysocki 
93726ad34d5SMika Westerberg static struct acpi_device *acpi_pci_find_companion(struct device *dev);
93826ad34d5SMika Westerberg 
pci_set_acpi_fwnode(struct pci_dev * dev)9393a15955dSShanker Donthineni void pci_set_acpi_fwnode(struct pci_dev *dev)
9403a15955dSShanker Donthineni {
9416bd65974SJean-Philippe Brucker 	if (!dev_fwnode(&dev->dev) && !pci_dev_is_added(dev))
9423a15955dSShanker Donthineni 		ACPI_COMPANION_SET(&dev->dev,
9433a15955dSShanker Donthineni 				   acpi_pci_find_companion(&dev->dev));
9443a15955dSShanker Donthineni }
9453a15955dSShanker Donthineni 
9466937b7ddSShanker Donthineni /**
9476937b7ddSShanker Donthineni  * pci_dev_acpi_reset - do a function level reset using _RST method
9486937b7ddSShanker Donthineni  * @dev: device to reset
9499bdc81ceSAmey Narkhede  * @probe: if true, return 0 if device supports _RST
9506937b7ddSShanker Donthineni  */
pci_dev_acpi_reset(struct pci_dev * dev,bool probe)9519bdc81ceSAmey Narkhede int pci_dev_acpi_reset(struct pci_dev *dev, bool probe)
9526937b7ddSShanker Donthineni {
9536937b7ddSShanker Donthineni 	acpi_handle handle = ACPI_HANDLE(&dev->dev);
9546937b7ddSShanker Donthineni 
9556937b7ddSShanker Donthineni 	if (!handle || !acpi_has_method(handle, "_RST"))
9566937b7ddSShanker Donthineni 		return -ENOTTY;
9576937b7ddSShanker Donthineni 
9586937b7ddSShanker Donthineni 	if (probe)
9596937b7ddSShanker Donthineni 		return 0;
9606937b7ddSShanker Donthineni 
9616937b7ddSShanker Donthineni 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_RST", NULL, NULL))) {
9626937b7ddSShanker Donthineni 		pci_warn(dev, "ACPI _RST failed\n");
9636937b7ddSShanker Donthineni 		return -ENOTTY;
9646937b7ddSShanker Donthineni 	}
9656937b7ddSShanker Donthineni 
9666937b7ddSShanker Donthineni 	return 0;
9676937b7ddSShanker Donthineni }
9686937b7ddSShanker Donthineni 
acpi_pci_power_manageable(struct pci_dev * dev)969d97c5d4cSRafael J. Wysocki bool acpi_pci_power_manageable(struct pci_dev *dev)
9704273e64cSShanker Donthineni {
9714273e64cSShanker Donthineni 	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
9724273e64cSShanker Donthineni 
973f0918371SRafael J. Wysocki 	return adev && acpi_device_power_manageable(adev);
9744273e64cSShanker Donthineni }
9754273e64cSShanker Donthineni 
acpi_pci_bridge_d3(struct pci_dev * dev)976d97c5d4cSRafael J. Wysocki bool acpi_pci_bridge_d3(struct pci_dev *dev)
97726ad34d5SMika Westerberg {
978375553a9SShanker Donthineni 	struct pci_dev *rpdev;
9798133844aSRafael J. Wysocki 	struct acpi_device *adev, *rpadev;
980dff61390SMario Limonciello 	const union acpi_object *obj;
98126ad34d5SMika Westerberg 
982d97c5d4cSRafael J. Wysocki 	if (acpi_pci_disabled || !dev->is_hotplug_bridge)
98326ad34d5SMika Westerberg 		return false;
98426ad34d5SMika Westerberg 
9858133844aSRafael J. Wysocki 	adev = ACPI_COMPANION(&dev->dev);
9868133844aSRafael J. Wysocki 	if (adev) {
9878133844aSRafael J. Wysocki 		/*
9888133844aSRafael J. Wysocki 		 * If the bridge has _S0W, whether or not it can go into D3
9898133844aSRafael J. Wysocki 		 * depends on what is returned by that object.  In particular,
9908133844aSRafael J. Wysocki 		 * if the power state returned by _S0W is D2 or shallower,
9918133844aSRafael J. Wysocki 		 * entering D3 should not be allowed.
9928133844aSRafael J. Wysocki 		 */
9938133844aSRafael J. Wysocki 		if (acpi_dev_power_state_for_wake(adev) <= ACPI_STATE_D2)
9948133844aSRafael J. Wysocki 			return false;
9958133844aSRafael J. Wysocki 
9968133844aSRafael J. Wysocki 		/*
9978133844aSRafael J. Wysocki 		 * Otherwise, assume that the bridge can enter D3 so long as it
9988133844aSRafael J. Wysocki 		 * is power-manageable via ACPI.
9998133844aSRafael J. Wysocki 		 */
10008133844aSRafael J. Wysocki 		if (acpi_device_power_manageable(adev))
1001c6e33131SLukas Wunner 			return true;
10028133844aSRafael J. Wysocki 	}
1003c6e33131SLukas Wunner 
1004375553a9SShanker Donthineni 	rpdev = pcie_find_root_port(dev);
1005375553a9SShanker Donthineni 	if (!rpdev)
100626ad34d5SMika Westerberg 		return false;
100726ad34d5SMika Westerberg 
10088133844aSRafael J. Wysocki 	if (rpdev == dev)
10098133844aSRafael J. Wysocki 		rpadev = adev;
10108133844aSRafael J. Wysocki 	else
10118133844aSRafael J. Wysocki 		rpadev = ACPI_COMPANION(&rpdev->dev);
10128133844aSRafael J. Wysocki 
10138133844aSRafael J. Wysocki 	if (!rpadev)
101426ad34d5SMika Westerberg 		return false;
101526ad34d5SMika Westerberg 
1016dff61390SMario Limonciello 	/*
1017dff61390SMario Limonciello 	 * If the Root Port cannot signal wakeup signals at all, i.e., it
1018dff61390SMario Limonciello 	 * doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug
1019dff61390SMario Limonciello 	 * events from low-power states including D3hot and D3cold.
1020dff61390SMario Limonciello 	 */
10218133844aSRafael J. Wysocki 	if (!rpadev->wakeup.flags.valid)
102226ad34d5SMika Westerberg 		return false;
102326ad34d5SMika Westerberg 
1024dff61390SMario Limonciello 	/*
10258133844aSRafael J. Wysocki 	 * In the bridge-below-a-Root-Port case, evaluate _S0W for the Root Port
10268133844aSRafael J. Wysocki 	 * to verify whether or not it can signal wakeup from D3.
1027dff61390SMario Limonciello 	 */
10288133844aSRafael J. Wysocki 	if (rpadev != adev &&
10298133844aSRafael J. Wysocki 	    acpi_dev_power_state_for_wake(rpadev) <= ACPI_STATE_D2)
1030dff61390SMario Limonciello 		return false;
1031dff61390SMario Limonciello 
1032dff61390SMario Limonciello 	/*
1033dff61390SMario Limonciello 	 * The "HotPlugSupportInD3" property in a Root Port _DSD indicates
1034dff61390SMario Limonciello 	 * the Port can signal hotplug events while in D3.  We assume any
1035dff61390SMario Limonciello 	 * bridges *below* that Root Port can also signal hotplug events
1036dff61390SMario Limonciello 	 * while in D3.
1037dff61390SMario Limonciello 	 */
10388133844aSRafael J. Wysocki 	if (!acpi_dev_get_property(rpadev, "HotPlugSupportInD3",
1039dff61390SMario Limonciello 				   ACPI_TYPE_INTEGER, &obj) &&
1040dff61390SMario Limonciello 	    obj->integer.value == 1)
1041dff61390SMario Limonciello 		return true;
1042dff61390SMario Limonciello 
1043dff61390SMario Limonciello 	return false;
104426ad34d5SMika Westerberg }
104526ad34d5SMika Westerberg 
acpi_pci_config_space_access(struct pci_dev * dev,bool enable)1046112a7f9cSMario Limonciello static void acpi_pci_config_space_access(struct pci_dev *dev, bool enable)
1047112a7f9cSMario Limonciello {
1048112a7f9cSMario Limonciello 	int val = enable ? ACPI_REG_CONNECT : ACPI_REG_DISCONNECT;
1049112a7f9cSMario Limonciello 	int ret = acpi_evaluate_reg(ACPI_HANDLE(&dev->dev),
1050112a7f9cSMario Limonciello 				    ACPI_ADR_SPACE_PCI_CONFIG, val);
1051112a7f9cSMario Limonciello 	if (ret)
1052112a7f9cSMario Limonciello 		pci_dbg(dev, "ACPI _REG %s evaluation failed (%d)\n",
1053112a7f9cSMario Limonciello 			enable ? "connect" : "disconnect", ret);
1054112a7f9cSMario Limonciello }
1055112a7f9cSMario Limonciello 
acpi_pci_set_power_state(struct pci_dev * dev,pci_power_t state)1056d97c5d4cSRafael J. Wysocki int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
1057b913100dSDavid Shaohua Li {
105885dbb3d0SRafael J. Wysocki 	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
1059583c377fSDavid Brownell 	static const u8 state_conv[] = {
1060583c377fSDavid Brownell 		[PCI_D0] = ACPI_STATE_D0,
1061583c377fSDavid Brownell 		[PCI_D1] = ACPI_STATE_D1,
1062583c377fSDavid Brownell 		[PCI_D2] = ACPI_STATE_D2,
106320dacb71SRafael J. Wysocki 		[PCI_D3hot] = ACPI_STATE_D3_HOT,
1064fc6504b3SRafael J. Wysocki 		[PCI_D3cold] = ACPI_STATE_D3_COLD,
1065b913100dSDavid Shaohua Li 	};
10665557b626SBjorn Helgaas 	int error;
1067b913100dSDavid Shaohua Li 
106810b3dcaeSShaohua Li 	/* If the ACPI device has _EJ0, ignore the device */
106985dbb3d0SRafael J. Wysocki 	if (!adev || acpi_has_method(adev->handle, "_EJ0"))
107044e4e66eSRafael J. Wysocki 		return -ENODEV;
1071583c377fSDavid Brownell 
1072583c377fSDavid Brownell 	switch (state) {
1073583c377fSDavid Brownell 	case PCI_D0:
1074583c377fSDavid Brownell 	case PCI_D1:
1075583c377fSDavid Brownell 	case PCI_D2:
1076583c377fSDavid Brownell 	case PCI_D3hot:
10775557b626SBjorn Helgaas 	case PCI_D3cold:
10785557b626SBjorn Helgaas 		break;
10795557b626SBjorn Helgaas 	default:
10805557b626SBjorn Helgaas 		return -EINVAL;
1081583c377fSDavid Brownell 	}
108244e4e66eSRafael J. Wysocki 
10835557b626SBjorn Helgaas 	if (state == PCI_D3cold) {
10845557b626SBjorn Helgaas 		if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
10855557b626SBjorn Helgaas 				PM_QOS_FLAGS_ALL)
10865557b626SBjorn Helgaas 			return -EBUSY;
1087112a7f9cSMario Limonciello 
1088112a7f9cSMario Limonciello 		/* Notify AML lack of PCI config space availability */
1089112a7f9cSMario Limonciello 		acpi_pci_config_space_access(dev, false);
10905557b626SBjorn Helgaas 	}
10915557b626SBjorn Helgaas 
10925557b626SBjorn Helgaas 	error = acpi_device_set_power(adev, state_conv[state]);
10935557b626SBjorn Helgaas 	if (error)
10945557b626SBjorn Helgaas 		return error;
10955557b626SBjorn Helgaas 
10967506dc79SFrederick Lawler 	pci_dbg(dev, "power state changed by ACPI to %s\n",
109769397852SRafael J. Wysocki 	        acpi_power_state_string(adev->power.state));
109844e4e66eSRafael J. Wysocki 
1099112a7f9cSMario Limonciello 	/*
1100112a7f9cSMario Limonciello 	 * Notify AML of PCI config space availability.  Config space is
1101112a7f9cSMario Limonciello 	 * accessible in all states except D3cold; the only transitions
1102112a7f9cSMario Limonciello 	 * that change availability are transitions to D3cold and from
1103112a7f9cSMario Limonciello 	 * D3cold to D0.
1104112a7f9cSMario Limonciello 	 */
1105112a7f9cSMario Limonciello 	if (state == PCI_D0)
1106112a7f9cSMario Limonciello 		acpi_pci_config_space_access(dev, true);
1107112a7f9cSMario Limonciello 
11085557b626SBjorn Helgaas 	return 0;
1109b913100dSDavid Shaohua Li }
1110b913100dSDavid Shaohua Li 
acpi_pci_get_power_state(struct pci_dev * dev)1111d97c5d4cSRafael J. Wysocki pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)
1112cc7cc02bSLukas Wunner {
1113cc7cc02bSLukas Wunner 	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
1114cc7cc02bSLukas Wunner 	static const pci_power_t state_conv[] = {
1115cc7cc02bSLukas Wunner 		[ACPI_STATE_D0]      = PCI_D0,
1116cc7cc02bSLukas Wunner 		[ACPI_STATE_D1]      = PCI_D1,
1117cc7cc02bSLukas Wunner 		[ACPI_STATE_D2]      = PCI_D2,
1118cc7cc02bSLukas Wunner 		[ACPI_STATE_D3_HOT]  = PCI_D3hot,
1119cc7cc02bSLukas Wunner 		[ACPI_STATE_D3_COLD] = PCI_D3cold,
1120cc7cc02bSLukas Wunner 	};
1121cc7cc02bSLukas Wunner 	int state;
1122cc7cc02bSLukas Wunner 
1123cc7cc02bSLukas Wunner 	if (!adev || !acpi_device_power_manageable(adev))
1124cc7cc02bSLukas Wunner 		return PCI_UNKNOWN;
1125cc7cc02bSLukas Wunner 
112683a16e3fSMika Westerberg 	state = adev->power.state;
112783a16e3fSMika Westerberg 	if (state == ACPI_STATE_UNKNOWN)
1128cc7cc02bSLukas Wunner 		return PCI_UNKNOWN;
1129cc7cc02bSLukas Wunner 
1130cc7cc02bSLukas Wunner 	return state_conv[state];
1131cc7cc02bSLukas Wunner }
1132cc7cc02bSLukas Wunner 
acpi_pci_refresh_power_state(struct pci_dev * dev)1133d97c5d4cSRafael J. Wysocki void acpi_pci_refresh_power_state(struct pci_dev *dev)
1134b51033e0SRafael J. Wysocki {
1135b51033e0SRafael J. Wysocki 	struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
1136b51033e0SRafael J. Wysocki 
1137b51033e0SRafael J. Wysocki 	if (adev && acpi_device_power_manageable(adev))
1138b51033e0SRafael J. Wysocki 		acpi_device_update_power(adev, NULL);
1139b51033e0SRafael J. Wysocki }
1140b51033e0SRafael J. Wysocki 
acpi_pci_propagate_wakeup(struct pci_bus * bus,bool enable)11418370c2dcSRafael J. Wysocki static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
11420baed8daSRafael J. Wysocki {
11430baed8daSRafael J. Wysocki 	while (bus->parent) {
11448370c2dcSRafael J. Wysocki 		if (acpi_pm_device_can_wakeup(&bus->self->dev))
11457482c5cbSRafael J. Wysocki 			return acpi_pm_set_device_wakeup(&bus->self->dev, enable);
11468370c2dcSRafael J. Wysocki 
11470baed8daSRafael J. Wysocki 		bus = bus->parent;
11480baed8daSRafael J. Wysocki 	}
11490baed8daSRafael J. Wysocki 
11500baed8daSRafael J. Wysocki 	/* We have reached the root bus. */
11518370c2dcSRafael J. Wysocki 	if (bus->bridge) {
11528370c2dcSRafael J. Wysocki 		if (acpi_pm_device_can_wakeup(bus->bridge))
11537482c5cbSRafael J. Wysocki 			return acpi_pm_set_device_wakeup(bus->bridge, enable);
11548370c2dcSRafael J. Wysocki 	}
11558370c2dcSRafael J. Wysocki 	return 0;
11560baed8daSRafael J. Wysocki }
11570baed8daSRafael J. Wysocki 
acpi_pci_wakeup(struct pci_dev * dev,bool enable)1158d97c5d4cSRafael J. Wysocki int acpi_pci_wakeup(struct pci_dev *dev, bool enable)
1159eb9d0fe4SRafael J. Wysocki {
1160d97c5d4cSRafael J. Wysocki 	if (acpi_pci_disabled)
1161d97c5d4cSRafael J. Wysocki 		return 0;
1162d97c5d4cSRafael J. Wysocki 
11638370c2dcSRafael J. Wysocki 	if (acpi_pm_device_can_wakeup(&dev->dev))
11644d183d04SRafael J. Wysocki 		return acpi_pm_set_device_wakeup(&dev->dev, enable);
11650baed8daSRafael J. Wysocki 
11668370c2dcSRafael J. Wysocki 	return acpi_pci_propagate_wakeup(dev->bus, enable);
1167b67ea761SRafael J. Wysocki }
1168b67ea761SRafael J. Wysocki 
acpi_pci_need_resume(struct pci_dev * dev)1169d97c5d4cSRafael J. Wysocki bool acpi_pci_need_resume(struct pci_dev *dev)
1170bac2a909SRafael J. Wysocki {
1171d97c5d4cSRafael J. Wysocki 	struct acpi_device *adev;
1172d97c5d4cSRafael J. Wysocki 
1173d97c5d4cSRafael J. Wysocki 	if (acpi_pci_disabled)
1174d97c5d4cSRafael J. Wysocki 		return false;
1175bac2a909SRafael J. Wysocki 
117626112ddcSRafael J. Wysocki 	/*
117726112ddcSRafael J. Wysocki 	 * In some cases (eg. Samsung 305V4A) leaving a bridge in suspend over
117826112ddcSRafael J. Wysocki 	 * system-wide suspend/resume confuses the platform firmware, so avoid
11799d64b539SRafael J. Wysocki 	 * doing that.  According to Section 16.1.6 of ACPI 6.2, endpoint
118026112ddcSRafael J. Wysocki 	 * devices are expected to be in D3 before invoking the S3 entry path
118126112ddcSRafael J. Wysocki 	 * from the firmware, so they should not be affected by this issue.
118226112ddcSRafael J. Wysocki 	 */
11839d64b539SRafael J. Wysocki 	if (pci_is_bridge(dev) && acpi_target_system_state() != ACPI_STATE_S0)
118426112ddcSRafael J. Wysocki 		return true;
118526112ddcSRafael J. Wysocki 
1186d97c5d4cSRafael J. Wysocki 	adev = ACPI_COMPANION(&dev->dev);
1187bac2a909SRafael J. Wysocki 	if (!adev || !acpi_device_power_manageable(adev))
1188bac2a909SRafael J. Wysocki 		return false;
1189bac2a909SRafael J. Wysocki 
11909a51c6b1SRafael J. Wysocki 	if (adev->wakeup.flags.valid &&
11919a51c6b1SRafael J. Wysocki 	    device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count)
1192bac2a909SRafael J. Wysocki 		return true;
1193bac2a909SRafael J. Wysocki 
1194bac2a909SRafael J. Wysocki 	if (acpi_target_system_state() == ACPI_STATE_S0)
1195bac2a909SRafael J. Wysocki 		return false;
1196bac2a909SRafael J. Wysocki 
1197bac2a909SRafael J. Wysocki 	return !!adev->power.flags.dsw_present;
1198bac2a909SRafael J. Wysocki }
1199bac2a909SRafael J. Wysocki 
acpi_pci_add_bus(struct pci_bus * bus)12005090d4a6SJiang Liu void acpi_pci_add_bus(struct pci_bus *bus)
12015090d4a6SJiang Liu {
1202e33caa82SAaron Lu 	union acpi_object *obj;
1203e33caa82SAaron Lu 	struct pci_host_bridge *bridge;
1204e33caa82SAaron Lu 
1205a0040c01SVitaly Kuznetsov 	if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge))
12065090d4a6SJiang Liu 		return;
12075090d4a6SJiang Liu 
1208be1c9de9SRafael J. Wysocki 	acpi_pci_slot_enumerate(bus);
1209be1c9de9SRafael J. Wysocki 	acpiphp_enumerate_slots(bus);
1210e33caa82SAaron Lu 
1211e33caa82SAaron Lu 	/*
1212e33caa82SAaron Lu 	 * For a host bridge, check its _DSM for function 8 and if
1213e33caa82SAaron Lu 	 * that is available, mark it in pci_host_bridge.
1214e33caa82SAaron Lu 	 */
1215e33caa82SAaron Lu 	if (!pci_is_root_bus(bus))
1216e33caa82SAaron Lu 		return;
1217e33caa82SAaron Lu 
121894116f81SAndy Shevchenko 	obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3,
12193910ebacSKrzysztof Wilczyński 				DSM_PCI_POWER_ON_RESET_DELAY, NULL);
1220e33caa82SAaron Lu 	if (!obj)
1221e33caa82SAaron Lu 		return;
1222e33caa82SAaron Lu 
1223e33caa82SAaron Lu 	if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
1224e33caa82SAaron Lu 		bridge = pci_find_host_bridge(bus);
1225e33caa82SAaron Lu 		bridge->ignore_reset_delay = 1;
1226e33caa82SAaron Lu 	}
1227e33caa82SAaron Lu 	ACPI_FREE(obj);
12285090d4a6SJiang Liu }
12295090d4a6SJiang Liu 
acpi_pci_remove_bus(struct pci_bus * bus)12305090d4a6SJiang Liu void acpi_pci_remove_bus(struct pci_bus *bus)
12315090d4a6SJiang Liu {
1232be1c9de9SRafael J. Wysocki 	if (acpi_pci_disabled || !bus->bridge)
12335090d4a6SJiang Liu 		return;
12345090d4a6SJiang Liu 
12353b63aaa7SJiang Liu 	acpiphp_remove_slots(bus);
12365c0b04e3SJiang Liu 	acpi_pci_slot_remove(bus);
12375090d4a6SJiang Liu }
12385090d4a6SJiang Liu 
123984df749fSDavid Shaohua Li /* ACPI bus type */
124059dc3325SRafael J. Wysocki 
124159dc3325SRafael J. Wysocki 
124259dc3325SRafael J. Wysocki static DECLARE_RWSEM(pci_acpi_companion_lookup_sem);
124359dc3325SRafael J. Wysocki static struct acpi_device *(*pci_acpi_find_companion_hook)(struct pci_dev *);
124459dc3325SRafael J. Wysocki 
124559dc3325SRafael J. Wysocki /**
124659dc3325SRafael J. Wysocki  * pci_acpi_set_companion_lookup_hook - Set ACPI companion lookup callback.
124759dc3325SRafael J. Wysocki  * @func: ACPI companion lookup callback pointer or NULL.
124859dc3325SRafael J. Wysocki  *
124959dc3325SRafael J. Wysocki  * Set a special ACPI companion lookup callback for PCI devices whose companion
125059dc3325SRafael J. Wysocki  * objects in the ACPI namespace have _ADR with non-standard bus-device-function
125159dc3325SRafael J. Wysocki  * encodings.
125259dc3325SRafael J. Wysocki  *
125359dc3325SRafael J. Wysocki  * Return 0 on success or a negative error code on failure (in which case no
125459dc3325SRafael J. Wysocki  * changes are made).
125559dc3325SRafael J. Wysocki  *
125659dc3325SRafael J. Wysocki  * The caller is responsible for the appropriate ordering of the invocations of
125759dc3325SRafael J. Wysocki  * this function with respect to the enumeration of the PCI devices needing the
125859dc3325SRafael J. Wysocki  * callback installed by it.
125959dc3325SRafael J. Wysocki  */
pci_acpi_set_companion_lookup_hook(struct acpi_device * (* func)(struct pci_dev *))126059dc3325SRafael J. Wysocki int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *))
126159dc3325SRafael J. Wysocki {
126259dc3325SRafael J. Wysocki 	int ret;
126359dc3325SRafael J. Wysocki 
126459dc3325SRafael J. Wysocki 	if (!func)
126559dc3325SRafael J. Wysocki 		return -EINVAL;
126659dc3325SRafael J. Wysocki 
126759dc3325SRafael J. Wysocki 	down_write(&pci_acpi_companion_lookup_sem);
126859dc3325SRafael J. Wysocki 
126959dc3325SRafael J. Wysocki 	if (pci_acpi_find_companion_hook) {
127059dc3325SRafael J. Wysocki 		ret = -EBUSY;
127159dc3325SRafael J. Wysocki 	} else {
127259dc3325SRafael J. Wysocki 		pci_acpi_find_companion_hook = func;
127359dc3325SRafael J. Wysocki 		ret = 0;
127459dc3325SRafael J. Wysocki 	}
127559dc3325SRafael J. Wysocki 
127659dc3325SRafael J. Wysocki 	up_write(&pci_acpi_companion_lookup_sem);
127759dc3325SRafael J. Wysocki 
127859dc3325SRafael J. Wysocki 	return ret;
127959dc3325SRafael J. Wysocki }
128059dc3325SRafael J. Wysocki EXPORT_SYMBOL_GPL(pci_acpi_set_companion_lookup_hook);
128159dc3325SRafael J. Wysocki 
128259dc3325SRafael J. Wysocki /**
128359dc3325SRafael J. Wysocki  * pci_acpi_clear_companion_lookup_hook - Clear ACPI companion lookup callback.
128459dc3325SRafael J. Wysocki  *
128559dc3325SRafael J. Wysocki  * Clear the special ACPI companion lookup callback previously set by
128659dc3325SRafael J. Wysocki  * pci_acpi_set_companion_lookup_hook().  Block until the last running instance
128759dc3325SRafael J. Wysocki  * of the callback returns before clearing it.
128859dc3325SRafael J. Wysocki  *
128959dc3325SRafael J. Wysocki  * The caller is responsible for the appropriate ordering of the invocations of
129059dc3325SRafael J. Wysocki  * this function with respect to the enumeration of the PCI devices needing the
129159dc3325SRafael J. Wysocki  * callback cleared by it.
129259dc3325SRafael J. Wysocki  */
pci_acpi_clear_companion_lookup_hook(void)129359dc3325SRafael J. Wysocki void pci_acpi_clear_companion_lookup_hook(void)
129459dc3325SRafael J. Wysocki {
129559dc3325SRafael J. Wysocki 	down_write(&pci_acpi_companion_lookup_sem);
129659dc3325SRafael J. Wysocki 
129759dc3325SRafael J. Wysocki 	pci_acpi_find_companion_hook = NULL;
129859dc3325SRafael J. Wysocki 
129959dc3325SRafael J. Wysocki 	up_write(&pci_acpi_companion_lookup_sem);
130059dc3325SRafael J. Wysocki }
130159dc3325SRafael J. Wysocki EXPORT_SYMBOL_GPL(pci_acpi_clear_companion_lookup_hook);
130259dc3325SRafael J. Wysocki 
acpi_pci_find_companion(struct device * dev)1303e3f02c52SRafael J. Wysocki static struct acpi_device *acpi_pci_find_companion(struct device *dev)
130484df749fSDavid Shaohua Li {
130560f75b8eSRafael J. Wysocki 	struct pci_dev *pci_dev = to_pci_dev(dev);
1306aa0b1574SRafael J. Wysocki 	struct acpi_device *adev;
13075ce79d20SRafael J. Wysocki 	bool check_children;
1308439913ffSLin Ming 	u64 addr;
130984df749fSDavid Shaohua Li 
13103fb937f4SRafael J. Wysocki 	if (!dev->parent)
13113fb937f4SRafael J. Wysocki 		return NULL;
13123fb937f4SRafael J. Wysocki 
131359dc3325SRafael J. Wysocki 	down_read(&pci_acpi_companion_lookup_sem);
131459dc3325SRafael J. Wysocki 
131559dc3325SRafael J. Wysocki 	adev = pci_acpi_find_companion_hook ?
131659dc3325SRafael J. Wysocki 		pci_acpi_find_companion_hook(pci_dev) : NULL;
131759dc3325SRafael J. Wysocki 
131859dc3325SRafael J. Wysocki 	up_read(&pci_acpi_companion_lookup_sem);
131959dc3325SRafael J. Wysocki 
132059dc3325SRafael J. Wysocki 	if (adev)
132159dc3325SRafael J. Wysocki 		return adev;
132259dc3325SRafael J. Wysocki 
13236788a51fSYijing Wang 	check_children = pci_is_bridge(pci_dev);
132484df749fSDavid Shaohua Li 	/* Please ref to ACPI spec for the syntax of _ADR */
132584df749fSDavid Shaohua Li 	addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
1326aa0b1574SRafael J. Wysocki 	adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
13275ce79d20SRafael J. Wysocki 				      check_children);
1328aa0b1574SRafael J. Wysocki 
1329aa0b1574SRafael J. Wysocki 	/*
1330aa0b1574SRafael J. Wysocki 	 * There may be ACPI device objects in the ACPI namespace that are
1331aa0b1574SRafael J. Wysocki 	 * children of the device object representing the host bridge, but don't
1332aa0b1574SRafael J. Wysocki 	 * represent PCI devices.  Both _HID and _ADR may be present for them,
1333aa0b1574SRafael J. Wysocki 	 * even though that is against the specification (for example, see
1334aa0b1574SRafael J. Wysocki 	 * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which
1335aa0b1574SRafael J. Wysocki 	 * appears to indicate that they should not be taken into consideration
1336aa0b1574SRafael J. Wysocki 	 * as potential companions of PCI devices on the root bus.
1337aa0b1574SRafael J. Wysocki 	 *
1338aa0b1574SRafael J. Wysocki 	 * To catch this special case, disregard the returned device object if
1339aa0b1574SRafael J. Wysocki 	 * it has a valid _HID, addr is 0 and the PCI device at hand is on the
1340aa0b1574SRafael J. Wysocki 	 * root bus.
1341aa0b1574SRafael J. Wysocki 	 */
1342aa0b1574SRafael J. Wysocki 	if (adev && adev->pnp.type.platform_id && !addr &&
1343aa0b1574SRafael J. Wysocki 	    pci_is_root_bus(pci_dev->bus))
1344aa0b1574SRafael J. Wysocki 		return NULL;
1345aa0b1574SRafael J. Wysocki 
1346aa0b1574SRafael J. Wysocki 	return adev;
134784df749fSDavid Shaohua Li }
134884df749fSDavid Shaohua Li 
1349e33caa82SAaron Lu /**
1350e33caa82SAaron Lu  * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
1351e33caa82SAaron Lu  * @pdev: the PCI device whose delay is to be updated
1352113e0d11SSrinidhi Kasagar  * @handle: ACPI handle of this device
1353e33caa82SAaron Lu  *
13543789af9aSKrzysztof Wilczyński  * Update the d3hot_delay and d3cold_delay of a PCI device from the ACPI _DSM
1355e33caa82SAaron Lu  * control method of either the device itself or the PCI host bridge.
1356e33caa82SAaron Lu  *
1357e33caa82SAaron Lu  * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
1358e33caa82SAaron Lu  * host bridge.  If it returns one, the OS may assume that all devices in
1359e33caa82SAaron Lu  * the hierarchy have already completed power-on reset delays.
1360e33caa82SAaron Lu  *
1361e33caa82SAaron Lu  * Function 9, "Device Readiness Durations," applies only to the object
1362e33caa82SAaron Lu  * where it is located.  It returns delay durations required after various
1363e33caa82SAaron Lu  * events if the device requires less time than the spec requires.  Delays
1364e33caa82SAaron Lu  * from this function take precedence over the Reset Delay function.
1365e33caa82SAaron Lu  *
1366e33caa82SAaron Lu  * These _DSM functions are defined by the draft ECN of January 28, 2014,
1367e33caa82SAaron Lu  * titled "ACPI additions for FW latency optimizations."
1368e33caa82SAaron Lu  */
pci_acpi_optimize_delay(struct pci_dev * pdev,acpi_handle handle)1369e33caa82SAaron Lu static void pci_acpi_optimize_delay(struct pci_dev *pdev,
1370e33caa82SAaron Lu 				    acpi_handle handle)
1371e33caa82SAaron Lu {
1372e33caa82SAaron Lu 	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
1373e33caa82SAaron Lu 	int value;
1374e33caa82SAaron Lu 	union acpi_object *obj, *elements;
1375e33caa82SAaron Lu 
1376e33caa82SAaron Lu 	if (bridge->ignore_reset_delay)
1377e33caa82SAaron Lu 		pdev->d3cold_delay = 0;
1378e33caa82SAaron Lu 
137994116f81SAndy Shevchenko 	obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3,
13803910ebacSKrzysztof Wilczyński 				DSM_PCI_DEVICE_READINESS_DURATIONS, NULL);
1381e33caa82SAaron Lu 	if (!obj)
1382e33caa82SAaron Lu 		return;
1383e33caa82SAaron Lu 
1384e33caa82SAaron Lu 	if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
1385e33caa82SAaron Lu 		elements = obj->package.elements;
1386e33caa82SAaron Lu 		if (elements[0].type == ACPI_TYPE_INTEGER) {
1387e33caa82SAaron Lu 			value = (int)elements[0].integer.value / 1000;
1388e33caa82SAaron Lu 			if (value < PCI_PM_D3COLD_WAIT)
1389e33caa82SAaron Lu 				pdev->d3cold_delay = value;
1390e33caa82SAaron Lu 		}
1391e33caa82SAaron Lu 		if (elements[3].type == ACPI_TYPE_INTEGER) {
1392e33caa82SAaron Lu 			value = (int)elements[3].integer.value / 1000;
13933789af9aSKrzysztof Wilczyński 			if (value < PCI_PM_D3HOT_WAIT)
13943789af9aSKrzysztof Wilczyński 				pdev->d3hot_delay = value;
1395e33caa82SAaron Lu 		}
1396e33caa82SAaron Lu 	}
1397e33caa82SAaron Lu 	ACPI_FREE(obj);
1398e33caa82SAaron Lu }
1399e33caa82SAaron Lu 
pci_acpi_set_external_facing(struct pci_dev * dev)140099b50be9SRajat Jain static void pci_acpi_set_external_facing(struct pci_dev *dev)
1401617654aaSMika Westerberg {
1402617654aaSMika Westerberg 	u8 val;
1403617654aaSMika Westerberg 
1404617654aaSMika Westerberg 	if (pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
1405617654aaSMika Westerberg 		return;
1406617654aaSMika Westerberg 	if (device_property_read_u8(&dev->dev, "ExternalFacingPort", &val))
1407617654aaSMika Westerberg 		return;
1408617654aaSMika Westerberg 
1409617654aaSMika Westerberg 	/*
1410617654aaSMika Westerberg 	 * These root ports expose PCIe (including DMA) outside of the
141199b50be9SRajat Jain 	 * system.  Everything downstream from them is external.
1412617654aaSMika Westerberg 	 */
1413617654aaSMika Westerberg 	if (val)
141499b50be9SRajat Jain 		dev->external_facing = 1;
1415617654aaSMika Westerberg }
1416617654aaSMika Westerberg 
pci_acpi_setup(struct device * dev,struct acpi_device * adev)141747954481SRafael J. Wysocki void pci_acpi_setup(struct device *dev, struct acpi_device *adev)
1418d2e5f0c1SRafael J. Wysocki {
1419d2e5f0c1SRafael J. Wysocki 	struct pci_dev *pci_dev = to_pci_dev(dev);
1420f084280cSRafael J. Wysocki 
1421e33caa82SAaron Lu 	pci_acpi_optimize_delay(pci_dev, adev->handle);
142299b50be9SRajat Jain 	pci_acpi_set_external_facing(pci_dev);
1423ac1c8e35SKuppuswamy Sathyanarayanan 	pci_acpi_add_edr_notifier(pci_dev);
1424e33caa82SAaron Lu 
1425f084280cSRafael J. Wysocki 	pci_acpi_add_pm_notifier(adev, pci_dev);
1426f084280cSRafael J. Wysocki 	if (!adev->wakeup.flags.valid)
1427d2e5f0c1SRafael J. Wysocki 		return;
1428d2e5f0c1SRafael J. Wysocki 
1429d2e5f0c1SRafael J. Wysocki 	device_set_wakeup_capable(dev, true);
14306299cf9eSMika Westerberg 	/*
14316299cf9eSMika Westerberg 	 * For bridges that can do D3 we enable wake automatically (as
14326299cf9eSMika Westerberg 	 * we do for the power management itself in that case). The
14336299cf9eSMika Westerberg 	 * reason is that the bridge may have additional methods such as
14346299cf9eSMika Westerberg 	 * _DSW that need to be called.
14356299cf9eSMika Westerberg 	 */
14366299cf9eSMika Westerberg 	if (pci_dev->bridge_d3)
14376299cf9eSMika Westerberg 		device_wakeup_enable(dev);
14386299cf9eSMika Westerberg 
14398370c2dcSRafael J. Wysocki 	acpi_pci_wakeup(pci_dev, false);
144053b22f90SMika Westerberg 	acpi_device_power_add_dependent(adev, dev);
144162d52871SRafael J. Wysocki 
144262d52871SRafael J. Wysocki 	if (pci_is_bridge(pci_dev))
144362d52871SRafael J. Wysocki 		acpi_dev_power_up_children_with_adr(adev);
1444d2e5f0c1SRafael J. Wysocki }
1445d2e5f0c1SRafael J. Wysocki 
pci_acpi_cleanup(struct device * dev,struct acpi_device * adev)144647954481SRafael J. Wysocki void pci_acpi_cleanup(struct device *dev, struct acpi_device *adev)
1447d2e5f0c1SRafael J. Wysocki {
14486299cf9eSMika Westerberg 	struct pci_dev *pci_dev = to_pci_dev(dev);
1449d2e5f0c1SRafael J. Wysocki 
1450ac1c8e35SKuppuswamy Sathyanarayanan 	pci_acpi_remove_edr_notifier(pci_dev);
1451f084280cSRafael J. Wysocki 	pci_acpi_remove_pm_notifier(adev);
14526299cf9eSMika Westerberg 	if (adev->wakeup.flags.valid) {
145353b22f90SMika Westerberg 		acpi_device_power_remove_dependent(adev, dev);
14546299cf9eSMika Westerberg 		if (pci_dev->bridge_d3)
14556299cf9eSMika Westerberg 			device_wakeup_disable(dev);
14566299cf9eSMika Westerberg 
1457d2e5f0c1SRafael J. Wysocki 		device_set_wakeup_capable(dev, false);
1458d2e5f0c1SRafael J. Wysocki 	}
14596299cf9eSMika Westerberg }
1460d2e5f0c1SRafael J. Wysocki 
1461471036b2SSuravee Suthikulpanit static struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev);
1462471036b2SSuravee Suthikulpanit 
1463471036b2SSuravee Suthikulpanit /**
1464471036b2SSuravee Suthikulpanit  * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode
1465471036b2SSuravee Suthikulpanit  * @fn:       Callback matching a device to a fwnode that identifies a PCI
1466471036b2SSuravee Suthikulpanit  *            MSI domain.
1467471036b2SSuravee Suthikulpanit  *
1468471036b2SSuravee Suthikulpanit  * This should be called by irqchip driver, which is the parent of
1469471036b2SSuravee Suthikulpanit  * the MSI domain to provide callback interface to query fwnode.
1470471036b2SSuravee Suthikulpanit  */
1471471036b2SSuravee Suthikulpanit void
pci_msi_register_fwnode_provider(struct fwnode_handle * (* fn)(struct device *))1472471036b2SSuravee Suthikulpanit pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *))
1473471036b2SSuravee Suthikulpanit {
1474471036b2SSuravee Suthikulpanit 	pci_msi_get_fwnode_cb = fn;
1475471036b2SSuravee Suthikulpanit }
1476471036b2SSuravee Suthikulpanit 
1477471036b2SSuravee Suthikulpanit /**
1478471036b2SSuravee Suthikulpanit  * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge
1479471036b2SSuravee Suthikulpanit  * @bus:      The PCI host bridge bus.
1480471036b2SSuravee Suthikulpanit  *
1481471036b2SSuravee Suthikulpanit  * This function uses the callback function registered by
1482471036b2SSuravee Suthikulpanit  * pci_msi_register_fwnode_provider() to retrieve the irq_domain with
1483471036b2SSuravee Suthikulpanit  * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus.
1484471036b2SSuravee Suthikulpanit  * This returns NULL on error or when the domain is not found.
1485471036b2SSuravee Suthikulpanit  */
pci_host_bridge_acpi_msi_domain(struct pci_bus * bus)1486471036b2SSuravee Suthikulpanit struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
1487471036b2SSuravee Suthikulpanit {
1488471036b2SSuravee Suthikulpanit 	struct fwnode_handle *fwnode;
1489471036b2SSuravee Suthikulpanit 
1490471036b2SSuravee Suthikulpanit 	if (!pci_msi_get_fwnode_cb)
1491471036b2SSuravee Suthikulpanit 		return NULL;
1492471036b2SSuravee Suthikulpanit 
1493471036b2SSuravee Suthikulpanit 	fwnode = pci_msi_get_fwnode_cb(&bus->dev);
1494471036b2SSuravee Suthikulpanit 	if (!fwnode)
1495471036b2SSuravee Suthikulpanit 		return NULL;
1496471036b2SSuravee Suthikulpanit 
1497471036b2SSuravee Suthikulpanit 	return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
1498471036b2SSuravee Suthikulpanit }
1499471036b2SSuravee Suthikulpanit 
acpi_pci_init(void)15009c273b95SMuthu Kumar static int __init acpi_pci_init(void)
150184df749fSDavid Shaohua Li {
1502993958feSBob Moore 	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) {
1503e7d45152SYijing Wang 		pr_info("ACPI FADT declares the system doesn't support MSI, so disable it\n");
1504f8993affSShaohua Li 		pci_no_msi();
1505f8993affSShaohua Li 	}
15065fde244dSShaohua Li 
1507993958feSBob Moore 	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
1508e7d45152SYijing Wang 		pr_info("ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
15095fde244dSShaohua Li 		pcie_no_aspm();
15105fde244dSShaohua Li 	}
15115fde244dSShaohua Li 
151247954481SRafael J. Wysocki 	if (acpi_pci_disabled)
151384df749fSDavid Shaohua Li 		return 0;
15145c0b04e3SJiang Liu 
15155c0b04e3SJiang Liu 	acpi_pci_slot_init();
15163b63aaa7SJiang Liu 	acpiphp_init();
15175c0b04e3SJiang Liu 
151884df749fSDavid Shaohua Li 	return 0;
151984df749fSDavid Shaohua Li }
15209c273b95SMuthu Kumar arch_initcall(acpi_pci_init);
1521