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, ®32);
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, ®32);
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, ®32);
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, ®32);
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